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 2594259563Spfg /* We can't widen a bswap. */ 2595259563Spfg if (unoptab == bswap_optab) 2596259563Spfg goto try_libcall; 2597259563Spfg 2598169689Skan if (CLASS_HAS_WIDER_MODES_P (class)) 2599169689Skan for (wider_mode = GET_MODE_WIDER_MODE (mode); 2600169689Skan wider_mode != VOIDmode; 260118334Speter wider_mode = GET_MODE_WIDER_MODE (wider_mode)) 260218334Speter { 260318334Speter if (unoptab->handlers[(int) wider_mode].insn_code != CODE_FOR_nothing) 260418334Speter { 260518334Speter rtx xop0 = op0; 260618334Speter 260718334Speter /* For certain operations, we need not actually extend 260818334Speter the narrow operand, as long as we will truncate the 260918334Speter results to the same narrowness. */ 261018334Speter 261118334Speter xop0 = widen_operand (xop0, wider_mode, mode, unsignedp, 261218334Speter (unoptab == neg_optab 261318334Speter || unoptab == one_cmpl_optab) 261418334Speter && class == MODE_INT); 2615132718Skan 261618334Speter temp = expand_unop (wider_mode, unoptab, xop0, NULL_RTX, 261718334Speter unsignedp); 261818334Speter 261918334Speter if (temp) 262018334Speter { 2621169689Skan if (class != MODE_INT 2622169689Skan || !TRULY_NOOP_TRUNCATION (GET_MODE_BITSIZE (mode), 2623169689Skan GET_MODE_BITSIZE (wider_mode))) 262418334Speter { 262518334Speter if (target == 0) 262618334Speter target = gen_reg_rtx (mode); 262718334Speter convert_move (target, temp, 0); 262818334Speter return target; 262918334Speter } 263018334Speter else 263118334Speter return gen_lowpart (mode, temp); 263218334Speter } 263318334Speter else 263418334Speter delete_insns_since (last); 263518334Speter } 263618334Speter } 263718334Speter 263818334Speter /* These can be done a word at a time. */ 263918334Speter if (unoptab == one_cmpl_optab 264018334Speter && class == MODE_INT 264118334Speter && GET_MODE_SIZE (mode) > UNITS_PER_WORD 264218334Speter && unoptab->handlers[(int) word_mode].insn_code != CODE_FOR_nothing) 264318334Speter { 264418334Speter int i; 264518334Speter rtx insns; 264618334Speter 264718334Speter if (target == 0 || target == op0) 264818334Speter target = gen_reg_rtx (mode); 264918334Speter 265018334Speter start_sequence (); 265118334Speter 265218334Speter /* Do the actual arithmetic. */ 265318334Speter for (i = 0; i < GET_MODE_BITSIZE (mode) / BITS_PER_WORD; i++) 265418334Speter { 265518334Speter rtx target_piece = operand_subword (target, i, 1, mode); 265618334Speter rtx x = expand_unop (word_mode, unoptab, 265718334Speter operand_subword_force (op0, i, mode), 265818334Speter target_piece, unsignedp); 265990075Sobrien 266018334Speter if (target_piece != x) 266118334Speter emit_move_insn (target_piece, x); 266218334Speter } 266318334Speter 266418334Speter insns = get_insns (); 266518334Speter end_sequence (); 266618334Speter 266718334Speter emit_no_conflict_block (insns, target, op0, NULL_RTX, 266850397Sobrien gen_rtx_fmt_e (unoptab->code, mode, 266950397Sobrien copy_rtx (op0))); 267018334Speter return target; 267118334Speter } 267218334Speter 2673169689Skan if (unoptab->code == NEG) 267418334Speter { 2675169689Skan /* Try negating floating point values by flipping the sign bit. */ 2676169689Skan if (SCALAR_FLOAT_MODE_P (mode)) 2677169689Skan { 2678169689Skan temp = expand_absneg_bit (NEG, mode, op0, target); 2679169689Skan if (temp) 2680169689Skan return temp; 2681169689Skan } 268218334Speter 2683169689Skan /* If there is no negation pattern, and we have no negative zero, 2684169689Skan try subtracting from zero. */ 2685169689Skan if (!HONOR_SIGNED_ZEROS (mode)) 2686132718Skan { 2687169689Skan temp = expand_binop (mode, (unoptab == negv_optab 2688169689Skan ? subv_optab : sub_optab), 2689169689Skan CONST0_RTX (mode), op0, target, 2690169689Skan unsignedp, OPTAB_DIRECT); 2691169689Skan if (temp) 2692169689Skan return temp; 2693169689Skan } 2694132718Skan } 2695132718Skan 2696132718Skan /* Try calculating parity (x) as popcount (x) % 2. */ 2697132718Skan if (unoptab == parity_optab) 2698132718Skan { 2699132718Skan temp = expand_parity (mode, op0, target); 2700132718Skan if (temp) 2701132718Skan return temp; 2702132718Skan } 2703132718Skan 2704132718Skan try_libcall: 270518334Speter /* Now try a library call in this mode. */ 270618334Speter if (unoptab->handlers[(int) mode].libfunc) 270718334Speter { 270818334Speter rtx insns; 270918334Speter rtx value; 2710132718Skan enum machine_mode outmode = mode; 271118334Speter 2712132718Skan /* All of these functions return small values. Thus we choose to 2713132718Skan have them return something that isn't a double-word. */ 2714132718Skan if (unoptab == ffs_optab || unoptab == clz_optab || unoptab == ctz_optab 2715132718Skan || unoptab == popcount_optab || unoptab == parity_optab) 2716132718Skan outmode 2717132718Skan = GET_MODE (hard_libcall_value (TYPE_MODE (integer_type_node))); 2718132718Skan 271918334Speter start_sequence (); 272018334Speter 272118334Speter /* Pass 1 for NO_QUEUE so we don't lose any increments 272218334Speter if the libcall is cse'd or moved. */ 272318334Speter value = emit_library_call_value (unoptab->handlers[(int) mode].libfunc, 2724132718Skan NULL_RTX, LCT_CONST, outmode, 2725132718Skan 1, op0, mode); 272618334Speter insns = get_insns (); 272718334Speter end_sequence (); 272818334Speter 2729132718Skan target = gen_reg_rtx (outmode); 273018334Speter emit_libcall_block (insns, target, value, 2731169689Skan gen_rtx_fmt_e (unoptab->code, outmode, op0)); 273218334Speter 273318334Speter return target; 273418334Speter } 273518334Speter 273618334Speter /* It can't be done in this mode. Can we do it in a wider mode? */ 273718334Speter 2738169689Skan if (CLASS_HAS_WIDER_MODES_P (class)) 273918334Speter { 2740169689Skan for (wider_mode = GET_MODE_WIDER_MODE (mode); 2741169689Skan wider_mode != VOIDmode; 274218334Speter wider_mode = GET_MODE_WIDER_MODE (wider_mode)) 274318334Speter { 274418334Speter if ((unoptab->handlers[(int) wider_mode].insn_code 274518334Speter != CODE_FOR_nothing) 274618334Speter || unoptab->handlers[(int) wider_mode].libfunc) 274718334Speter { 274818334Speter rtx xop0 = op0; 274918334Speter 275018334Speter /* For certain operations, we need not actually extend 275118334Speter the narrow operand, as long as we will truncate the 275218334Speter results to the same narrowness. */ 275318334Speter 275418334Speter xop0 = widen_operand (xop0, wider_mode, mode, unsignedp, 275518334Speter (unoptab == neg_optab 275618334Speter || unoptab == one_cmpl_optab) 275718334Speter && class == MODE_INT); 2758132718Skan 275918334Speter temp = expand_unop (wider_mode, unoptab, xop0, NULL_RTX, 276018334Speter unsignedp); 276118334Speter 2762132718Skan /* If we are generating clz using wider mode, adjust the 2763132718Skan result. */ 2764132718Skan if (unoptab == clz_optab && temp != 0) 2765132718Skan temp = expand_binop (wider_mode, sub_optab, temp, 2766132718Skan GEN_INT (GET_MODE_BITSIZE (wider_mode) 2767132718Skan - GET_MODE_BITSIZE (mode)), 2768132718Skan target, true, OPTAB_DIRECT); 2769132718Skan 277018334Speter if (temp) 277118334Speter { 277218334Speter if (class != MODE_INT) 277318334Speter { 277418334Speter if (target == 0) 277518334Speter target = gen_reg_rtx (mode); 277618334Speter convert_move (target, temp, 0); 277718334Speter return target; 277818334Speter } 277918334Speter else 278018334Speter return gen_lowpart (mode, temp); 278118334Speter } 278218334Speter else 278318334Speter delete_insns_since (last); 278418334Speter } 278518334Speter } 278618334Speter } 278718334Speter 2788169689Skan /* One final attempt at implementing negation via subtraction, 2789169689Skan this time allowing widening of the operand. */ 2790169689Skan if (unoptab->code == NEG && !HONOR_SIGNED_ZEROS (mode)) 2791132718Skan { 279218334Speter rtx temp; 279390075Sobrien temp = expand_binop (mode, 279490075Sobrien unoptab == negv_optab ? subv_optab : sub_optab, 279590075Sobrien CONST0_RTX (mode), op0, 279690075Sobrien target, unsignedp, OPTAB_LIB_WIDEN); 279718334Speter if (temp) 2798169689Skan return temp; 279918334Speter } 2800132718Skan 280118334Speter return 0; 280218334Speter} 280318334Speter 280418334Speter/* Emit code to compute the absolute value of OP0, with result to 280518334Speter TARGET if convenient. (TARGET may be 0.) The return value says 280618334Speter where the result actually is to be found. 280718334Speter 280818334Speter MODE is the mode of the operand; the mode of the result is 280918334Speter different but can be deduced from MODE. 281018334Speter 281152284Sobrien */ 281218334Speter 281318334Speterrtx 2814132718Skanexpand_abs_nojump (enum machine_mode mode, rtx op0, rtx target, 2815132718Skan int result_unsignedp) 281618334Speter{ 2817132718Skan rtx temp; 281818334Speter 281990075Sobrien if (! flag_trapv) 282090075Sobrien result_unsignedp = 1; 282190075Sobrien 282218334Speter /* First try to do it with a special abs instruction. */ 282390075Sobrien temp = expand_unop (mode, result_unsignedp ? abs_optab : absv_optab, 282490075Sobrien op0, target, 0); 282518334Speter if (temp != 0) 282618334Speter return temp; 282718334Speter 2828132718Skan /* For floating point modes, try clearing the sign bit. */ 2829169689Skan if (SCALAR_FLOAT_MODE_P (mode)) 2830132718Skan { 2831169689Skan temp = expand_absneg_bit (ABS, mode, op0, target); 2832169689Skan if (temp) 2833169689Skan return temp; 2834132718Skan } 2835132718Skan 283690075Sobrien /* If we have a MAX insn, we can do this as MAX (x, -x). */ 2837169689Skan if (smax_optab->handlers[(int) mode].insn_code != CODE_FOR_nothing 2838169689Skan && !HONOR_SIGNED_ZEROS (mode)) 283990075Sobrien { 284090075Sobrien rtx last = get_last_insn (); 284190075Sobrien 284290075Sobrien temp = expand_unop (mode, neg_optab, op0, NULL_RTX, 0); 284390075Sobrien if (temp != 0) 284490075Sobrien temp = expand_binop (mode, smax_optab, op0, temp, target, 0, 284590075Sobrien OPTAB_WIDEN); 284690075Sobrien 284790075Sobrien if (temp != 0) 284890075Sobrien return temp; 284990075Sobrien 285090075Sobrien delete_insns_since (last); 285190075Sobrien } 285290075Sobrien 285318334Speter /* If this machine has expensive jumps, we can do integer absolute 285418334Speter value of X as (((signed) x >> (W-1)) ^ x) - ((signed) x >> (W-1)), 285518334Speter where W is the width of MODE. */ 285618334Speter 285718334Speter if (GET_MODE_CLASS (mode) == MODE_INT && BRANCH_COST >= 2) 285818334Speter { 285918334Speter rtx extended = expand_shift (RSHIFT_EXPR, mode, op0, 286018334Speter size_int (GET_MODE_BITSIZE (mode) - 1), 286118334Speter NULL_RTX, 0); 286218334Speter 286318334Speter temp = expand_binop (mode, xor_optab, extended, op0, target, 0, 286418334Speter OPTAB_LIB_WIDEN); 286518334Speter if (temp != 0) 286690075Sobrien temp = expand_binop (mode, result_unsignedp ? sub_optab : subv_optab, 286790075Sobrien temp, extended, target, 0, OPTAB_LIB_WIDEN); 286818334Speter 286918334Speter if (temp != 0) 287018334Speter return temp; 287118334Speter } 287218334Speter 2873132718Skan return NULL_RTX; 2874132718Skan} 2875132718Skan 2876132718Skanrtx 2877132718Skanexpand_abs (enum machine_mode mode, rtx op0, rtx target, 2878132718Skan int result_unsignedp, int safe) 2879132718Skan{ 2880132718Skan rtx temp, op1; 2881132718Skan 2882132718Skan if (! flag_trapv) 2883132718Skan result_unsignedp = 1; 2884132718Skan 2885132718Skan temp = expand_abs_nojump (mode, op0, target, result_unsignedp); 2886132718Skan if (temp != 0) 2887132718Skan return temp; 2888132718Skan 288918334Speter /* If that does not win, use conditional jump and negate. */ 289050397Sobrien 289150397Sobrien /* It is safe to use the target if it is the same 289250397Sobrien as the source if this is also a pseudo register */ 2893169689Skan if (op0 == target && REG_P (op0) 289450397Sobrien && REGNO (op0) >= FIRST_PSEUDO_REGISTER) 289550397Sobrien safe = 1; 289650397Sobrien 289718334Speter op1 = gen_label_rtx (); 289818334Speter if (target == 0 || ! safe 289918334Speter || GET_MODE (target) != mode 2900169689Skan || (MEM_P (target) && MEM_VOLATILE_P (target)) 2901169689Skan || (REG_P (target) 290218334Speter && REGNO (target) < FIRST_PSEUDO_REGISTER)) 290318334Speter target = gen_reg_rtx (mode); 290418334Speter 290518334Speter emit_move_insn (target, op0); 290618334Speter NO_DEFER_POP; 290718334Speter 2908169689Skan do_compare_rtx_and_jump (target, CONST0_RTX (mode), GE, 0, mode, 2909169689Skan NULL_RTX, NULL_RTX, op1); 291018334Speter 291190075Sobrien op0 = expand_unop (mode, result_unsignedp ? neg_optab : negv_optab, 291290075Sobrien target, target, 0); 291318334Speter if (op0 != target) 291418334Speter emit_move_insn (target, op0); 291518334Speter emit_label (op1); 291618334Speter OK_DEFER_POP; 291718334Speter return target; 291818334Speter} 291918334Speter 2920169689Skan/* A subroutine of expand_copysign, perform the copysign operation using the 2921169689Skan abs and neg primitives advertised to exist on the target. The assumption 2922169689Skan is that we have a split register file, and leaving op0 in fp registers, 2923169689Skan and not playing with subregs so much, will help the register allocator. */ 292418334Speter 2925169689Skanstatic rtx 2926169689Skanexpand_copysign_absneg (enum machine_mode mode, rtx op0, rtx op1, rtx target, 2927169689Skan int bitpos, bool op0_is_abs) 292818334Speter{ 2929169689Skan enum machine_mode imode; 2930169689Skan HOST_WIDE_INT hi, lo; 2931169689Skan int word; 2932169689Skan rtx label; 293318334Speter 2934169689Skan if (target == op1) 2935169689Skan target = NULL_RTX; 293618334Speter 2937169689Skan if (!op0_is_abs) 2938169689Skan { 2939169689Skan op0 = expand_unop (mode, abs_optab, op0, target, 0); 2940169689Skan if (op0 == NULL) 2941169689Skan return NULL_RTX; 2942169689Skan target = op0; 2943169689Skan } 2944169689Skan else 2945169689Skan { 2946169689Skan if (target == NULL_RTX) 2947169689Skan target = copy_to_reg (op0); 2948169689Skan else 2949169689Skan emit_move_insn (target, op0); 2950169689Skan } 295118334Speter 2952169689Skan if (GET_MODE_SIZE (mode) <= UNITS_PER_WORD) 2953169689Skan { 2954169689Skan imode = int_mode_for_mode (mode); 2955169689Skan if (imode == BLKmode) 2956169689Skan return NULL_RTX; 2957169689Skan op1 = gen_lowpart (imode, op1); 2958169689Skan } 2959169689Skan else 2960169689Skan { 2961169689Skan imode = word_mode; 2962169689Skan if (FLOAT_WORDS_BIG_ENDIAN) 2963169689Skan word = (GET_MODE_BITSIZE (mode) - bitpos) / BITS_PER_WORD; 2964169689Skan else 2965169689Skan word = bitpos / BITS_PER_WORD; 2966169689Skan bitpos = bitpos % BITS_PER_WORD; 2967169689Skan op1 = operand_subword_force (op1, word, mode); 2968169689Skan } 296918334Speter 2970169689Skan if (bitpos < HOST_BITS_PER_WIDE_INT) 297118334Speter { 2972169689Skan hi = 0; 2973169689Skan lo = (HOST_WIDE_INT) 1 << bitpos; 297418334Speter } 2975169689Skan else 2976169689Skan { 2977169689Skan hi = (HOST_WIDE_INT) 1 << (bitpos - HOST_BITS_PER_WIDE_INT); 2978169689Skan lo = 0; 2979169689Skan } 298018334Speter 2981169689Skan op1 = expand_binop (imode, and_optab, op1, 2982169689Skan immed_double_const (lo, hi, imode), 2983169689Skan NULL_RTX, 1, OPTAB_LIB_WIDEN); 298418334Speter 2985169689Skan label = gen_label_rtx (); 2986169689Skan emit_cmp_and_jump_insns (op1, const0_rtx, EQ, NULL_RTX, imode, 1, label); 298718334Speter 2988169689Skan if (GET_CODE (op0) == CONST_DOUBLE) 2989169689Skan op0 = simplify_unary_operation (NEG, mode, op0, mode); 2990169689Skan else 2991169689Skan op0 = expand_unop (mode, neg_optab, op0, target, 0); 2992169689Skan if (op0 != target) 2993169689Skan emit_move_insn (target, op0); 299490075Sobrien 2995169689Skan emit_label (label); 299618334Speter 2997169689Skan return target; 2998169689Skan} 299918334Speter 300018334Speter 3001169689Skan/* A subroutine of expand_copysign, perform the entire copysign operation 3002169689Skan with integer bitmasks. BITPOS is the position of the sign bit; OP0_IS_ABS 3003169689Skan is true if op0 is known to have its sign bit clear. */ 300418334Speter 3005169689Skanstatic rtx 3006169689Skanexpand_copysign_bit (enum machine_mode mode, rtx op0, rtx op1, rtx target, 3007169689Skan int bitpos, bool op0_is_abs) 3008169689Skan{ 3009169689Skan enum machine_mode imode; 3010169689Skan HOST_WIDE_INT hi, lo; 3011169689Skan int word, nwords, i; 3012169689Skan rtx temp, insns; 301318334Speter 3014169689Skan if (GET_MODE_SIZE (mode) <= UNITS_PER_WORD) 3015169689Skan { 3016169689Skan imode = int_mode_for_mode (mode); 3017169689Skan if (imode == BLKmode) 3018169689Skan return NULL_RTX; 3019169689Skan word = 0; 3020169689Skan nwords = 1; 3021169689Skan } 3022169689Skan else 3023169689Skan { 3024169689Skan imode = word_mode; 302518334Speter 3026169689Skan if (FLOAT_WORDS_BIG_ENDIAN) 3027169689Skan word = (GET_MODE_BITSIZE (mode) - bitpos) / BITS_PER_WORD; 302818334Speter else 3029169689Skan word = bitpos / BITS_PER_WORD; 3030169689Skan bitpos = bitpos % BITS_PER_WORD; 3031169689Skan nwords = (GET_MODE_BITSIZE (mode) + BITS_PER_WORD - 1) / BITS_PER_WORD; 303218334Speter } 303318334Speter 3034169689Skan if (bitpos < HOST_BITS_PER_WIDE_INT) 3035169689Skan { 3036169689Skan hi = 0; 3037169689Skan lo = (HOST_WIDE_INT) 1 << bitpos; 3038169689Skan } 3039169689Skan else 3040169689Skan { 3041169689Skan hi = (HOST_WIDE_INT) 1 << (bitpos - HOST_BITS_PER_WIDE_INT); 3042169689Skan lo = 0; 3043169689Skan } 304418334Speter 3045169689Skan if (target == 0 || target == op0 || target == op1) 3046169689Skan target = gen_reg_rtx (mode); 3047169689Skan 3048169689Skan if (nwords > 1) 304918334Speter { 3050169689Skan start_sequence (); 3051169689Skan 3052169689Skan for (i = 0; i < nwords; ++i) 305318334Speter { 3054169689Skan rtx targ_piece = operand_subword (target, i, 1, mode); 3055169689Skan rtx op0_piece = operand_subword_force (op0, i, mode); 305618334Speter 3057169689Skan if (i == word) 3058169689Skan { 3059169689Skan if (!op0_is_abs) 3060169689Skan op0_piece = expand_binop (imode, and_optab, op0_piece, 3061169689Skan immed_double_const (~lo, ~hi, imode), 3062169689Skan NULL_RTX, 1, OPTAB_LIB_WIDEN); 306318334Speter 3064169689Skan op1 = expand_binop (imode, and_optab, 3065169689Skan operand_subword_force (op1, i, mode), 3066169689Skan immed_double_const (lo, hi, imode), 3067169689Skan NULL_RTX, 1, OPTAB_LIB_WIDEN); 3068169689Skan 3069169689Skan temp = expand_binop (imode, ior_optab, op0_piece, op1, 3070169689Skan targ_piece, 1, OPTAB_LIB_WIDEN); 3071169689Skan if (temp != targ_piece) 3072169689Skan emit_move_insn (targ_piece, temp); 307318334Speter } 307418334Speter else 3075169689Skan emit_move_insn (targ_piece, op0_piece); 307618334Speter } 3077169689Skan 3078169689Skan insns = get_insns (); 3079169689Skan end_sequence (); 3080169689Skan 3081169689Skan emit_no_conflict_block (insns, target, op0, op1, NULL_RTX); 308218334Speter } 3083169689Skan else 308418334Speter { 3085169689Skan op1 = expand_binop (imode, and_optab, gen_lowpart (imode, op1), 3086169689Skan immed_double_const (lo, hi, imode), 3087169689Skan NULL_RTX, 1, OPTAB_LIB_WIDEN); 308818334Speter 3089169689Skan op0 = gen_lowpart (imode, op0); 3090169689Skan if (!op0_is_abs) 3091169689Skan op0 = expand_binop (imode, and_optab, op0, 3092169689Skan immed_double_const (~lo, ~hi, imode), 3093169689Skan NULL_RTX, 1, OPTAB_LIB_WIDEN); 309418334Speter 3095169689Skan temp = expand_binop (imode, ior_optab, op0, op1, 3096169689Skan gen_lowpart (imode, target), 1, OPTAB_LIB_WIDEN); 3097169689Skan target = lowpart_subreg_maybe_copy (mode, temp, imode); 3098169689Skan } 309918334Speter 3100169689Skan return target; 3101169689Skan} 310218334Speter 3103169689Skan/* Expand the C99 copysign operation. OP0 and OP1 must be the same 3104169689Skan scalar floating point mode. Return NULL if we do not know how to 3105169689Skan expand the operation inline. */ 310618334Speter 3107169689Skanrtx 3108169689Skanexpand_copysign (rtx op0, rtx op1, rtx target) 3109169689Skan{ 3110169689Skan enum machine_mode mode = GET_MODE (op0); 3111169689Skan const struct real_format *fmt; 3112169689Skan bool op0_is_abs; 3113169689Skan rtx temp; 311418334Speter 3115169689Skan gcc_assert (SCALAR_FLOAT_MODE_P (mode)); 3116169689Skan gcc_assert (GET_MODE (op1) == mode); 311718334Speter 3118169689Skan /* First try to do it with a special instruction. */ 3119169689Skan temp = expand_binop (mode, copysign_optab, op0, op1, 3120169689Skan target, 0, OPTAB_DIRECT); 3121169689Skan if (temp) 3122169689Skan return temp; 312318334Speter 3124169689Skan fmt = REAL_MODE_FORMAT (mode); 3125169689Skan if (fmt == NULL || !fmt->has_signed_zero) 3126169689Skan return NULL_RTX; 312718334Speter 3128169689Skan op0_is_abs = false; 3129169689Skan if (GET_CODE (op0) == CONST_DOUBLE) 3130169689Skan { 3131169689Skan if (real_isneg (CONST_DOUBLE_REAL_VALUE (op0))) 3132169689Skan op0 = simplify_unary_operation (ABS, mode, op0, mode); 3133169689Skan op0_is_abs = true; 313418334Speter } 313518334Speter 3136169689Skan if (fmt->signbit_ro >= 0 3137169689Skan && (GET_CODE (op0) == CONST_DOUBLE 3138169689Skan || (neg_optab->handlers[mode].insn_code != CODE_FOR_nothing 3139169689Skan && abs_optab->handlers[mode].insn_code != CODE_FOR_nothing))) 314018334Speter { 3141169689Skan temp = expand_copysign_absneg (mode, op0, op1, target, 3142169689Skan fmt->signbit_ro, op0_is_abs); 3143169689Skan if (temp) 3144169689Skan return temp; 314518334Speter } 314618334Speter 3147169689Skan if (fmt->signbit_rw < 0) 3148169689Skan return NULL_RTX; 3149169689Skan return expand_copysign_bit (mode, op0, op1, target, 3150169689Skan fmt->signbit_rw, op0_is_abs); 315118334Speter} 315218334Speter 315318334Speter/* Generate an instruction whose insn-code is INSN_CODE, 315418334Speter with two operands: an output TARGET and an input OP0. 315518334Speter TARGET *must* be nonzero, and the output is always stored there. 315618334Speter CODE is an rtx code such that (CODE OP0) is an rtx that describes 315718334Speter the value that is stored into TARGET. */ 315818334Speter 315918334Spetervoid 3160132718Skanemit_unop_insn (int icode, rtx target, rtx op0, enum rtx_code code) 316118334Speter{ 316290075Sobrien rtx temp; 316390075Sobrien enum machine_mode mode0 = insn_data[icode].operand[1].mode; 316418334Speter rtx pat; 316518334Speter 3166169689Skan temp = target; 316718334Speter 316818334Speter /* Now, if insn does not accept our operands, put them into pseudos. */ 316918334Speter 3170169689Skan if (!insn_data[icode].operand[1].predicate (op0, mode0)) 317118334Speter op0 = copy_to_mode_reg (mode0, op0); 317218334Speter 3173169689Skan if (!insn_data[icode].operand[0].predicate (temp, GET_MODE (temp))) 317418334Speter temp = gen_reg_rtx (GET_MODE (temp)); 317518334Speter 317618334Speter pat = GEN_FCN (icode) (temp, op0); 317718334Speter 3178117395Skan if (INSN_P (pat) && NEXT_INSN (pat) != NULL_RTX && code != UNKNOWN) 317918334Speter add_equal_note (pat, temp, code, op0, NULL_RTX); 3180132718Skan 318118334Speter emit_insn (pat); 318218334Speter 318318334Speter if (temp != target) 318418334Speter emit_move_insn (target, temp); 318518334Speter} 318618334Speter 3187169689Skanstruct no_conflict_data 3188169689Skan{ 3189169689Skan rtx target, first, insn; 3190169689Skan bool must_stay; 3191169689Skan}; 3192169689Skan 3193169689Skan/* Called via note_stores by emit_no_conflict_block and emit_libcall_block. 3194169689Skan Set P->must_stay if the currently examined clobber / store has to stay 3195169689Skan in the list of insns that constitute the actual no_conflict block / 3196169689Skan libcall block. */ 3197169689Skanstatic void 3198169689Skanno_conflict_move_test (rtx dest, rtx set, void *p0) 3199169689Skan{ 3200169689Skan struct no_conflict_data *p= p0; 3201169689Skan 3202169689Skan /* If this inns directly contributes to setting the target, it must stay. */ 3203169689Skan if (reg_overlap_mentioned_p (p->target, dest)) 3204169689Skan p->must_stay = true; 3205169689Skan /* If we haven't committed to keeping any other insns in the list yet, 3206169689Skan there is nothing more to check. */ 3207169689Skan else if (p->insn == p->first) 3208169689Skan return; 3209169689Skan /* If this insn sets / clobbers a register that feeds one of the insns 3210169689Skan already in the list, this insn has to stay too. */ 3211169689Skan else if (reg_overlap_mentioned_p (dest, PATTERN (p->first)) 3212169689Skan || (CALL_P (p->first) && (find_reg_fusage (p->first, USE, dest))) 3213169689Skan || reg_used_between_p (dest, p->first, p->insn) 3214169689Skan /* Likewise if this insn depends on a register set by a previous 3215169689Skan insn in the list, or if it sets a result (presumably a hard 3216169689Skan register) that is set or clobbered by a previous insn. 3217169689Skan N.B. the modified_*_p (SET_DEST...) tests applied to a MEM 3218169689Skan SET_DEST perform the former check on the address, and the latter 3219169689Skan check on the MEM. */ 3220169689Skan || (GET_CODE (set) == SET 3221169689Skan && (modified_in_p (SET_SRC (set), p->first) 3222169689Skan || modified_in_p (SET_DEST (set), p->first) 3223169689Skan || modified_between_p (SET_SRC (set), p->first, p->insn) 3224169689Skan || modified_between_p (SET_DEST (set), p->first, p->insn)))) 3225169689Skan p->must_stay = true; 3226169689Skan} 3227169689Skan 3228169689Skan/* Encapsulate the block starting at FIRST and ending with LAST, which is 3229169689Skan logically equivalent to EQUIV, so it gets manipulated as a unit if it 3230169689Skan is possible to do so. */ 3231169689Skan 3232169689Skanstatic void 3233169689Skanmaybe_encapsulate_block (rtx first, rtx last, rtx equiv) 3234169689Skan{ 3235169689Skan if (!flag_non_call_exceptions || !may_trap_p (equiv)) 3236169689Skan { 3237169689Skan /* We can't attach the REG_LIBCALL and REG_RETVAL notes when the 3238169689Skan encapsulated region would not be in one basic block, i.e. when 3239169689Skan there is a control_flow_insn_p insn between FIRST and LAST. */ 3240169689Skan bool attach_libcall_retval_notes = true; 3241169689Skan rtx insn, next = NEXT_INSN (last); 3242169689Skan 3243169689Skan for (insn = first; insn != next; insn = NEXT_INSN (insn)) 3244169689Skan if (control_flow_insn_p (insn)) 3245169689Skan { 3246169689Skan attach_libcall_retval_notes = false; 3247169689Skan break; 3248169689Skan } 3249169689Skan 3250169689Skan if (attach_libcall_retval_notes) 3251169689Skan { 3252169689Skan REG_NOTES (first) = gen_rtx_INSN_LIST (REG_LIBCALL, last, 3253169689Skan REG_NOTES (first)); 3254169689Skan REG_NOTES (last) = gen_rtx_INSN_LIST (REG_RETVAL, first, 3255169689Skan REG_NOTES (last)); 3256169689Skan } 3257169689Skan } 3258169689Skan} 3259169689Skan 326018334Speter/* Emit code to perform a series of operations on a multi-word quantity, one 326118334Speter word at a time. 326218334Speter 326318334Speter Such a block is preceded by a CLOBBER of the output, consists of multiple 326418334Speter insns, each setting one word of the output, and followed by a SET copying 326518334Speter the output to itself. 326618334Speter 326718334Speter Each of the insns setting words of the output receives a REG_NO_CONFLICT 326818334Speter note indicating that it doesn't conflict with the (also multi-word) 326918334Speter inputs. The entire block is surrounded by REG_LIBCALL and REG_RETVAL 327018334Speter notes. 327118334Speter 327218334Speter INSNS is a block of code generated to perform the operation, not including 327318334Speter the CLOBBER and final copy. All insns that compute intermediate values 3274132718Skan are first emitted, followed by the block as described above. 327518334Speter 327618334Speter TARGET, OP0, and OP1 are the output and inputs of the operations, 327718334Speter respectively. OP1 may be zero for a unary operation. 327818334Speter 3279117395Skan EQUIV, if nonzero, is an expression to be placed into a REG_EQUAL note 328018334Speter on the last insn. 328118334Speter 328218334Speter If TARGET is not a register, INSNS is simply emitted with no special 328318334Speter processing. Likewise if anything in INSNS is not an INSN or if 328418334Speter there is a libcall block inside INSNS. 328518334Speter 328618334Speter The final insn emitted is returned. */ 328718334Speter 328818334Speterrtx 3289132718Skanemit_no_conflict_block (rtx insns, rtx target, rtx op0, rtx op1, rtx equiv) 329018334Speter{ 329118334Speter rtx prev, next, first, last, insn; 329218334Speter 3293169689Skan if (!REG_P (target) || reload_in_progress) 3294117395Skan return emit_insn (insns); 329518334Speter else 329618334Speter for (insn = insns; insn; insn = NEXT_INSN (insn)) 3297169689Skan if (!NONJUMP_INSN_P (insn) 329818334Speter || find_reg_note (insn, REG_LIBCALL, NULL_RTX)) 3299117395Skan return emit_insn (insns); 330018334Speter 330118334Speter /* First emit all insns that do not store into words of the output and remove 330218334Speter these from the list. */ 330318334Speter for (insn = insns; insn; insn = next) 330418334Speter { 3305169689Skan rtx note; 3306169689Skan struct no_conflict_data data; 330718334Speter 330818334Speter next = NEXT_INSN (insn); 330918334Speter 3310132718Skan /* Some ports (cris) create a libcall regions at their own. We must 331196263Sobrien avoid any potential nesting of LIBCALLs. */ 331296263Sobrien if ((note = find_reg_note (insn, REG_LIBCALL, NULL)) != NULL) 331396263Sobrien remove_note (insn, note); 331496263Sobrien if ((note = find_reg_note (insn, REG_RETVAL, NULL)) != NULL) 331596263Sobrien remove_note (insn, note); 331696263Sobrien 3317169689Skan data.target = target; 3318169689Skan data.first = insns; 3319169689Skan data.insn = insn; 3320169689Skan data.must_stay = 0; 3321169689Skan note_stores (PATTERN (insn), no_conflict_move_test, &data); 3322169689Skan if (! data.must_stay) 332318334Speter { 332418334Speter if (PREV_INSN (insn)) 332518334Speter NEXT_INSN (PREV_INSN (insn)) = next; 332618334Speter else 332718334Speter insns = next; 332818334Speter 332918334Speter if (next) 333018334Speter PREV_INSN (next) = PREV_INSN (insn); 333118334Speter 333218334Speter add_insn (insn); 333318334Speter } 333418334Speter } 333518334Speter 333618334Speter prev = get_last_insn (); 333718334Speter 333818334Speter /* Now write the CLOBBER of the output, followed by the setting of each 333918334Speter of the words, followed by the final copy. */ 334018334Speter if (target != op0 && target != op1) 334150397Sobrien emit_insn (gen_rtx_CLOBBER (VOIDmode, target)); 334218334Speter 334318334Speter for (insn = insns; insn; insn = next) 334418334Speter { 334518334Speter next = NEXT_INSN (insn); 334618334Speter add_insn (insn); 334718334Speter 3348169689Skan if (op1 && REG_P (op1)) 334950397Sobrien REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_NO_CONFLICT, op1, 335050397Sobrien REG_NOTES (insn)); 335118334Speter 3352169689Skan if (op0 && REG_P (op0)) 335350397Sobrien REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_NO_CONFLICT, op0, 335450397Sobrien REG_NOTES (insn)); 335518334Speter } 335618334Speter 335718334Speter if (mov_optab->handlers[(int) GET_MODE (target)].insn_code 335818334Speter != CODE_FOR_nothing) 335918334Speter { 336018334Speter last = emit_move_insn (target, target); 336118334Speter if (equiv) 336252284Sobrien set_unique_reg_note (last, REG_EQUAL, equiv); 336318334Speter } 336418334Speter else 336590075Sobrien { 336690075Sobrien last = get_last_insn (); 336718334Speter 336890075Sobrien /* Remove any existing REG_EQUAL note from "last", or else it will 336990075Sobrien be mistaken for a note referring to the full contents of the 337090075Sobrien alleged libcall value when found together with the REG_RETVAL 337190075Sobrien note added below. An existing note can come from an insn 337290075Sobrien expansion at "last". */ 337390075Sobrien remove_note (last, find_reg_note (last, REG_EQUAL, NULL_RTX)); 337490075Sobrien } 337590075Sobrien 337618334Speter if (prev == 0) 337718334Speter first = get_insns (); 337818334Speter else 337918334Speter first = NEXT_INSN (prev); 338018334Speter 3381169689Skan maybe_encapsulate_block (first, last, equiv); 338218334Speter 338318334Speter return last; 338418334Speter} 338518334Speter 338618334Speter/* Emit code to make a call to a constant function or a library call. 338718334Speter 338818334Speter INSNS is a list containing all insns emitted in the call. 338918334Speter These insns leave the result in RESULT. Our block is to copy RESULT 339018334Speter to TARGET, which is logically equivalent to EQUIV. 339118334Speter 339218334Speter We first emit any insns that set a pseudo on the assumption that these are 339318334Speter loading constants into registers; doing so allows them to be safely cse'ed 339418334Speter between blocks. Then we emit all the other insns in the block, followed by 339518334Speter an insn to move RESULT to TARGET. This last insn will have a REQ_EQUAL 339618334Speter note with an operand of EQUIV. 339718334Speter 339818334Speter Moving assignments to pseudos outside of the block is done to improve 339918334Speter the generated code, but is not required to generate correct code, 340018334Speter hence being unable to move an assignment is not grounds for not making 340118334Speter a libcall block. There are two reasons why it is safe to leave these 340218334Speter insns inside the block: First, we know that these pseudos cannot be 340318334Speter used in generated RTL outside the block since they are created for 340418334Speter temporary purposes within the block. Second, CSE will not record the 340518334Speter values of anything set inside a libcall block, so we know they must 340618334Speter be dead at the end of the block. 340718334Speter 340818334Speter Except for the first group of insns (the ones setting pseudos), the 340918334Speter block is delimited by REG_RETVAL and REG_LIBCALL notes. */ 341018334Speter 341118334Spetervoid 3412132718Skanemit_libcall_block (rtx insns, rtx target, rtx result, rtx equiv) 341318334Speter{ 341470635Sobrien rtx final_dest = target; 341518334Speter rtx prev, next, first, last, insn; 341618334Speter 341770635Sobrien /* If this is a reg with REG_USERVAR_P set, then it could possibly turn 341870635Sobrien into a MEM later. Protect the libcall block from this change. */ 341970635Sobrien if (! REG_P (target) || REG_USERVAR_P (target)) 342070635Sobrien target = gen_reg_rtx (GET_MODE (target)); 3421132718Skan 342290075Sobrien /* If we're using non-call exceptions, a libcall corresponding to an 342390075Sobrien operation that may trap may also trap. */ 342490075Sobrien if (flag_non_call_exceptions && may_trap_p (equiv)) 342590075Sobrien { 342690075Sobrien for (insn = insns; insn; insn = NEXT_INSN (insn)) 3427169689Skan if (CALL_P (insn)) 342890075Sobrien { 342990075Sobrien rtx note = find_reg_note (insn, REG_EH_REGION, NULL_RTX); 3430132718Skan 343190075Sobrien if (note != 0 && INTVAL (XEXP (note, 0)) <= 0) 343290075Sobrien remove_note (insn, note); 343390075Sobrien } 343490075Sobrien } 343590075Sobrien else 343652284Sobrien /* look for any CALL_INSNs in this sequence, and attach a REG_EH_REGION 343790075Sobrien reg note to indicate that this call cannot throw or execute a nonlocal 343890075Sobrien goto (unless there is already a REG_EH_REGION note, in which case 343990075Sobrien we update it). */ 344090075Sobrien for (insn = insns; insn; insn = NEXT_INSN (insn)) 3441169689Skan if (CALL_P (insn)) 344290075Sobrien { 344390075Sobrien rtx note = find_reg_note (insn, REG_EH_REGION, NULL_RTX); 3444132718Skan 344590075Sobrien if (note != 0) 3446169689Skan XEXP (note, 0) = constm1_rtx; 344790075Sobrien else 3448169689Skan REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_EH_REGION, constm1_rtx, 344990075Sobrien REG_NOTES (insn)); 345090075Sobrien } 345152284Sobrien 345218334Speter /* First emit all insns that set pseudos. Remove them from the list as 345318334Speter we go. Avoid insns that set pseudos which were referenced in previous 345418334Speter insns. These can be generated by move_by_pieces, for example, 345518334Speter to update an address. Similarly, avoid insns that reference things 345618334Speter set in previous insns. */ 345718334Speter 345818334Speter for (insn = insns; insn; insn = next) 345918334Speter { 346018334Speter rtx set = single_set (insn); 346196263Sobrien rtx note; 346218334Speter 3463132718Skan /* Some ports (cris) create a libcall regions at their own. We must 346496263Sobrien avoid any potential nesting of LIBCALLs. */ 346596263Sobrien if ((note = find_reg_note (insn, REG_LIBCALL, NULL)) != NULL) 346696263Sobrien remove_note (insn, note); 346796263Sobrien if ((note = find_reg_note (insn, REG_RETVAL, NULL)) != NULL) 346896263Sobrien remove_note (insn, note); 346996263Sobrien 347018334Speter next = NEXT_INSN (insn); 347118334Speter 3472169689Skan if (set != 0 && REG_P (SET_DEST (set)) 3473169689Skan && REGNO (SET_DEST (set)) >= FIRST_PSEUDO_REGISTER) 347418334Speter { 3475169689Skan struct no_conflict_data data; 347618334Speter 3477169689Skan data.target = const0_rtx; 3478169689Skan data.first = insns; 3479169689Skan data.insn = insn; 3480169689Skan data.must_stay = 0; 3481169689Skan note_stores (PATTERN (insn), no_conflict_move_test, &data); 3482169689Skan if (! data.must_stay) 3483169689Skan { 3484169689Skan if (PREV_INSN (insn)) 3485169689Skan NEXT_INSN (PREV_INSN (insn)) = next; 3486169689Skan else 3487169689Skan insns = next; 348818334Speter 3489169689Skan if (next) 3490169689Skan PREV_INSN (next) = PREV_INSN (insn); 3491169689Skan 3492169689Skan add_insn (insn); 3493169689Skan } 349418334Speter } 3495132718Skan 3496132718Skan /* Some ports use a loop to copy large arguments onto the stack. 3497132718Skan Don't move anything outside such a loop. */ 3498169689Skan if (LABEL_P (insn)) 3499132718Skan break; 350018334Speter } 350118334Speter 350218334Speter prev = get_last_insn (); 350318334Speter 350418334Speter /* Write the remaining insns followed by the final copy. */ 350518334Speter 350618334Speter for (insn = insns; insn; insn = next) 350718334Speter { 350818334Speter next = NEXT_INSN (insn); 350918334Speter 351018334Speter add_insn (insn); 351118334Speter } 351218334Speter 351318334Speter last = emit_move_insn (target, result); 351450397Sobrien if (mov_optab->handlers[(int) GET_MODE (target)].insn_code 351550397Sobrien != CODE_FOR_nothing) 351652284Sobrien set_unique_reg_note (last, REG_EQUAL, copy_rtx (equiv)); 351790075Sobrien else 351890075Sobrien { 351990075Sobrien /* Remove any existing REG_EQUAL note from "last", or else it will 352090075Sobrien be mistaken for a note referring to the full contents of the 352190075Sobrien libcall value when found together with the REG_RETVAL note added 352290075Sobrien below. An existing note can come from an insn expansion at 352390075Sobrien "last". */ 352490075Sobrien remove_note (last, find_reg_note (last, REG_EQUAL, NULL_RTX)); 352590075Sobrien } 352618334Speter 352770635Sobrien if (final_dest != target) 352870635Sobrien emit_move_insn (final_dest, target); 352970635Sobrien 353018334Speter if (prev == 0) 353118334Speter first = get_insns (); 353218334Speter else 353318334Speter first = NEXT_INSN (prev); 353418334Speter 3535169689Skan maybe_encapsulate_block (first, last, equiv); 353618334Speter} 353718334Speter 353890075Sobrien/* Nonzero if we can perform a comparison of mode MODE straightforwardly. 353990075Sobrien PURPOSE describes how this comparison will be used. CODE is the rtx 354090075Sobrien comparison code we will be using. 354118334Speter 354290075Sobrien ??? Actually, CODE is slightly weaker than that. A target is still 3543132718Skan required to implement all of the normal bcc operations, but not 354490075Sobrien required to implement all (or any) of the unordered bcc operations. */ 3545132718Skan 354690075Sobrienint 3547132718Skancan_compare_p (enum rtx_code code, enum machine_mode mode, 3548132718Skan enum can_compare_purpose purpose) 354990075Sobrien{ 355090075Sobrien do 355190075Sobrien { 3552117395Skan if (cmp_optab->handlers[(int) mode].insn_code != CODE_FOR_nothing) 355390075Sobrien { 355490075Sobrien if (purpose == ccp_jump) 3555117395Skan return bcc_gen_fctn[(int) code] != NULL; 355690075Sobrien else if (purpose == ccp_store_flag) 3557117395Skan return setcc_gen_code[(int) code] != CODE_FOR_nothing; 355890075Sobrien else 355990075Sobrien /* There's only one cmov entry point, and it's allowed to fail. */ 356090075Sobrien return 1; 356190075Sobrien } 356290075Sobrien if (purpose == ccp_jump 3563117395Skan && cbranch_optab->handlers[(int) mode].insn_code != CODE_FOR_nothing) 356490075Sobrien return 1; 356590075Sobrien if (purpose == ccp_cmov 3566117395Skan && cmov_optab->handlers[(int) mode].insn_code != CODE_FOR_nothing) 356790075Sobrien return 1; 356890075Sobrien if (purpose == ccp_store_flag 3569117395Skan && cstore_optab->handlers[(int) mode].insn_code != CODE_FOR_nothing) 357090075Sobrien return 1; 357190075Sobrien mode = GET_MODE_WIDER_MODE (mode); 357290075Sobrien } 357390075Sobrien while (mode != VOIDmode); 357490075Sobrien 357590075Sobrien return 0; 357690075Sobrien} 357790075Sobrien 357890075Sobrien/* This function is called when we are going to emit a compare instruction that 357990075Sobrien compares the values found in *PX and *PY, using the rtl operator COMPARISON. 358090075Sobrien 358190075Sobrien *PMODE is the mode of the inputs (in case they are const_int). 358290075Sobrien *PUNSIGNEDP nonzero says that the operands are unsigned; 358318334Speter this matters if they need to be widened. 358418334Speter 358590075Sobrien If they have mode BLKmode, then SIZE specifies the size of both operands. 358618334Speter 358790075Sobrien This function performs all the setup necessary so that the caller only has 358890075Sobrien to emit a single comparison insn. This setup can involve doing a BLKmode 358990075Sobrien comparison or emitting a library call to perform the comparison if no insn 359090075Sobrien is available to handle it. 359190075Sobrien The values which are passed in through pointers can be modified; the caller 3592169689Skan should perform the comparison on the modified values. Constant 3593169689Skan comparisons must have already been folded. */ 359418334Speter 359590075Sobrienstatic void 3596132718Skanprepare_cmp_insn (rtx *px, rtx *py, enum rtx_code *pcomparison, rtx size, 3597132718Skan enum machine_mode *pmode, int *punsignedp, 3598132718Skan enum can_compare_purpose purpose) 359918334Speter{ 360090075Sobrien enum machine_mode mode = *pmode; 360190075Sobrien rtx x = *px, y = *py; 360290075Sobrien int unsignedp = *punsignedp; 360318334Speter 3604169689Skan /* If we are inside an appropriately-short loop and we are optimizing, 3605169689Skan force expensive constants into a register. */ 3606169689Skan if (CONSTANT_P (x) && optimize 360790075Sobrien && rtx_cost (x, COMPARE) > COSTS_N_INSNS (1)) 360818334Speter x = force_reg (mode, x); 360918334Speter 3610169689Skan if (CONSTANT_P (y) && optimize 361190075Sobrien && rtx_cost (y, COMPARE) > COSTS_N_INSNS (1)) 361218334Speter y = force_reg (mode, y); 361318334Speter 361452284Sobrien#ifdef HAVE_cc0 3615169689Skan /* Make sure if we have a canonical comparison. The RTL 3616169689Skan documentation states that canonical comparisons are required only 3617169689Skan for targets which have cc0. */ 3618169689Skan gcc_assert (!CONSTANT_P (x) || CONSTANT_P (y)); 361952284Sobrien#endif 362052284Sobrien 362118334Speter /* Don't let both operands fail to indicate the mode. */ 362218334Speter if (GET_MODE (x) == VOIDmode && GET_MODE (y) == VOIDmode) 362318334Speter x = force_reg (mode, x); 362418334Speter 362518334Speter /* Handle all BLKmode compares. */ 362618334Speter 362718334Speter if (mode == BLKmode) 362818334Speter { 3629132718Skan enum machine_mode cmp_mode, result_mode; 3630132718Skan enum insn_code cmp_code; 3631132718Skan tree length_type; 3632132718Skan rtx libfunc; 363390075Sobrien rtx result; 3634132718Skan rtx opalign 363590075Sobrien = GEN_INT (MIN (MEM_ALIGN (x), MEM_ALIGN (y)) / BITS_PER_UNIT); 363690075Sobrien 3637169689Skan gcc_assert (size); 3638132718Skan 3639132718Skan /* Try to use a memory block compare insn - either cmpstr 3640132718Skan or cmpmem will do. */ 3641132718Skan for (cmp_mode = GET_CLASS_NARROWEST_MODE (MODE_INT); 3642132718Skan cmp_mode != VOIDmode; 3643132718Skan cmp_mode = GET_MODE_WIDER_MODE (cmp_mode)) 364418334Speter { 3645132718Skan cmp_code = cmpmem_optab[cmp_mode]; 3646132718Skan if (cmp_code == CODE_FOR_nothing) 3647132718Skan cmp_code = cmpstr_optab[cmp_mode]; 3648132718Skan if (cmp_code == CODE_FOR_nothing) 3649169689Skan cmp_code = cmpstrn_optab[cmp_mode]; 3650169689Skan if (cmp_code == CODE_FOR_nothing) 3651132718Skan continue; 3652132718Skan 3653132718Skan /* Must make sure the size fits the insn's mode. */ 3654132718Skan if ((GET_CODE (size) == CONST_INT 3655132718Skan && INTVAL (size) >= (1 << GET_MODE_BITSIZE (cmp_mode))) 3656132718Skan || (GET_MODE_BITSIZE (GET_MODE (size)) 3657132718Skan > GET_MODE_BITSIZE (cmp_mode))) 3658132718Skan continue; 3659132718Skan 3660132718Skan result_mode = insn_data[cmp_code].operand[0].mode; 366190075Sobrien result = gen_reg_rtx (result_mode); 3662132718Skan size = convert_to_mode (cmp_mode, size, 1); 3663132718Skan emit_insn (GEN_FCN (cmp_code) (result, x, y, size, opalign)); 3664132718Skan 3665132718Skan *px = result; 3666132718Skan *py = const0_rtx; 3667132718Skan *pmode = result_mode; 3668132718Skan return; 366918334Speter } 3670132718Skan 3671169689Skan /* Otherwise call a library function, memcmp. */ 3672132718Skan libfunc = memcmp_libfunc; 3673132718Skan length_type = sizetype; 3674132718Skan result_mode = TYPE_MODE (integer_type_node); 3675132718Skan cmp_mode = TYPE_MODE (length_type); 3676132718Skan size = convert_to_mode (TYPE_MODE (length_type), size, 3677169689Skan TYPE_UNSIGNED (length_type)); 367850397Sobrien 3679132718Skan result = emit_library_call_value (libfunc, 0, LCT_PURE_MAKE_BLOCK, 3680132718Skan result_mode, 3, 3681132718Skan XEXP (x, 0), Pmode, 3682132718Skan XEXP (y, 0), Pmode, 3683132718Skan size, cmp_mode); 368490075Sobrien *px = result; 368590075Sobrien *py = const0_rtx; 368690075Sobrien *pmode = result_mode; 368718334Speter return; 368818334Speter } 368918334Speter 3690132718Skan /* Don't allow operands to the compare to trap, as that can put the 3691132718Skan compare and branch in different basic blocks. */ 3692132718Skan if (flag_non_call_exceptions) 3693132718Skan { 3694132718Skan if (may_trap_p (x)) 3695132718Skan x = force_reg (mode, x); 3696132718Skan if (may_trap_p (y)) 3697132718Skan y = force_reg (mode, y); 3698132718Skan } 3699132718Skan 370090075Sobrien *px = x; 370190075Sobrien *py = y; 370290075Sobrien if (can_compare_p (*pcomparison, mode, purpose)) 370390075Sobrien return; 370418334Speter 370518334Speter /* Handle a lib call just for the mode we are using. */ 370618334Speter 3707169689Skan if (cmp_optab->handlers[(int) mode].libfunc && !SCALAR_FLOAT_MODE_P (mode)) 370818334Speter { 370918334Speter rtx libfunc = cmp_optab->handlers[(int) mode].libfunc; 371050397Sobrien rtx result; 371150397Sobrien 371218334Speter /* If we want unsigned, and this mode has a distinct unsigned 371318334Speter comparison routine, use that. */ 371418334Speter if (unsignedp && ucmp_optab->handlers[(int) mode].libfunc) 371518334Speter libfunc = ucmp_optab->handlers[(int) mode].libfunc; 371618334Speter 3717117395Skan result = emit_library_call_value (libfunc, NULL_RTX, LCT_CONST_MAKE_BLOCK, 3718117395Skan word_mode, 2, x, mode, y, mode); 371918334Speter 3720169689Skan /* There are two kinds of comparison routines. Biased routines 3721169689Skan return 0/1/2, and unbiased routines return -1/0/1. Other parts 3722169689Skan of gcc expect that the comparison operation is equivalent 3723169689Skan to the modified comparison. For signed comparisons compare the 3724169689Skan result against 1 in the biased case, and zero in the unbiased 3725169689Skan case. For unsigned comparisons always compare against 1 after 3726169689Skan biasing the unbiased result by adding 1. This gives us a way to 3727169689Skan represent LTU. */ 372890075Sobrien *px = result; 3729169689Skan *pmode = word_mode; 373090075Sobrien *py = const1_rtx; 3731169689Skan 3732169689Skan if (!TARGET_LIB_INT_CMP_BIASED) 3733169689Skan { 3734169689Skan if (*punsignedp) 3735169689Skan *px = plus_constant (result, 1); 3736169689Skan else 3737169689Skan *py = const0_rtx; 3738169689Skan } 373918334Speter return; 374018334Speter } 374118334Speter 3742169689Skan gcc_assert (SCALAR_FLOAT_MODE_P (mode)); 3743169689Skan prepare_float_lib_cmp (px, py, pcomparison, pmode, punsignedp); 374418334Speter} 374518334Speter 374690075Sobrien/* Before emitting an insn with code ICODE, make sure that X, which is going 374790075Sobrien to be used for operand OPNUM of the insn, is converted from mode MODE to 374890075Sobrien WIDER_MODE (UNSIGNEDP determines whether it is an unsigned conversion), and 374990075Sobrien that it is accepted by the operand predicate. Return the new value. */ 375090075Sobrien 3751169689Skanstatic rtx 3752132718Skanprepare_operand (int icode, rtx x, int opnum, enum machine_mode mode, 3753132718Skan enum machine_mode wider_mode, int unsignedp) 375490075Sobrien{ 375590075Sobrien if (mode != wider_mode) 375690075Sobrien x = convert_modes (wider_mode, mode, x, unsignedp); 375790075Sobrien 3758169689Skan if (!insn_data[icode].operand[opnum].predicate 375990075Sobrien (x, insn_data[icode].operand[opnum].mode)) 3760119256Skan { 3761119256Skan if (no_new_pseudos) 3762119256Skan return NULL_RTX; 3763119256Skan x = copy_to_mode_reg (insn_data[icode].operand[opnum].mode, x); 3764119256Skan } 3765119256Skan 376690075Sobrien return x; 376790075Sobrien} 376890075Sobrien 376990075Sobrien/* Subroutine of emit_cmp_and_jump_insns; this function is called when we know 377090075Sobrien we can do the comparison. 377190075Sobrien The arguments are the same as for emit_cmp_and_jump_insns; but LABEL may 377290075Sobrien be NULL_RTX which indicates that only a comparison is to be generated. */ 377390075Sobrien 377490075Sobrienstatic void 3775132718Skanemit_cmp_and_jump_insn_1 (rtx x, rtx y, enum machine_mode mode, 3776132718Skan enum rtx_code comparison, int unsignedp, rtx label) 377790075Sobrien{ 377890075Sobrien rtx test = gen_rtx_fmt_ee (comparison, mode, x, y); 377990075Sobrien enum mode_class class = GET_MODE_CLASS (mode); 378090075Sobrien enum machine_mode wider_mode = mode; 378190075Sobrien 378290075Sobrien /* Try combined insns first. */ 378390075Sobrien do 378490075Sobrien { 378590075Sobrien enum insn_code icode; 378690075Sobrien PUT_MODE (test, wider_mode); 378790075Sobrien 378890075Sobrien if (label) 3789132718Skan { 3790117395Skan icode = cbranch_optab->handlers[(int) wider_mode].insn_code; 3791132718Skan 379290075Sobrien if (icode != CODE_FOR_nothing 3793169689Skan && insn_data[icode].operand[0].predicate (test, wider_mode)) 379490075Sobrien { 379590075Sobrien x = prepare_operand (icode, x, 1, mode, wider_mode, unsignedp); 379690075Sobrien y = prepare_operand (icode, y, 2, mode, wider_mode, unsignedp); 379790075Sobrien emit_jump_insn (GEN_FCN (icode) (test, x, y, label)); 379890075Sobrien return; 379990075Sobrien } 380090075Sobrien } 380190075Sobrien 380290075Sobrien /* Handle some compares against zero. */ 380390075Sobrien icode = (int) tst_optab->handlers[(int) wider_mode].insn_code; 380490075Sobrien if (y == CONST0_RTX (mode) && icode != CODE_FOR_nothing) 380590075Sobrien { 380690075Sobrien x = prepare_operand (icode, x, 0, mode, wider_mode, unsignedp); 380790075Sobrien emit_insn (GEN_FCN (icode) (x)); 380890075Sobrien if (label) 3809169689Skan emit_jump_insn (bcc_gen_fctn[(int) comparison] (label)); 381090075Sobrien return; 381190075Sobrien } 381290075Sobrien 381390075Sobrien /* Handle compares for which there is a directly suitable insn. */ 381490075Sobrien 381590075Sobrien icode = (int) cmp_optab->handlers[(int) wider_mode].insn_code; 381690075Sobrien if (icode != CODE_FOR_nothing) 381790075Sobrien { 381890075Sobrien x = prepare_operand (icode, x, 0, mode, wider_mode, unsignedp); 381990075Sobrien y = prepare_operand (icode, y, 1, mode, wider_mode, unsignedp); 382090075Sobrien emit_insn (GEN_FCN (icode) (x, y)); 382190075Sobrien if (label) 3822169689Skan emit_jump_insn (bcc_gen_fctn[(int) comparison] (label)); 382390075Sobrien return; 382490075Sobrien } 382590075Sobrien 3826169689Skan if (!CLASS_HAS_WIDER_MODES_P (class)) 382790075Sobrien break; 382890075Sobrien 382990075Sobrien wider_mode = GET_MODE_WIDER_MODE (wider_mode); 3830117395Skan } 3831117395Skan while (wider_mode != VOIDmode); 383290075Sobrien 3833169689Skan gcc_unreachable (); 383490075Sobrien} 383590075Sobrien 383652284Sobrien/* Generate code to compare X with Y so that the condition codes are 383752284Sobrien set and to jump to LABEL if the condition is true. If X is a 383852284Sobrien constant and Y is not a constant, then the comparison is swapped to 383952284Sobrien ensure that the comparison RTL has the canonical form. 384052284Sobrien 384152284Sobrien UNSIGNEDP nonzero says that X and Y are unsigned; this matters if they 384252284Sobrien need to be widened by emit_cmp_insn. UNSIGNEDP is also used to select 384352284Sobrien the proper branch condition code. 384452284Sobrien 384590075Sobrien If X and Y have mode BLKmode, then SIZE specifies the size of both X and Y. 384652284Sobrien 384752284Sobrien MODE is the mode of the inputs (in case they are const_int). 384852284Sobrien 384952284Sobrien COMPARISON is the rtl operator to compare with (EQ, NE, GT, etc.). It will 385052284Sobrien be passed unchanged to emit_cmp_insn, then potentially converted into an 385152284Sobrien unsigned variant based on UNSIGNEDP to select a proper jump instruction. */ 385252284Sobrien 385352284Sobrienvoid 3854132718Skanemit_cmp_and_jump_insns (rtx x, rtx y, enum rtx_code comparison, rtx size, 3855132718Skan enum machine_mode mode, int unsignedp, rtx label) 385652284Sobrien{ 385790075Sobrien rtx op0 = x, op1 = y; 385890075Sobrien 385990075Sobrien /* Swap operands and condition to ensure canonical RTL. */ 386090075Sobrien if (swap_commutative_operands_p (x, y)) 386152284Sobrien { 386290075Sobrien /* If we're not emitting a branch, this means some caller 386390075Sobrien is out of sync. */ 3864169689Skan gcc_assert (label); 386590075Sobrien 386690075Sobrien op0 = y, op1 = x; 386752284Sobrien comparison = swap_condition (comparison); 386852284Sobrien } 386952284Sobrien 387052284Sobrien#ifdef HAVE_cc0 3871169689Skan /* If OP0 is still a constant, then both X and Y must be constants. 3872169689Skan Force X into a register to create canonical RTL. */ 387352284Sobrien if (CONSTANT_P (op0)) 387452284Sobrien op0 = force_reg (mode, op0); 387552284Sobrien#endif 387652284Sobrien 387752284Sobrien if (unsignedp) 387852284Sobrien comparison = unsigned_condition (comparison); 387990075Sobrien 388090075Sobrien prepare_cmp_insn (&op0, &op1, &comparison, size, &mode, &unsignedp, 388190075Sobrien ccp_jump); 388290075Sobrien emit_cmp_and_jump_insn_1 (op0, op1, mode, comparison, unsignedp, label); 388352284Sobrien} 388452284Sobrien 388590075Sobrien/* Like emit_cmp_and_jump_insns, but generate only the comparison. */ 388652284Sobrien 388790075Sobrienvoid 3888132718Skanemit_cmp_insn (rtx x, rtx y, enum rtx_code comparison, rtx size, 3889132718Skan enum machine_mode mode, int unsignedp) 389018334Speter{ 389190075Sobrien emit_cmp_and_jump_insns (x, y, comparison, size, mode, unsignedp, 0); 389218334Speter} 389318334Speter 389418334Speter/* Emit a library call comparison between floating point X and Y. 389518334Speter COMPARISON is the rtl operator to compare with (EQ, NE, GT, etc.). */ 389618334Speter 389790075Sobrienstatic void 3898132718Skanprepare_float_lib_cmp (rtx *px, rtx *py, enum rtx_code *pcomparison, 3899132718Skan enum machine_mode *pmode, int *punsignedp) 390018334Speter{ 390190075Sobrien enum rtx_code comparison = *pcomparison; 3902132718Skan enum rtx_code swapped = swap_condition (comparison); 3903169689Skan enum rtx_code reversed = reverse_condition_maybe_unordered (comparison); 3904169689Skan rtx x = *px; 3905169689Skan rtx y = *py; 3906132718Skan enum machine_mode orig_mode = GET_MODE (x); 3907132718Skan enum machine_mode mode; 3908132718Skan rtx value, target, insns, equiv; 390918334Speter rtx libfunc = 0; 3910169689Skan bool reversed_p = false; 391118334Speter 3912169689Skan for (mode = orig_mode; 3913169689Skan mode != VOIDmode; 3914169689Skan mode = GET_MODE_WIDER_MODE (mode)) 3915132718Skan { 3916132718Skan if ((libfunc = code_to_optab[comparison]->handlers[mode].libfunc)) 391718334Speter break; 391818334Speter 3919132718Skan if ((libfunc = code_to_optab[swapped]->handlers[mode].libfunc)) 3920132718Skan { 3921132718Skan rtx tmp; 3922132718Skan tmp = x; x = y; y = tmp; 3923132718Skan comparison = swapped; 3924132718Skan break; 3925132718Skan } 3926169689Skan 3927169689Skan if ((libfunc = code_to_optab[reversed]->handlers[mode].libfunc) 3928169689Skan && FLOAT_LIB_COMPARE_RETURNS_BOOL (mode, reversed)) 3929169689Skan { 3930169689Skan comparison = reversed; 3931169689Skan reversed_p = true; 3932169689Skan break; 3933169689Skan } 3934132718Skan } 393518334Speter 3936169689Skan gcc_assert (mode != VOIDmode); 393718334Speter 3938132718Skan if (mode != orig_mode) 3939132718Skan { 3940132718Skan x = convert_to_mode (mode, x, 0); 3941132718Skan y = convert_to_mode (mode, y, 0); 3942132718Skan } 394318334Speter 3944132718Skan /* Attach a REG_EQUAL note describing the semantics of the libcall to 3945132718Skan the RTL. The allows the RTL optimizers to delete the libcall if the 3946132718Skan condition can be determined at compile-time. */ 3947132718Skan if (comparison == UNORDERED) 3948132718Skan { 3949132718Skan rtx temp = simplify_gen_relational (NE, word_mode, mode, x, x); 3950132718Skan equiv = simplify_gen_relational (NE, word_mode, mode, y, y); 3951132718Skan equiv = simplify_gen_ternary (IF_THEN_ELSE, word_mode, word_mode, 3952132718Skan temp, const_true_rtx, equiv); 3953132718Skan } 3954132718Skan else 3955132718Skan { 3956132718Skan equiv = simplify_gen_relational (comparison, word_mode, mode, x, y); 3957132718Skan if (! FLOAT_LIB_COMPARE_RETURNS_BOOL (mode, comparison)) 3958132718Skan { 3959132718Skan rtx true_rtx, false_rtx; 396018334Speter 3961132718Skan switch (comparison) 3962132718Skan { 3963132718Skan case EQ: 3964132718Skan true_rtx = const0_rtx; 3965132718Skan false_rtx = const_true_rtx; 3966132718Skan break; 396750397Sobrien 3968132718Skan case NE: 3969132718Skan true_rtx = const_true_rtx; 3970132718Skan false_rtx = const0_rtx; 3971132718Skan break; 397290075Sobrien 3973132718Skan case GT: 3974132718Skan true_rtx = const1_rtx; 3975132718Skan false_rtx = const0_rtx; 3976132718Skan break; 397718334Speter 3978132718Skan case GE: 3979132718Skan true_rtx = const0_rtx; 3980132718Skan false_rtx = constm1_rtx; 3981132718Skan break; 398218334Speter 3983132718Skan case LT: 3984132718Skan true_rtx = constm1_rtx; 3985132718Skan false_rtx = const0_rtx; 3986132718Skan break; 398718334Speter 3988132718Skan case LE: 3989132718Skan true_rtx = const0_rtx; 3990132718Skan false_rtx = const1_rtx; 3991132718Skan break; 399218334Speter 3993132718Skan default: 3994169689Skan gcc_unreachable (); 3995132718Skan } 3996132718Skan equiv = simplify_gen_ternary (IF_THEN_ELSE, word_mode, word_mode, 3997132718Skan equiv, true_rtx, false_rtx); 3998132718Skan } 3999132718Skan } 400018334Speter 4001132718Skan start_sequence (); 4002132718Skan value = emit_library_call_value (libfunc, NULL_RTX, LCT_CONST, 4003132718Skan word_mode, 2, x, mode, y, mode); 4004132718Skan insns = get_insns (); 4005132718Skan end_sequence (); 400650397Sobrien 4007132718Skan target = gen_reg_rtx (word_mode); 4008132718Skan emit_libcall_block (insns, target, value, equiv); 400990075Sobrien 4010132718Skan if (comparison == UNORDERED 4011132718Skan || FLOAT_LIB_COMPARE_RETURNS_BOOL (mode, comparison)) 4012169689Skan comparison = reversed_p ? EQ : NE; 401318334Speter 4014132718Skan *px = target; 401590075Sobrien *py = const0_rtx; 401690075Sobrien *pmode = word_mode; 4017132718Skan *pcomparison = comparison; 401890075Sobrien *punsignedp = 0; 401918334Speter} 402018334Speter 402118334Speter/* Generate code to indirectly jump to a location given in the rtx LOC. */ 402218334Speter 402318334Spetervoid 4024132718Skanemit_indirect_jump (rtx loc) 402518334Speter{ 4026169689Skan if (!insn_data[(int) CODE_FOR_indirect_jump].operand[0].predicate 4027169689Skan (loc, Pmode)) 402818334Speter loc = copy_to_mode_reg (Pmode, loc); 402918334Speter 403018334Speter emit_jump_insn (gen_indirect_jump (loc)); 403118334Speter emit_barrier (); 403218334Speter} 403318334Speter 403418334Speter#ifdef HAVE_conditional_move 403518334Speter 403618334Speter/* Emit a conditional move instruction if the machine supports one for that 403718334Speter condition and machine mode. 403818334Speter 403918334Speter OP0 and OP1 are the operands that should be compared using CODE. CMODE is 404018334Speter the mode to use should they be constants. If it is VOIDmode, they cannot 404118334Speter both be constants. 404218334Speter 404318334Speter OP2 should be stored in TARGET if the comparison is true, otherwise OP3 404418334Speter should be stored there. MODE is the mode to use should they be constants. 404518334Speter If it is VOIDmode, they cannot both be constants. 404618334Speter 404718334Speter The result is either TARGET (perhaps modified) or NULL_RTX if the operation 404818334Speter is not supported. */ 404918334Speter 405018334Speterrtx 4051132718Skanemit_conditional_move (rtx target, enum rtx_code code, rtx op0, rtx op1, 4052132718Skan enum machine_mode cmode, rtx op2, rtx op3, 4053132718Skan enum machine_mode mode, int unsignedp) 405418334Speter{ 405518334Speter rtx tem, subtarget, comparison, insn; 405618334Speter enum insn_code icode; 405790075Sobrien enum rtx_code reversed; 405818334Speter 405918334Speter /* If one operand is constant, make it the second one. Only do this 406018334Speter if the other operand is not constant as well. */ 406118334Speter 406290075Sobrien if (swap_commutative_operands_p (op0, op1)) 406318334Speter { 406418334Speter tem = op0; 406518334Speter op0 = op1; 406618334Speter op1 = tem; 406718334Speter code = swap_condition (code); 406818334Speter } 406918334Speter 407090075Sobrien /* get_condition will prefer to generate LT and GT even if the old 407190075Sobrien comparison was against zero, so undo that canonicalization here since 407290075Sobrien comparisons against zero are cheaper. */ 4073132718Skan if (code == LT && op1 == const1_rtx) 407490075Sobrien code = LE, op1 = const0_rtx; 4075132718Skan else if (code == GT && op1 == constm1_rtx) 407690075Sobrien code = GE, op1 = const0_rtx; 407790075Sobrien 407818334Speter if (cmode == VOIDmode) 407918334Speter cmode = GET_MODE (op0); 408018334Speter 408190075Sobrien if (swap_commutative_operands_p (op2, op3) 408290075Sobrien && ((reversed = reversed_comparison_code_parts (code, op0, op1, NULL)) 408390075Sobrien != UNKNOWN)) 408418334Speter { 408518334Speter tem = op2; 408618334Speter op2 = op3; 408718334Speter op3 = tem; 408890075Sobrien code = reversed; 408918334Speter } 409018334Speter 409118334Speter if (mode == VOIDmode) 409218334Speter mode = GET_MODE (op2); 409318334Speter 409418334Speter icode = movcc_gen_code[mode]; 409518334Speter 409618334Speter if (icode == CODE_FOR_nothing) 409718334Speter return 0; 409818334Speter 4099169689Skan if (!target) 410018334Speter target = gen_reg_rtx (mode); 410118334Speter 410218334Speter subtarget = target; 410318334Speter 410418334Speter /* If the insn doesn't accept these operands, put them in pseudos. */ 410518334Speter 4106169689Skan if (!insn_data[icode].operand[0].predicate 410790075Sobrien (subtarget, insn_data[icode].operand[0].mode)) 410890075Sobrien subtarget = gen_reg_rtx (insn_data[icode].operand[0].mode); 410918334Speter 4110169689Skan if (!insn_data[icode].operand[2].predicate 411190075Sobrien (op2, insn_data[icode].operand[2].mode)) 411290075Sobrien op2 = copy_to_mode_reg (insn_data[icode].operand[2].mode, op2); 411318334Speter 4114169689Skan if (!insn_data[icode].operand[3].predicate 411590075Sobrien (op3, insn_data[icode].operand[3].mode)) 411690075Sobrien op3 = copy_to_mode_reg (insn_data[icode].operand[3].mode, op3); 411718334Speter 411818334Speter /* Everything should now be in the suitable form, so emit the compare insn 411918334Speter and then the conditional move. */ 412018334Speter 4121132718Skan comparison 412290075Sobrien = compare_from_rtx (op0, op1, code, unsignedp, cmode, NULL_RTX); 412318334Speter 412418334Speter /* ??? Watch for const0_rtx (nop) and const_true_rtx (unconditional)? */ 412590075Sobrien /* We can get const0_rtx or const_true_rtx in some circumstances. Just 412690075Sobrien return NULL and let the caller figure out how best to deal with this 412790075Sobrien situation. */ 412818334Speter if (GET_CODE (comparison) != code) 412990075Sobrien return NULL_RTX; 4130132718Skan 413118334Speter insn = GEN_FCN (icode) (subtarget, comparison, op2, op3); 413218334Speter 413318334Speter /* If that failed, then give up. */ 413418334Speter if (insn == 0) 413518334Speter return 0; 413618334Speter 413718334Speter emit_insn (insn); 413818334Speter 413918334Speter if (subtarget != target) 414018334Speter convert_move (target, subtarget, 0); 414118334Speter 414218334Speter return target; 414318334Speter} 414418334Speter 4145117395Skan/* Return nonzero if a conditional move of mode MODE is supported. 414618334Speter 414718334Speter This function is for combine so it can tell whether an insn that looks 414818334Speter like a conditional move is actually supported by the hardware. If we 414918334Speter guess wrong we lose a bit on optimization, but that's it. */ 415018334Speter/* ??? sparc64 supports conditionally moving integers values based on fp 415118334Speter comparisons, and vice versa. How do we handle them? */ 415218334Speter 415318334Speterint 4154132718Skancan_conditionally_move_p (enum machine_mode mode) 415518334Speter{ 415618334Speter if (movcc_gen_code[mode] != CODE_FOR_nothing) 415718334Speter return 1; 415818334Speter 415918334Speter return 0; 416018334Speter} 416118334Speter 416218334Speter#endif /* HAVE_conditional_move */ 4163132718Skan 4164132718Skan/* Emit a conditional addition instruction if the machine supports one for that 4165132718Skan condition and machine mode. 4166132718Skan 4167132718Skan OP0 and OP1 are the operands that should be compared using CODE. CMODE is 4168132718Skan the mode to use should they be constants. If it is VOIDmode, they cannot 4169132718Skan both be constants. 4170132718Skan 4171132718Skan OP2 should be stored in TARGET if the comparison is true, otherwise OP2+OP3 4172132718Skan should be stored there. MODE is the mode to use should they be constants. 4173132718Skan If it is VOIDmode, they cannot both be constants. 4174132718Skan 4175132718Skan The result is either TARGET (perhaps modified) or NULL_RTX if the operation 4176132718Skan is not supported. */ 4177132718Skan 4178132718Skanrtx 4179132718Skanemit_conditional_add (rtx target, enum rtx_code code, rtx op0, rtx op1, 4180132718Skan enum machine_mode cmode, rtx op2, rtx op3, 4181132718Skan enum machine_mode mode, int unsignedp) 4182132718Skan{ 4183132718Skan rtx tem, subtarget, comparison, insn; 4184132718Skan enum insn_code icode; 4185132718Skan enum rtx_code reversed; 4186132718Skan 4187132718Skan /* If one operand is constant, make it the second one. Only do this 4188132718Skan if the other operand is not constant as well. */ 4189132718Skan 4190132718Skan if (swap_commutative_operands_p (op0, op1)) 4191132718Skan { 4192132718Skan tem = op0; 4193132718Skan op0 = op1; 4194132718Skan op1 = tem; 4195132718Skan code = swap_condition (code); 4196132718Skan } 4197132718Skan 4198132718Skan /* get_condition will prefer to generate LT and GT even if the old 4199132718Skan comparison was against zero, so undo that canonicalization here since 4200132718Skan comparisons against zero are cheaper. */ 4201132718Skan if (code == LT && op1 == const1_rtx) 4202132718Skan code = LE, op1 = const0_rtx; 4203132718Skan else if (code == GT && op1 == constm1_rtx) 4204132718Skan code = GE, op1 = const0_rtx; 4205132718Skan 4206132718Skan if (cmode == VOIDmode) 4207132718Skan cmode = GET_MODE (op0); 4208132718Skan 4209132718Skan if (swap_commutative_operands_p (op2, op3) 4210132718Skan && ((reversed = reversed_comparison_code_parts (code, op0, op1, NULL)) 4211132718Skan != UNKNOWN)) 4212132718Skan { 4213132718Skan tem = op2; 4214132718Skan op2 = op3; 4215132718Skan op3 = tem; 4216132718Skan code = reversed; 4217132718Skan } 4218132718Skan 4219132718Skan if (mode == VOIDmode) 4220132718Skan mode = GET_MODE (op2); 4221132718Skan 4222132718Skan icode = addcc_optab->handlers[(int) mode].insn_code; 4223132718Skan 4224132718Skan if (icode == CODE_FOR_nothing) 4225132718Skan return 0; 4226132718Skan 4227169689Skan if (!target) 4228132718Skan target = gen_reg_rtx (mode); 4229132718Skan 4230132718Skan /* If the insn doesn't accept these operands, put them in pseudos. */ 4231132718Skan 4232169689Skan if (!insn_data[icode].operand[0].predicate 4233169689Skan (target, insn_data[icode].operand[0].mode)) 4234132718Skan subtarget = gen_reg_rtx (insn_data[icode].operand[0].mode); 4235169689Skan else 4236169689Skan subtarget = target; 4237132718Skan 4238169689Skan if (!insn_data[icode].operand[2].predicate 4239132718Skan (op2, insn_data[icode].operand[2].mode)) 4240132718Skan op2 = copy_to_mode_reg (insn_data[icode].operand[2].mode, op2); 4241132718Skan 4242169689Skan if (!insn_data[icode].operand[3].predicate 4243132718Skan (op3, insn_data[icode].operand[3].mode)) 4244132718Skan op3 = copy_to_mode_reg (insn_data[icode].operand[3].mode, op3); 4245132718Skan 4246132718Skan /* Everything should now be in the suitable form, so emit the compare insn 4247132718Skan and then the conditional move. */ 4248132718Skan 4249132718Skan comparison 4250132718Skan = compare_from_rtx (op0, op1, code, unsignedp, cmode, NULL_RTX); 4251132718Skan 4252132718Skan /* ??? Watch for const0_rtx (nop) and const_true_rtx (unconditional)? */ 4253132718Skan /* We can get const0_rtx or const_true_rtx in some circumstances. Just 4254132718Skan return NULL and let the caller figure out how best to deal with this 4255132718Skan situation. */ 4256132718Skan if (GET_CODE (comparison) != code) 4257132718Skan return NULL_RTX; 4258132718Skan 4259132718Skan insn = GEN_FCN (icode) (subtarget, comparison, op2, op3); 4260132718Skan 4261132718Skan /* If that failed, then give up. */ 4262132718Skan if (insn == 0) 4263132718Skan return 0; 4264132718Skan 4265132718Skan emit_insn (insn); 4266132718Skan 4267132718Skan if (subtarget != target) 4268132718Skan convert_move (target, subtarget, 0); 4269132718Skan 4270132718Skan return target; 4271132718Skan} 427218334Speter 4273132718Skan/* These functions attempt to generate an insn body, rather than 4274132718Skan emitting the insn, but if the gen function already emits them, we 4275169689Skan make no attempt to turn them back into naked patterns. */ 427618334Speter 427718334Speter/* Generate and return an insn body to add Y to X. */ 427818334Speter 427918334Speterrtx 4280132718Skangen_add2_insn (rtx x, rtx y) 428118334Speter{ 4282132718Skan int icode = (int) add_optab->handlers[(int) GET_MODE (x)].insn_code; 428318334Speter 4284169689Skan gcc_assert (insn_data[icode].operand[0].predicate 4285169689Skan (x, insn_data[icode].operand[0].mode)); 4286169689Skan gcc_assert (insn_data[icode].operand[1].predicate 4287169689Skan (x, insn_data[icode].operand[1].mode)); 4288169689Skan gcc_assert (insn_data[icode].operand[2].predicate 4289169689Skan (y, insn_data[icode].operand[2].mode)); 429018334Speter 4291169689Skan return GEN_FCN (icode) (x, x, y); 429218334Speter} 429318334Speter 429490075Sobrien/* Generate and return an insn body to add r1 and c, 429590075Sobrien storing the result in r0. */ 429690075Sobrienrtx 4297132718Skangen_add3_insn (rtx r0, rtx r1, rtx c) 429890075Sobrien{ 429990075Sobrien int icode = (int) add_optab->handlers[(int) GET_MODE (r0)].insn_code; 430090075Sobrien 4301117395Skan if (icode == CODE_FOR_nothing 4302169689Skan || !(insn_data[icode].operand[0].predicate 4303169689Skan (r0, insn_data[icode].operand[0].mode)) 4304169689Skan || !(insn_data[icode].operand[1].predicate 4305169689Skan (r1, insn_data[icode].operand[1].mode)) 4306169689Skan || !(insn_data[icode].operand[2].predicate 4307169689Skan (c, insn_data[icode].operand[2].mode))) 430890075Sobrien return NULL_RTX; 430990075Sobrien 4310169689Skan return GEN_FCN (icode) (r0, r1, c); 431190075Sobrien} 431290075Sobrien 431318334Speterint 4314132718Skanhave_add2_insn (rtx x, rtx y) 431518334Speter{ 431690075Sobrien int icode; 431790075Sobrien 4318169689Skan gcc_assert (GET_MODE (x) != VOIDmode); 431990075Sobrien 4320132718Skan icode = (int) add_optab->handlers[(int) GET_MODE (x)].insn_code; 432190075Sobrien 432290075Sobrien if (icode == CODE_FOR_nothing) 432390075Sobrien return 0; 432490075Sobrien 4325169689Skan if (!(insn_data[icode].operand[0].predicate 4326169689Skan (x, insn_data[icode].operand[0].mode)) 4327169689Skan || !(insn_data[icode].operand[1].predicate 4328169689Skan (x, insn_data[icode].operand[1].mode)) 4329169689Skan || !(insn_data[icode].operand[2].predicate 4330169689Skan (y, insn_data[icode].operand[2].mode))) 433190075Sobrien return 0; 433290075Sobrien 433390075Sobrien return 1; 433418334Speter} 433518334Speter 433618334Speter/* Generate and return an insn body to subtract Y from X. */ 433718334Speter 433818334Speterrtx 4339132718Skangen_sub2_insn (rtx x, rtx y) 434018334Speter{ 4341132718Skan int icode = (int) sub_optab->handlers[(int) GET_MODE (x)].insn_code; 434218334Speter 4343169689Skan gcc_assert (insn_data[icode].operand[0].predicate 4344169689Skan (x, insn_data[icode].operand[0].mode)); 4345169689Skan gcc_assert (insn_data[icode].operand[1].predicate 4346169689Skan (x, insn_data[icode].operand[1].mode)); 4347169689Skan gcc_assert (insn_data[icode].operand[2].predicate 4348169689Skan (y, insn_data[icode].operand[2].mode)); 434918334Speter 4350169689Skan return GEN_FCN (icode) (x, x, y); 435118334Speter} 435218334Speter 435390075Sobrien/* Generate and return an insn body to subtract r1 and c, 435490075Sobrien storing the result in r0. */ 435590075Sobrienrtx 4356132718Skangen_sub3_insn (rtx r0, rtx r1, rtx c) 435790075Sobrien{ 435890075Sobrien int icode = (int) sub_optab->handlers[(int) GET_MODE (r0)].insn_code; 435990075Sobrien 4360117395Skan if (icode == CODE_FOR_nothing 4361169689Skan || !(insn_data[icode].operand[0].predicate 4362169689Skan (r0, insn_data[icode].operand[0].mode)) 4363169689Skan || !(insn_data[icode].operand[1].predicate 4364169689Skan (r1, insn_data[icode].operand[1].mode)) 4365169689Skan || !(insn_data[icode].operand[2].predicate 4366169689Skan (c, insn_data[icode].operand[2].mode))) 436790075Sobrien return NULL_RTX; 436890075Sobrien 4369169689Skan return GEN_FCN (icode) (r0, r1, c); 437090075Sobrien} 437190075Sobrien 437218334Speterint 4373132718Skanhave_sub2_insn (rtx x, rtx y) 437418334Speter{ 437590075Sobrien int icode; 437690075Sobrien 4377169689Skan gcc_assert (GET_MODE (x) != VOIDmode); 437890075Sobrien 4379132718Skan icode = (int) sub_optab->handlers[(int) GET_MODE (x)].insn_code; 438090075Sobrien 438190075Sobrien if (icode == CODE_FOR_nothing) 438290075Sobrien return 0; 438390075Sobrien 4384169689Skan if (!(insn_data[icode].operand[0].predicate 4385169689Skan (x, insn_data[icode].operand[0].mode)) 4386169689Skan || !(insn_data[icode].operand[1].predicate 4387169689Skan (x, insn_data[icode].operand[1].mode)) 4388169689Skan || !(insn_data[icode].operand[2].predicate 4389169689Skan (y, insn_data[icode].operand[2].mode))) 439090075Sobrien return 0; 439190075Sobrien 439290075Sobrien return 1; 439318334Speter} 439418334Speter 439518334Speter/* Generate the body of an instruction to copy Y into X. 4396117395Skan It may be a list of insns, if one insn isn't enough. */ 439718334Speter 439818334Speterrtx 4399132718Skangen_move_insn (rtx x, rtx y) 440018334Speter{ 440118334Speter rtx seq; 440218334Speter 440318334Speter start_sequence (); 440418334Speter emit_move_insn_1 (x, y); 4405117395Skan seq = get_insns (); 440618334Speter end_sequence (); 440718334Speter return seq; 440818334Speter} 440918334Speter 441018334Speter/* Return the insn code used to extend FROM_MODE to TO_MODE. 441118334Speter UNSIGNEDP specifies zero-extension instead of sign-extension. If 441218334Speter no such operation exists, CODE_FOR_nothing will be returned. */ 441318334Speter 441418334Speterenum insn_code 4415132718Skancan_extend_p (enum machine_mode to_mode, enum machine_mode from_mode, 4416132718Skan int unsignedp) 441718334Speter{ 4418132718Skan convert_optab tab; 441990075Sobrien#ifdef HAVE_ptr_extend 442090075Sobrien if (unsignedp < 0) 442190075Sobrien return CODE_FOR_ptr_extend; 442290075Sobrien#endif 4423132718Skan 4424132718Skan tab = unsignedp ? zext_optab : sext_optab; 4425132718Skan return tab->handlers[to_mode][from_mode].insn_code; 442618334Speter} 442718334Speter 442818334Speter/* Generate the body of an insn to extend Y (with mode MFROM) 442918334Speter into X (with mode MTO). Do zero-extension if UNSIGNEDP is nonzero. */ 443018334Speter 443118334Speterrtx 4432132718Skangen_extend_insn (rtx x, rtx y, enum machine_mode mto, 4433132718Skan enum machine_mode mfrom, int unsignedp) 443418334Speter{ 4435132718Skan enum insn_code icode = can_extend_p (mto, mfrom, unsignedp); 4436132718Skan return GEN_FCN (icode) (x, y); 443718334Speter} 443818334Speter 443918334Speter/* can_fix_p and can_float_p say whether the target machine 444018334Speter can directly convert a given fixed point type to 444118334Speter a given floating point type, or vice versa. 444218334Speter The returned value is the CODE_FOR_... value to use, 444318334Speter or CODE_FOR_nothing if these modes cannot be directly converted. 444418334Speter 444518334Speter *TRUNCP_PTR is set to 1 if it is necessary to output 444618334Speter an explicit FTRUNC insn before the fix insn; otherwise 0. */ 444718334Speter 444818334Speterstatic enum insn_code 4449132718Skancan_fix_p (enum machine_mode fixmode, enum machine_mode fltmode, 4450132718Skan int unsignedp, int *truncp_ptr) 445118334Speter{ 4452132718Skan convert_optab tab; 4453132718Skan enum insn_code icode; 445418334Speter 4455132718Skan tab = unsignedp ? ufixtrunc_optab : sfixtrunc_optab; 4456132718Skan icode = tab->handlers[fixmode][fltmode].insn_code; 4457132718Skan if (icode != CODE_FOR_nothing) 445818334Speter { 4459132718Skan *truncp_ptr = 0; 4460132718Skan return icode; 4461132718Skan } 4462132718Skan 4463169689Skan /* FIXME: This requires a port to define both FIX and FTRUNC pattern 4464169689Skan for this to work. We need to rework the fix* and ftrunc* patterns 4465169689Skan and documentation. */ 4466132718Skan tab = unsignedp ? ufix_optab : sfix_optab; 4467132718Skan icode = tab->handlers[fixmode][fltmode].insn_code; 4468132718Skan if (icode != CODE_FOR_nothing 4469132718Skan && ftrunc_optab->handlers[fltmode].insn_code != CODE_FOR_nothing) 4470132718Skan { 447118334Speter *truncp_ptr = 1; 4472132718Skan return icode; 447318334Speter } 4474132718Skan 4475132718Skan *truncp_ptr = 0; 447618334Speter return CODE_FOR_nothing; 447718334Speter} 447818334Speter 447918334Speterstatic enum insn_code 4480132718Skancan_float_p (enum machine_mode fltmode, enum machine_mode fixmode, 4481132718Skan int unsignedp) 448218334Speter{ 4483132718Skan convert_optab tab; 4484132718Skan 4485132718Skan tab = unsignedp ? ufloat_optab : sfloat_optab; 4486132718Skan return tab->handlers[fltmode][fixmode].insn_code; 448718334Speter} 448818334Speter 448918334Speter/* Generate code to convert FROM to floating point 449018334Speter and store in TO. FROM must be fixed point and not VOIDmode. 449118334Speter UNSIGNEDP nonzero means regard FROM as unsigned. 449218334Speter Normally this is done by correcting the final value 449318334Speter if it is negative. */ 449418334Speter 449518334Spetervoid 4496132718Skanexpand_float (rtx to, rtx from, int unsignedp) 449718334Speter{ 449818334Speter enum insn_code icode; 449990075Sobrien rtx target = to; 450018334Speter enum machine_mode fmode, imode; 4501169689Skan bool can_do_signed = false; 450218334Speter 450318334Speter /* Crash now, because we won't be able to decide which mode to use. */ 4504169689Skan gcc_assert (GET_MODE (from) != VOIDmode); 450518334Speter 450618334Speter /* Look for an insn to do the conversion. Do it in the specified 450718334Speter modes if possible; otherwise convert either input, output or both to 450818334Speter wider mode. If the integer mode is wider than the mode of FROM, 450918334Speter we can do the conversion signed even if the input is unsigned. */ 451018334Speter 4511117395Skan for (fmode = GET_MODE (to); fmode != VOIDmode; 4512117395Skan fmode = GET_MODE_WIDER_MODE (fmode)) 4513117395Skan for (imode = GET_MODE (from); imode != VOIDmode; 4514117395Skan imode = GET_MODE_WIDER_MODE (imode)) 451518334Speter { 451618334Speter int doing_unsigned = unsignedp; 451718334Speter 451890075Sobrien if (fmode != GET_MODE (to) 451990075Sobrien && significand_size (fmode) < GET_MODE_BITSIZE (GET_MODE (from))) 452090075Sobrien continue; 452190075Sobrien 452218334Speter icode = can_float_p (fmode, imode, unsignedp); 4523169689Skan if (icode == CODE_FOR_nothing && unsignedp) 4524169689Skan { 4525169689Skan enum insn_code scode = can_float_p (fmode, imode, 0); 4526169689Skan if (scode != CODE_FOR_nothing) 4527169689Skan can_do_signed = true; 4528169689Skan if (imode != GET_MODE (from)) 4529169689Skan icode = scode, doing_unsigned = 0; 4530169689Skan } 453118334Speter 453218334Speter if (icode != CODE_FOR_nothing) 453318334Speter { 453418334Speter if (imode != GET_MODE (from)) 453518334Speter from = convert_to_mode (imode, from, unsignedp); 453618334Speter 453718334Speter if (fmode != GET_MODE (to)) 453818334Speter target = gen_reg_rtx (fmode); 453918334Speter 454018334Speter emit_unop_insn (icode, target, from, 454118334Speter doing_unsigned ? UNSIGNED_FLOAT : FLOAT); 454218334Speter 454318334Speter if (target != to) 454418334Speter convert_move (to, target, 0); 454518334Speter return; 454618334Speter } 4547117395Skan } 454818334Speter 4549169689Skan /* Unsigned integer, and no way to convert directly. For binary 4550169689Skan floating point modes, convert as signed, then conditionally adjust 4551169689Skan the result. */ 4552169689Skan if (unsignedp && can_do_signed && !DECIMAL_FLOAT_MODE_P (GET_MODE (to))) 455318334Speter { 455418334Speter rtx label = gen_label_rtx (); 455518334Speter rtx temp; 455618334Speter REAL_VALUE_TYPE offset; 455718334Speter 455818334Speter /* Look for a usable floating mode FMODE wider than the source and at 455918334Speter least as wide as the target. Using FMODE will avoid rounding woes 456018334Speter with unsigned values greater than the signed maximum value. */ 456118334Speter 456218334Speter for (fmode = GET_MODE (to); fmode != VOIDmode; 456318334Speter fmode = GET_MODE_WIDER_MODE (fmode)) 456418334Speter if (GET_MODE_BITSIZE (GET_MODE (from)) < GET_MODE_BITSIZE (fmode) 456518334Speter && can_float_p (fmode, GET_MODE (from), 0) != CODE_FOR_nothing) 456618334Speter break; 456718334Speter 456818334Speter if (fmode == VOIDmode) 456918334Speter { 457018334Speter /* There is no such mode. Pretend the target is wide enough. */ 457118334Speter fmode = GET_MODE (to); 457218334Speter 457350397Sobrien /* Avoid double-rounding when TO is narrower than FROM. */ 457418334Speter if ((significand_size (fmode) + 1) 457518334Speter < GET_MODE_BITSIZE (GET_MODE (from))) 457618334Speter { 457718334Speter rtx temp1; 457818334Speter rtx neglabel = gen_label_rtx (); 457918334Speter 4580132718Skan /* Don't use TARGET if it isn't a register, is a hard register, 458118334Speter or is the wrong mode. */ 4582169689Skan if (!REG_P (target) 458318334Speter || REGNO (target) < FIRST_PSEUDO_REGISTER 458418334Speter || GET_MODE (target) != fmode) 458518334Speter target = gen_reg_rtx (fmode); 458618334Speter 458718334Speter imode = GET_MODE (from); 458818334Speter do_pending_stack_adjust (); 458918334Speter 459018334Speter /* Test whether the sign bit is set. */ 459190075Sobrien emit_cmp_and_jump_insns (from, const0_rtx, LT, NULL_RTX, imode, 459290075Sobrien 0, neglabel); 459318334Speter 459418334Speter /* The sign bit is not set. Convert as signed. */ 459518334Speter expand_float (target, from, 0); 459618334Speter emit_jump_insn (gen_jump (label)); 459718334Speter emit_barrier (); 459818334Speter 459918334Speter /* The sign bit is set. 460018334Speter Convert to a usable (positive signed) value by shifting right 460118334Speter one bit, while remembering if a nonzero bit was shifted 460218334Speter out; i.e., compute (from & 1) | (from >> 1). */ 460318334Speter 460418334Speter emit_label (neglabel); 460518334Speter temp = expand_binop (imode, and_optab, from, const1_rtx, 460618334Speter NULL_RTX, 1, OPTAB_LIB_WIDEN); 460718334Speter temp1 = expand_shift (RSHIFT_EXPR, imode, from, integer_one_node, 460818334Speter NULL_RTX, 1); 4609132718Skan temp = expand_binop (imode, ior_optab, temp, temp1, temp, 1, 461018334Speter OPTAB_LIB_WIDEN); 461118334Speter expand_float (target, temp, 0); 461218334Speter 461318334Speter /* Multiply by 2 to undo the shift above. */ 461418334Speter temp = expand_binop (fmode, add_optab, target, target, 4615117395Skan target, 0, OPTAB_LIB_WIDEN); 461618334Speter if (temp != target) 461718334Speter emit_move_insn (target, temp); 461818334Speter 461918334Speter do_pending_stack_adjust (); 462018334Speter emit_label (label); 462118334Speter goto done; 462218334Speter } 462318334Speter } 462418334Speter 462518334Speter /* If we are about to do some arithmetic to correct for an 462618334Speter unsigned operand, do it in a pseudo-register. */ 462718334Speter 462818334Speter if (GET_MODE (to) != fmode 4629169689Skan || !REG_P (to) || REGNO (to) < FIRST_PSEUDO_REGISTER) 463018334Speter target = gen_reg_rtx (fmode); 463118334Speter 463218334Speter /* Convert as signed integer to floating. */ 463318334Speter expand_float (target, from, 0); 463418334Speter 463518334Speter /* If FROM is negative (and therefore TO is negative), 463618334Speter correct its value by 2**bitwidth. */ 463718334Speter 463818334Speter do_pending_stack_adjust (); 463952284Sobrien emit_cmp_and_jump_insns (from, const0_rtx, GE, NULL_RTX, GET_MODE (from), 464090075Sobrien 0, label); 464118334Speter 4642132718Skan 4643117395Skan real_2expN (&offset, GET_MODE_BITSIZE (GET_MODE (from))); 464418334Speter temp = expand_binop (fmode, add_optab, target, 464518334Speter CONST_DOUBLE_FROM_REAL_VALUE (offset, fmode), 464618334Speter target, 0, OPTAB_LIB_WIDEN); 464718334Speter if (temp != target) 464818334Speter emit_move_insn (target, temp); 464918334Speter 465018334Speter do_pending_stack_adjust (); 465118334Speter emit_label (label); 465218334Speter goto done; 465318334Speter } 465418334Speter 4655132718Skan /* No hardware instruction available; call a library routine. */ 465618334Speter { 4657132718Skan rtx libfunc; 465818334Speter rtx insns; 465918334Speter rtx value; 4660132718Skan convert_optab tab = unsignedp ? ufloat_optab : sfloat_optab; 466118334Speter 466218334Speter if (GET_MODE_SIZE (GET_MODE (from)) < GET_MODE_SIZE (SImode)) 466318334Speter from = convert_to_mode (SImode, from, unsignedp); 466418334Speter 4665132718Skan libfunc = tab->handlers[GET_MODE (to)][GET_MODE (from)].libfunc; 4666169689Skan gcc_assert (libfunc); 466718334Speter 466818334Speter start_sequence (); 466918334Speter 4670132718Skan value = emit_library_call_value (libfunc, NULL_RTX, LCT_CONST, 467190075Sobrien GET_MODE (to), 1, from, 467290075Sobrien GET_MODE (from)); 467318334Speter insns = get_insns (); 467418334Speter end_sequence (); 467518334Speter 467618334Speter emit_libcall_block (insns, target, value, 467750397Sobrien gen_rtx_FLOAT (GET_MODE (to), from)); 467818334Speter } 467918334Speter 468018334Speter done: 468118334Speter 468218334Speter /* Copy result to requested destination 468318334Speter if we have been computing in a temp location. */ 468418334Speter 468518334Speter if (target != to) 468618334Speter { 468718334Speter if (GET_MODE (target) == GET_MODE (to)) 468818334Speter emit_move_insn (to, target); 468918334Speter else 469018334Speter convert_move (to, target, 0); 469118334Speter } 469218334Speter} 469318334Speter 4694169689Skan/* Generate code to convert FROM to fixed point and store in TO. FROM 4695169689Skan must be floating point. */ 469618334Speter 469718334Spetervoid 4698132718Skanexpand_fix (rtx to, rtx from, int unsignedp) 469918334Speter{ 470018334Speter enum insn_code icode; 470190075Sobrien rtx target = to; 470218334Speter enum machine_mode fmode, imode; 470318334Speter int must_trunc = 0; 470418334Speter 470518334Speter /* We first try to find a pair of modes, one real and one integer, at 470618334Speter least as wide as FROM and TO, respectively, in which we can open-code 470718334Speter this conversion. If the integer mode is wider than the mode of TO, 470818334Speter we can do the conversion either signed or unsigned. */ 470918334Speter 471090075Sobrien for (fmode = GET_MODE (from); fmode != VOIDmode; 471190075Sobrien fmode = GET_MODE_WIDER_MODE (fmode)) 471290075Sobrien for (imode = GET_MODE (to); imode != VOIDmode; 471390075Sobrien imode = GET_MODE_WIDER_MODE (imode)) 471418334Speter { 471518334Speter int doing_unsigned = unsignedp; 471618334Speter 471718334Speter icode = can_fix_p (imode, fmode, unsignedp, &must_trunc); 471818334Speter if (icode == CODE_FOR_nothing && imode != GET_MODE (to) && unsignedp) 471918334Speter icode = can_fix_p (imode, fmode, 0, &must_trunc), doing_unsigned = 0; 472018334Speter 472118334Speter if (icode != CODE_FOR_nothing) 472218334Speter { 472318334Speter if (fmode != GET_MODE (from)) 472418334Speter from = convert_to_mode (fmode, from, 0); 472518334Speter 472618334Speter if (must_trunc) 4727169689Skan { 4728169689Skan rtx temp = gen_reg_rtx (GET_MODE (from)); 4729169689Skan from = expand_unop (GET_MODE (from), ftrunc_optab, from, 4730169689Skan temp, 0); 4731169689Skan } 473218334Speter 473318334Speter if (imode != GET_MODE (to)) 473418334Speter target = gen_reg_rtx (imode); 473518334Speter 473618334Speter emit_unop_insn (icode, target, from, 473718334Speter doing_unsigned ? UNSIGNED_FIX : FIX); 473818334Speter if (target != to) 473918334Speter convert_move (to, target, unsignedp); 474018334Speter return; 474118334Speter } 474218334Speter } 474318334Speter 474418334Speter /* For an unsigned conversion, there is one more way to do it. 474518334Speter If we have a signed conversion, we generate code that compares 474618334Speter the real value to the largest representable positive number. If if 474718334Speter is smaller, the conversion is done normally. Otherwise, subtract 474818334Speter one plus the highest signed number, convert, and add it back. 474918334Speter 475018334Speter We only need to check all real modes, since we know we didn't find 4751132718Skan anything with a wider integer mode. 475218334Speter 4753132718Skan This code used to extend FP value into mode wider than the destination. 4754132718Skan This is not needed. Consider, for instance conversion from SFmode 4755132718Skan into DImode. 4756132718Skan 4757169689Skan The hot path through the code is dealing with inputs smaller than 2^63 4758132718Skan and doing just the conversion, so there is no bits to lose. 4759132718Skan 4760132718Skan In the other path we know the value is positive in the range 2^63..2^64-1 4761132718Skan inclusive. (as for other imput overflow happens and result is undefined) 4762132718Skan So we know that the most important bit set in mantissa corresponds to 4763132718Skan 2^63. The subtraction of 2^63 should not generate any rounding as it 4764132718Skan simply clears out that bit. The rest is trivial. */ 4765132718Skan 476618334Speter if (unsignedp && GET_MODE_BITSIZE (GET_MODE (to)) <= HOST_BITS_PER_WIDE_INT) 476718334Speter for (fmode = GET_MODE (from); fmode != VOIDmode; 476818334Speter fmode = GET_MODE_WIDER_MODE (fmode)) 4769132718Skan if (CODE_FOR_nothing != can_fix_p (GET_MODE (to), fmode, 0, 4770132718Skan &must_trunc)) 477118334Speter { 477218334Speter int bitsize; 477318334Speter REAL_VALUE_TYPE offset; 477418334Speter rtx limit, lab1, lab2, insn; 477518334Speter 477618334Speter bitsize = GET_MODE_BITSIZE (GET_MODE (to)); 4777117395Skan real_2expN (&offset, bitsize - 1); 477818334Speter limit = CONST_DOUBLE_FROM_REAL_VALUE (offset, fmode); 477918334Speter lab1 = gen_label_rtx (); 478018334Speter lab2 = gen_label_rtx (); 478118334Speter 478218334Speter if (fmode != GET_MODE (from)) 478318334Speter from = convert_to_mode (fmode, from, 0); 478418334Speter 478518334Speter /* See if we need to do the subtraction. */ 478618334Speter do_pending_stack_adjust (); 478752284Sobrien emit_cmp_and_jump_insns (from, limit, GE, NULL_RTX, GET_MODE (from), 478890075Sobrien 0, lab1); 478918334Speter 479018334Speter /* If not, do the signed "fix" and branch around fixup code. */ 479118334Speter expand_fix (to, from, 0); 479218334Speter emit_jump_insn (gen_jump (lab2)); 479318334Speter emit_barrier (); 479418334Speter 479518334Speter /* Otherwise, subtract 2**(N-1), convert to signed number, 479618334Speter then add 2**(N-1). Do the addition using XOR since this 479718334Speter will often generate better code. */ 479818334Speter emit_label (lab1); 479918334Speter target = expand_binop (GET_MODE (from), sub_optab, from, limit, 480018334Speter NULL_RTX, 0, OPTAB_LIB_WIDEN); 480118334Speter expand_fix (to, target, 0); 480218334Speter target = expand_binop (GET_MODE (to), xor_optab, to, 4803117395Skan gen_int_mode 4804117395Skan ((HOST_WIDE_INT) 1 << (bitsize - 1), 4805117395Skan GET_MODE (to)), 480618334Speter to, 1, OPTAB_LIB_WIDEN); 480718334Speter 480818334Speter if (target != to) 480918334Speter emit_move_insn (to, target); 481018334Speter 481118334Speter emit_label (lab2); 481218334Speter 481350397Sobrien if (mov_optab->handlers[(int) GET_MODE (to)].insn_code 481450397Sobrien != CODE_FOR_nothing) 481550397Sobrien { 481650397Sobrien /* Make a place for a REG_NOTE and add it. */ 481750397Sobrien insn = emit_move_insn (to, to); 481852284Sobrien set_unique_reg_note (insn, 481952284Sobrien REG_EQUAL, 482052284Sobrien gen_rtx_fmt_e (UNSIGNED_FIX, 482152284Sobrien GET_MODE (to), 482252284Sobrien copy_rtx (from))); 482350397Sobrien } 482490075Sobrien 482518334Speter return; 482618334Speter } 482718334Speter 482818334Speter /* We can't do it with an insn, so use a library call. But first ensure 482918334Speter that the mode of TO is at least as wide as SImode, since those are the 483018334Speter only library calls we know about. */ 483118334Speter 483218334Speter if (GET_MODE_SIZE (GET_MODE (to)) < GET_MODE_SIZE (SImode)) 483318334Speter { 483418334Speter target = gen_reg_rtx (SImode); 483518334Speter 483618334Speter expand_fix (target, from, unsignedp); 483718334Speter } 483818334Speter else 483918334Speter { 484018334Speter rtx insns; 484118334Speter rtx value; 4842132718Skan rtx libfunc; 4843169689Skan 4844132718Skan convert_optab tab = unsignedp ? ufix_optab : sfix_optab; 4845132718Skan libfunc = tab->handlers[GET_MODE (to)][GET_MODE (from)].libfunc; 4846169689Skan gcc_assert (libfunc); 484718334Speter 484818334Speter start_sequence (); 484918334Speter 4850132718Skan value = emit_library_call_value (libfunc, NULL_RTX, LCT_CONST, 485190075Sobrien GET_MODE (to), 1, from, 485290075Sobrien GET_MODE (from)); 485318334Speter insns = get_insns (); 485418334Speter end_sequence (); 485518334Speter 485618334Speter emit_libcall_block (insns, target, value, 485750397Sobrien gen_rtx_fmt_e (unsignedp ? UNSIGNED_FIX : FIX, 485850397Sobrien GET_MODE (to), from)); 485918334Speter } 4860132718Skan 486150397Sobrien if (target != to) 486250397Sobrien { 486350397Sobrien if (GET_MODE (to) == GET_MODE (target)) 486450397Sobrien emit_move_insn (to, target); 486550397Sobrien else 486650397Sobrien convert_move (to, target, 0); 486750397Sobrien } 486818334Speter} 486918334Speter 487090075Sobrien/* Report whether we have an instruction to perform the operation 487190075Sobrien specified by CODE on operands of mode MODE. */ 487290075Sobrienint 4873132718Skanhave_insn_for (enum rtx_code code, enum machine_mode mode) 487418334Speter{ 487590075Sobrien return (code_to_optab[(int) code] != 0 487690075Sobrien && (code_to_optab[(int) code]->handlers[(int) mode].insn_code 487790075Sobrien != CODE_FOR_nothing)); 487890075Sobrien} 487990075Sobrien 488090075Sobrien/* Create a blank optab. */ 488190075Sobrienstatic optab 4882132718Skannew_optab (void) 488390075Sobrien{ 488418334Speter int i; 4885132718Skan optab op = ggc_alloc (sizeof (struct optab)); 488618334Speter for (i = 0; i < NUM_MACHINE_MODES; i++) 488718334Speter { 488818334Speter op->handlers[i].insn_code = CODE_FOR_nothing; 488918334Speter op->handlers[i].libfunc = 0; 489018334Speter } 489118334Speter 489290075Sobrien return op; 489390075Sobrien} 489418334Speter 4895132718Skanstatic convert_optab 4896132718Skannew_convert_optab (void) 4897132718Skan{ 4898132718Skan int i, j; 4899132718Skan convert_optab op = ggc_alloc (sizeof (struct convert_optab)); 4900132718Skan for (i = 0; i < NUM_MACHINE_MODES; i++) 4901132718Skan for (j = 0; j < NUM_MACHINE_MODES; j++) 4902132718Skan { 4903132718Skan op->handlers[i][j].insn_code = CODE_FOR_nothing; 4904132718Skan op->handlers[i][j].libfunc = 0; 4905132718Skan } 4906132718Skan return op; 4907132718Skan} 4908132718Skan 490990075Sobrien/* Same, but fill in its code as CODE, and write it into the 491090075Sobrien code_to_optab table. */ 491190075Sobrienstatic inline optab 4912132718Skaninit_optab (enum rtx_code code) 491390075Sobrien{ 491490075Sobrien optab op = new_optab (); 491590075Sobrien op->code = code; 491690075Sobrien code_to_optab[(int) code] = op; 491718334Speter return op; 491818334Speter} 491918334Speter 492090075Sobrien/* Same, but fill in its code as CODE, and do _not_ write it into 492190075Sobrien the code_to_optab table. */ 492290075Sobrienstatic inline optab 4923132718Skaninit_optabv (enum rtx_code code) 492490075Sobrien{ 492590075Sobrien optab op = new_optab (); 492690075Sobrien op->code = code; 492790075Sobrien return op; 492890075Sobrien} 492990075Sobrien 4930132718Skan/* Conversion optabs never go in the code_to_optab table. */ 4931132718Skanstatic inline convert_optab 4932132718Skaninit_convert_optab (enum rtx_code code) 4933132718Skan{ 4934132718Skan convert_optab op = new_convert_optab (); 4935132718Skan op->code = code; 4936132718Skan return op; 4937132718Skan} 4938132718Skan 493918334Speter/* Initialize the libfunc fields of an entire group of entries in some 494018334Speter optab. Each entry is set equal to a string consisting of a leading 494118334Speter pair of underscores followed by a generic operation name followed by 4942132718Skan a mode name (downshifted to lowercase) followed by a single character 494318334Speter representing the number of operands for the given operation (which is 494418334Speter usually one of the characters '2', '3', or '4'). 494518334Speter 494618334Speter OPTABLE is the table in which libfunc fields are to be initialized. 494718334Speter FIRST_MODE is the first machine mode index in the given optab to 494818334Speter initialize. 494918334Speter LAST_MODE is the last machine mode index in the given optab to 495018334Speter initialize. 495118334Speter OPNAME is the generic (string) name of the operation. 495218334Speter SUFFIX is the character which specifies the number of operands for 495318334Speter the given generic operation. 495418334Speter*/ 495518334Speter 495618334Speterstatic void 4957132718Skaninit_libfuncs (optab optable, int first_mode, int last_mode, 4958132718Skan const char *opname, int suffix) 495918334Speter{ 496090075Sobrien int mode; 496190075Sobrien unsigned opname_len = strlen (opname); 496218334Speter 496318334Speter for (mode = first_mode; (int) mode <= (int) last_mode; 496418334Speter mode = (enum machine_mode) ((int) mode + 1)) 496518334Speter { 4966117395Skan const char *mname = GET_MODE_NAME (mode); 496790075Sobrien unsigned mname_len = strlen (mname); 496890075Sobrien char *libfunc_name = alloca (2 + opname_len + mname_len + 1 + 1); 496990075Sobrien char *p; 497090075Sobrien const char *q; 497118334Speter 497218334Speter p = libfunc_name; 497318334Speter *p++ = '_'; 497418334Speter *p++ = '_'; 497518334Speter for (q = opname; *q; ) 497618334Speter *p++ = *q++; 497718334Speter for (q = mname; *q; q++) 497890075Sobrien *p++ = TOLOWER (*q); 497918334Speter *p++ = suffix; 498090075Sobrien *p = '\0'; 498190075Sobrien 498218334Speter optable->handlers[(int) mode].libfunc 4983132718Skan = init_one_libfunc (ggc_alloc_string (libfunc_name, p - libfunc_name)); 498418334Speter } 498518334Speter} 498618334Speter 498718334Speter/* Initialize the libfunc fields of an entire group of entries in some 498818334Speter optab which correspond to all integer mode operations. The parameters 498918334Speter have the same meaning as similarly named ones for the `init_libfuncs' 499018334Speter routine. (See above). */ 499118334Speter 499218334Speterstatic void 4993132718Skaninit_integral_libfuncs (optab optable, const char *opname, int suffix) 499418334Speter{ 4995132718Skan int maxsize = 2*BITS_PER_WORD; 4996132718Skan if (maxsize < LONG_LONG_TYPE_SIZE) 4997132718Skan maxsize = LONG_LONG_TYPE_SIZE; 4998132718Skan init_libfuncs (optable, word_mode, 4999132718Skan mode_for_size (maxsize, MODE_INT, 0), 5000132718Skan opname, suffix); 500118334Speter} 500218334Speter 500318334Speter/* Initialize the libfunc fields of an entire group of entries in some 500418334Speter optab which correspond to all real mode operations. The parameters 500518334Speter have the same meaning as similarly named ones for the `init_libfuncs' 500618334Speter routine. (See above). */ 500718334Speter 500818334Speterstatic void 5009132718Skaninit_floating_libfuncs (optab optable, const char *opname, int suffix) 501018334Speter{ 5011132718Skan init_libfuncs (optable, MIN_MODE_FLOAT, MAX_MODE_FLOAT, opname, suffix); 5012169689Skan init_libfuncs (optable, MIN_MODE_DECIMAL_FLOAT, MAX_MODE_DECIMAL_FLOAT, 5013169689Skan opname, suffix); 501418334Speter} 501518334Speter 5016132718Skan/* Initialize the libfunc fields of an entire group of entries of an 5017132718Skan inter-mode-class conversion optab. The string formation rules are 5018132718Skan similar to the ones for init_libfuncs, above, but instead of having 5019132718Skan a mode name and an operand count these functions have two mode names 5020132718Skan and no operand count. */ 5021132718Skanstatic void 5022132718Skaninit_interclass_conv_libfuncs (convert_optab tab, const char *opname, 5023132718Skan enum mode_class from_class, 5024132718Skan enum mode_class to_class) 5025132718Skan{ 5026132718Skan enum machine_mode first_from_mode = GET_CLASS_NARROWEST_MODE (from_class); 5027132718Skan enum machine_mode first_to_mode = GET_CLASS_NARROWEST_MODE (to_class); 5028132718Skan size_t opname_len = strlen (opname); 5029132718Skan size_t max_mname_len = 0; 5030132718Skan 5031132718Skan enum machine_mode fmode, tmode; 5032132718Skan const char *fname, *tname; 5033132718Skan const char *q; 5034132718Skan char *libfunc_name, *suffix; 5035132718Skan char *p; 5036132718Skan 5037132718Skan for (fmode = first_from_mode; 5038132718Skan fmode != VOIDmode; 5039132718Skan fmode = GET_MODE_WIDER_MODE (fmode)) 5040132718Skan max_mname_len = MAX (max_mname_len, strlen (GET_MODE_NAME (fmode))); 5041132718Skan 5042132718Skan for (tmode = first_to_mode; 5043132718Skan tmode != VOIDmode; 5044132718Skan tmode = GET_MODE_WIDER_MODE (tmode)) 5045132718Skan max_mname_len = MAX (max_mname_len, strlen (GET_MODE_NAME (tmode))); 5046132718Skan 5047132718Skan libfunc_name = alloca (2 + opname_len + 2*max_mname_len + 1 + 1); 5048132718Skan libfunc_name[0] = '_'; 5049132718Skan libfunc_name[1] = '_'; 5050132718Skan memcpy (&libfunc_name[2], opname, opname_len); 5051132718Skan suffix = libfunc_name + opname_len + 2; 5052132718Skan 5053132718Skan for (fmode = first_from_mode; fmode != VOIDmode; 5054132718Skan fmode = GET_MODE_WIDER_MODE (fmode)) 5055132718Skan for (tmode = first_to_mode; tmode != VOIDmode; 5056132718Skan tmode = GET_MODE_WIDER_MODE (tmode)) 5057132718Skan { 5058132718Skan fname = GET_MODE_NAME (fmode); 5059132718Skan tname = GET_MODE_NAME (tmode); 5060132718Skan 5061132718Skan p = suffix; 5062132718Skan for (q = fname; *q; p++, q++) 5063132718Skan *p = TOLOWER (*q); 5064132718Skan for (q = tname; *q; p++, q++) 5065132718Skan *p = TOLOWER (*q); 5066132718Skan 5067132718Skan *p = '\0'; 5068132718Skan 5069132718Skan tab->handlers[tmode][fmode].libfunc 5070132718Skan = init_one_libfunc (ggc_alloc_string (libfunc_name, 5071132718Skan p - libfunc_name)); 5072132718Skan } 5073132718Skan} 5074132718Skan 5075132718Skan/* Initialize the libfunc fields of an entire group of entries of an 5076132718Skan intra-mode-class conversion optab. The string formation rules are 5077132718Skan similar to the ones for init_libfunc, above. WIDENING says whether 5078132718Skan the optab goes from narrow to wide modes or vice versa. These functions 5079132718Skan have two mode names _and_ an operand count. */ 5080132718Skanstatic void 5081132718Skaninit_intraclass_conv_libfuncs (convert_optab tab, const char *opname, 5082132718Skan enum mode_class class, bool widening) 5083132718Skan{ 5084132718Skan enum machine_mode first_mode = GET_CLASS_NARROWEST_MODE (class); 5085132718Skan size_t opname_len = strlen (opname); 5086132718Skan size_t max_mname_len = 0; 5087132718Skan 5088132718Skan enum machine_mode nmode, wmode; 5089132718Skan const char *nname, *wname; 5090132718Skan const char *q; 5091132718Skan char *libfunc_name, *suffix; 5092132718Skan char *p; 5093132718Skan 5094132718Skan for (nmode = first_mode; nmode != VOIDmode; 5095132718Skan nmode = GET_MODE_WIDER_MODE (nmode)) 5096132718Skan max_mname_len = MAX (max_mname_len, strlen (GET_MODE_NAME (nmode))); 5097132718Skan 5098132718Skan libfunc_name = alloca (2 + opname_len + 2*max_mname_len + 1 + 1); 5099132718Skan libfunc_name[0] = '_'; 5100132718Skan libfunc_name[1] = '_'; 5101132718Skan memcpy (&libfunc_name[2], opname, opname_len); 5102132718Skan suffix = libfunc_name + opname_len + 2; 5103132718Skan 5104132718Skan for (nmode = first_mode; nmode != VOIDmode; 5105132718Skan nmode = GET_MODE_WIDER_MODE (nmode)) 5106132718Skan for (wmode = GET_MODE_WIDER_MODE (nmode); wmode != VOIDmode; 5107132718Skan wmode = GET_MODE_WIDER_MODE (wmode)) 5108132718Skan { 5109132718Skan nname = GET_MODE_NAME (nmode); 5110132718Skan wname = GET_MODE_NAME (wmode); 5111132718Skan 5112132718Skan p = suffix; 5113132718Skan for (q = widening ? nname : wname; *q; p++, q++) 5114132718Skan *p = TOLOWER (*q); 5115132718Skan for (q = widening ? wname : nname; *q; p++, q++) 5116132718Skan *p = TOLOWER (*q); 5117132718Skan 5118132718Skan *p++ = '2'; 5119132718Skan *p = '\0'; 5120132718Skan 5121132718Skan tab->handlers[widening ? wmode : nmode] 5122132718Skan [widening ? nmode : wmode].libfunc 5123132718Skan = init_one_libfunc (ggc_alloc_string (libfunc_name, 5124132718Skan p - libfunc_name)); 5125132718Skan } 5126132718Skan} 5127132718Skan 5128132718Skan 512990075Sobrienrtx 5130132718Skaninit_one_libfunc (const char *name) 513190075Sobrien{ 5132132718Skan rtx symbol; 5133132718Skan 5134117395Skan /* Create a FUNCTION_DECL that can be passed to 5135117395Skan targetm.encode_section_info. */ 513690075Sobrien /* ??? We don't have any type information except for this is 513790075Sobrien a function. Pretend this is "int foo()". */ 513890075Sobrien tree decl = build_decl (FUNCTION_DECL, get_identifier (name), 513990075Sobrien build_function_type (integer_type_node, NULL_TREE)); 514090075Sobrien DECL_ARTIFICIAL (decl) = 1; 514190075Sobrien DECL_EXTERNAL (decl) = 1; 514290075Sobrien TREE_PUBLIC (decl) = 1; 514318334Speter 5144132718Skan symbol = XEXP (DECL_RTL (decl), 0); 5145132718Skan 5146132718Skan /* Zap the nonsensical SYMBOL_REF_DECL for this. What we're left with 5147132718Skan are the flags assigned by targetm.encode_section_info. */ 5148169689Skan SET_SYMBOL_REF_DECL (symbol, 0); 5149132718Skan 5150132718Skan return symbol; 515190075Sobrien} 515290075Sobrien 5153132718Skan/* Call this to reset the function entry for one optab (OPTABLE) in mode 5154132718Skan MODE to NAME, which should be either 0 or a string constant. */ 5155132718Skanvoid 5156132718Skanset_optab_libfunc (optab optable, enum machine_mode mode, const char *name) 5157132718Skan{ 5158132718Skan if (name) 5159132718Skan optable->handlers[mode].libfunc = init_one_libfunc (name); 5160132718Skan else 5161132718Skan optable->handlers[mode].libfunc = 0; 5162132718Skan} 5163132718Skan 5164132718Skan/* Call this to reset the function entry for one conversion optab 5165132718Skan (OPTABLE) from mode FMODE to mode TMODE to NAME, which should be 5166132718Skan either 0 or a string constant. */ 5167132718Skanvoid 5168132718Skanset_conv_libfunc (convert_optab optable, enum machine_mode tmode, 5169132718Skan enum machine_mode fmode, const char *name) 5170132718Skan{ 5171132718Skan if (name) 5172132718Skan optable->handlers[tmode][fmode].libfunc = init_one_libfunc (name); 5173132718Skan else 5174132718Skan optable->handlers[tmode][fmode].libfunc = 0; 5175132718Skan} 5176132718Skan 517718334Speter/* Call this once to initialize the contents of the optabs 517818334Speter appropriately for the current target machine. */ 517918334Speter 518018334Spetervoid 5181132718Skaninit_optabs (void) 518218334Speter{ 5183132718Skan unsigned int i; 518450397Sobrien 518518334Speter /* Start by initializing all tables to contain CODE_FOR_nothing. */ 518618334Speter 518718334Speter for (i = 0; i < NUM_RTX_CODE; i++) 518818334Speter setcc_gen_code[i] = CODE_FOR_nothing; 518918334Speter 519018334Speter#ifdef HAVE_conditional_move 519118334Speter for (i = 0; i < NUM_MACHINE_MODES; i++) 519218334Speter movcc_gen_code[i] = CODE_FOR_nothing; 519318334Speter#endif 519418334Speter 5195169689Skan for (i = 0; i < NUM_MACHINE_MODES; i++) 5196169689Skan { 5197169689Skan vcond_gen_code[i] = CODE_FOR_nothing; 5198169689Skan vcondu_gen_code[i] = CODE_FOR_nothing; 5199169689Skan } 5200169689Skan 520118334Speter add_optab = init_optab (PLUS); 520290075Sobrien addv_optab = init_optabv (PLUS); 520318334Speter sub_optab = init_optab (MINUS); 520490075Sobrien subv_optab = init_optabv (MINUS); 520518334Speter smul_optab = init_optab (MULT); 520690075Sobrien smulv_optab = init_optabv (MULT); 520718334Speter smul_highpart_optab = init_optab (UNKNOWN); 520818334Speter umul_highpart_optab = init_optab (UNKNOWN); 520918334Speter smul_widen_optab = init_optab (UNKNOWN); 521018334Speter umul_widen_optab = init_optab (UNKNOWN); 5211169689Skan usmul_widen_optab = init_optab (UNKNOWN); 521218334Speter sdiv_optab = init_optab (DIV); 521390075Sobrien sdivv_optab = init_optabv (DIV); 521418334Speter sdivmod_optab = init_optab (UNKNOWN); 521518334Speter udiv_optab = init_optab (UDIV); 521618334Speter udivmod_optab = init_optab (UNKNOWN); 521718334Speter smod_optab = init_optab (MOD); 521818334Speter umod_optab = init_optab (UMOD); 5219169689Skan fmod_optab = init_optab (UNKNOWN); 5220169689Skan drem_optab = init_optab (UNKNOWN); 522118334Speter ftrunc_optab = init_optab (UNKNOWN); 522218334Speter and_optab = init_optab (AND); 522318334Speter ior_optab = init_optab (IOR); 522418334Speter xor_optab = init_optab (XOR); 522518334Speter ashl_optab = init_optab (ASHIFT); 522618334Speter ashr_optab = init_optab (ASHIFTRT); 522718334Speter lshr_optab = init_optab (LSHIFTRT); 522818334Speter rotl_optab = init_optab (ROTATE); 522918334Speter rotr_optab = init_optab (ROTATERT); 523018334Speter smin_optab = init_optab (SMIN); 523118334Speter smax_optab = init_optab (SMAX); 523218334Speter umin_optab = init_optab (UMIN); 523318334Speter umax_optab = init_optab (UMAX); 5234132718Skan pow_optab = init_optab (UNKNOWN); 5235132718Skan atan2_optab = init_optab (UNKNOWN); 523690075Sobrien 523790075Sobrien /* These three have codes assigned exclusively for the sake of 523890075Sobrien have_insn_for. */ 523990075Sobrien mov_optab = init_optab (SET); 524090075Sobrien movstrict_optab = init_optab (STRICT_LOW_PART); 524190075Sobrien cmp_optab = init_optab (COMPARE); 524290075Sobrien 524318334Speter ucmp_optab = init_optab (UNKNOWN); 524418334Speter tst_optab = init_optab (UNKNOWN); 5245132718Skan 5246132718Skan eq_optab = init_optab (EQ); 5247132718Skan ne_optab = init_optab (NE); 5248132718Skan gt_optab = init_optab (GT); 5249132718Skan ge_optab = init_optab (GE); 5250132718Skan lt_optab = init_optab (LT); 5251132718Skan le_optab = init_optab (LE); 5252132718Skan unord_optab = init_optab (UNORDERED); 5253132718Skan 525418334Speter neg_optab = init_optab (NEG); 525590075Sobrien negv_optab = init_optabv (NEG); 525618334Speter abs_optab = init_optab (ABS); 525790075Sobrien absv_optab = init_optabv (ABS); 5258132718Skan addcc_optab = init_optab (UNKNOWN); 525918334Speter one_cmpl_optab = init_optab (NOT); 5260259563Spfg bswap_optab = init_optab (BSWAP); 526118334Speter ffs_optab = init_optab (FFS); 5262132718Skan clz_optab = init_optab (CLZ); 5263132718Skan ctz_optab = init_optab (CTZ); 5264132718Skan popcount_optab = init_optab (POPCOUNT); 5265132718Skan parity_optab = init_optab (PARITY); 526618334Speter sqrt_optab = init_optab (SQRT); 5267132718Skan floor_optab = init_optab (UNKNOWN); 5268169689Skan lfloor_optab = init_optab (UNKNOWN); 5269132718Skan ceil_optab = init_optab (UNKNOWN); 5270169689Skan lceil_optab = init_optab (UNKNOWN); 5271132718Skan round_optab = init_optab (UNKNOWN); 5272132718Skan btrunc_optab = init_optab (UNKNOWN); 5273132718Skan nearbyint_optab = init_optab (UNKNOWN); 5274169689Skan rint_optab = init_optab (UNKNOWN); 5275169689Skan lrint_optab = init_optab (UNKNOWN); 5276169689Skan sincos_optab = init_optab (UNKNOWN); 527718334Speter sin_optab = init_optab (UNKNOWN); 5278169689Skan asin_optab = init_optab (UNKNOWN); 527918334Speter cos_optab = init_optab (UNKNOWN); 5280169689Skan acos_optab = init_optab (UNKNOWN); 5281117395Skan exp_optab = init_optab (UNKNOWN); 5282169689Skan exp10_optab = init_optab (UNKNOWN); 5283169689Skan exp2_optab = init_optab (UNKNOWN); 5284169689Skan expm1_optab = init_optab (UNKNOWN); 5285169689Skan ldexp_optab = init_optab (UNKNOWN); 5286169689Skan logb_optab = init_optab (UNKNOWN); 5287169689Skan ilogb_optab = init_optab (UNKNOWN); 5288117395Skan log_optab = init_optab (UNKNOWN); 5289169689Skan log10_optab = init_optab (UNKNOWN); 5290169689Skan log2_optab = init_optab (UNKNOWN); 5291169689Skan log1p_optab = init_optab (UNKNOWN); 5292132718Skan tan_optab = init_optab (UNKNOWN); 5293132718Skan atan_optab = init_optab (UNKNOWN); 5294169689Skan copysign_optab = init_optab (UNKNOWN); 5295169689Skan 529618334Speter strlen_optab = init_optab (UNKNOWN); 529790075Sobrien cbranch_optab = init_optab (UNKNOWN); 529890075Sobrien cmov_optab = init_optab (UNKNOWN); 529990075Sobrien cstore_optab = init_optab (UNKNOWN); 530090075Sobrien push_optab = init_optab (UNKNOWN); 530118334Speter 5302169689Skan reduc_smax_optab = init_optab (UNKNOWN); 5303169689Skan reduc_umax_optab = init_optab (UNKNOWN); 5304169689Skan reduc_smin_optab = init_optab (UNKNOWN); 5305169689Skan reduc_umin_optab = init_optab (UNKNOWN); 5306169689Skan reduc_splus_optab = init_optab (UNKNOWN); 5307169689Skan reduc_uplus_optab = init_optab (UNKNOWN); 5308169689Skan 5309169689Skan ssum_widen_optab = init_optab (UNKNOWN); 5310169689Skan usum_widen_optab = init_optab (UNKNOWN); 5311169689Skan sdot_prod_optab = init_optab (UNKNOWN); 5312169689Skan udot_prod_optab = init_optab (UNKNOWN); 5313169689Skan 5314132718Skan vec_extract_optab = init_optab (UNKNOWN); 5315132718Skan vec_set_optab = init_optab (UNKNOWN); 5316132718Skan vec_init_optab = init_optab (UNKNOWN); 5317169689Skan vec_shl_optab = init_optab (UNKNOWN); 5318169689Skan vec_shr_optab = init_optab (UNKNOWN); 5319169689Skan vec_realign_load_optab = init_optab (UNKNOWN); 5320169689Skan movmisalign_optab = init_optab (UNKNOWN); 5321169689Skan 5322169689Skan powi_optab = init_optab (UNKNOWN); 5323169689Skan 5324132718Skan /* Conversions. */ 5325132718Skan sext_optab = init_convert_optab (SIGN_EXTEND); 5326132718Skan zext_optab = init_convert_optab (ZERO_EXTEND); 5327132718Skan trunc_optab = init_convert_optab (TRUNCATE); 5328132718Skan sfix_optab = init_convert_optab (FIX); 5329132718Skan ufix_optab = init_convert_optab (UNSIGNED_FIX); 5330132718Skan sfixtrunc_optab = init_convert_optab (UNKNOWN); 5331132718Skan ufixtrunc_optab = init_convert_optab (UNKNOWN); 5332132718Skan sfloat_optab = init_convert_optab (FLOAT); 5333132718Skan ufloat_optab = init_convert_optab (UNSIGNED_FLOAT); 5334132718Skan 533518334Speter for (i = 0; i < NUM_MACHINE_MODES; i++) 533618334Speter { 5337169689Skan movmem_optab[i] = CODE_FOR_nothing; 5338132718Skan cmpstr_optab[i] = CODE_FOR_nothing; 5339169689Skan cmpstrn_optab[i] = CODE_FOR_nothing; 5340132718Skan cmpmem_optab[i] = CODE_FOR_nothing; 5341169689Skan setmem_optab[i] = CODE_FOR_nothing; 534218334Speter 5343169689Skan sync_add_optab[i] = CODE_FOR_nothing; 5344169689Skan sync_sub_optab[i] = CODE_FOR_nothing; 5345169689Skan sync_ior_optab[i] = CODE_FOR_nothing; 5346169689Skan sync_and_optab[i] = CODE_FOR_nothing; 5347169689Skan sync_xor_optab[i] = CODE_FOR_nothing; 5348169689Skan sync_nand_optab[i] = CODE_FOR_nothing; 5349169689Skan sync_old_add_optab[i] = CODE_FOR_nothing; 5350169689Skan sync_old_sub_optab[i] = CODE_FOR_nothing; 5351169689Skan sync_old_ior_optab[i] = CODE_FOR_nothing; 5352169689Skan sync_old_and_optab[i] = CODE_FOR_nothing; 5353169689Skan sync_old_xor_optab[i] = CODE_FOR_nothing; 5354169689Skan sync_old_nand_optab[i] = CODE_FOR_nothing; 5355169689Skan sync_new_add_optab[i] = CODE_FOR_nothing; 5356169689Skan sync_new_sub_optab[i] = CODE_FOR_nothing; 5357169689Skan sync_new_ior_optab[i] = CODE_FOR_nothing; 5358169689Skan sync_new_and_optab[i] = CODE_FOR_nothing; 5359169689Skan sync_new_xor_optab[i] = CODE_FOR_nothing; 5360169689Skan sync_new_nand_optab[i] = CODE_FOR_nothing; 5361169689Skan sync_compare_and_swap[i] = CODE_FOR_nothing; 5362169689Skan sync_compare_and_swap_cc[i] = CODE_FOR_nothing; 5363169689Skan sync_lock_test_and_set[i] = CODE_FOR_nothing; 5364169689Skan sync_lock_release[i] = CODE_FOR_nothing; 5365169689Skan 536618334Speter reload_in_optab[i] = reload_out_optab[i] = CODE_FOR_nothing; 536718334Speter } 536818334Speter 536918334Speter /* Fill in the optabs with the insns we support. */ 537018334Speter init_all_optabs (); 537118334Speter 537218334Speter /* Initialize the optabs with the names of the library functions. */ 537318334Speter init_integral_libfuncs (add_optab, "add", '3'); 537418334Speter init_floating_libfuncs (add_optab, "add", '3'); 537590075Sobrien init_integral_libfuncs (addv_optab, "addv", '3'); 537690075Sobrien init_floating_libfuncs (addv_optab, "add", '3'); 537718334Speter init_integral_libfuncs (sub_optab, "sub", '3'); 537818334Speter init_floating_libfuncs (sub_optab, "sub", '3'); 537990075Sobrien init_integral_libfuncs (subv_optab, "subv", '3'); 538090075Sobrien init_floating_libfuncs (subv_optab, "sub", '3'); 538118334Speter init_integral_libfuncs (smul_optab, "mul", '3'); 538218334Speter init_floating_libfuncs (smul_optab, "mul", '3'); 538390075Sobrien init_integral_libfuncs (smulv_optab, "mulv", '3'); 538490075Sobrien init_floating_libfuncs (smulv_optab, "mul", '3'); 538518334Speter init_integral_libfuncs (sdiv_optab, "div", '3'); 538690075Sobrien init_floating_libfuncs (sdiv_optab, "div", '3'); 538790075Sobrien init_integral_libfuncs (sdivv_optab, "divv", '3'); 538818334Speter init_integral_libfuncs (udiv_optab, "udiv", '3'); 538918334Speter init_integral_libfuncs (sdivmod_optab, "divmod", '4'); 539018334Speter init_integral_libfuncs (udivmod_optab, "udivmod", '4'); 539118334Speter init_integral_libfuncs (smod_optab, "mod", '3'); 539218334Speter init_integral_libfuncs (umod_optab, "umod", '3'); 539318334Speter init_floating_libfuncs (ftrunc_optab, "ftrunc", '2'); 539418334Speter init_integral_libfuncs (and_optab, "and", '3'); 539518334Speter init_integral_libfuncs (ior_optab, "ior", '3'); 539618334Speter init_integral_libfuncs (xor_optab, "xor", '3'); 539718334Speter init_integral_libfuncs (ashl_optab, "ashl", '3'); 539818334Speter init_integral_libfuncs (ashr_optab, "ashr", '3'); 539918334Speter init_integral_libfuncs (lshr_optab, "lshr", '3'); 540018334Speter init_integral_libfuncs (smin_optab, "min", '3'); 540118334Speter init_floating_libfuncs (smin_optab, "min", '3'); 540218334Speter init_integral_libfuncs (smax_optab, "max", '3'); 540318334Speter init_floating_libfuncs (smax_optab, "max", '3'); 540418334Speter init_integral_libfuncs (umin_optab, "umin", '3'); 540518334Speter init_integral_libfuncs (umax_optab, "umax", '3'); 540618334Speter init_integral_libfuncs (neg_optab, "neg", '2'); 540718334Speter init_floating_libfuncs (neg_optab, "neg", '2'); 540890075Sobrien init_integral_libfuncs (negv_optab, "negv", '2'); 540990075Sobrien init_floating_libfuncs (negv_optab, "neg", '2'); 541018334Speter init_integral_libfuncs (one_cmpl_optab, "one_cmpl", '2'); 541118334Speter init_integral_libfuncs (ffs_optab, "ffs", '2'); 5412132718Skan init_integral_libfuncs (clz_optab, "clz", '2'); 5413132718Skan init_integral_libfuncs (ctz_optab, "ctz", '2'); 5414132718Skan init_integral_libfuncs (popcount_optab, "popcount", '2'); 5415132718Skan init_integral_libfuncs (parity_optab, "parity", '2'); 541618334Speter 5417169689Skan /* Comparison libcalls for integers MUST come in pairs, 5418169689Skan signed/unsigned. */ 541918334Speter init_integral_libfuncs (cmp_optab, "cmp", '2'); 542018334Speter init_integral_libfuncs (ucmp_optab, "ucmp", '2'); 542118334Speter init_floating_libfuncs (cmp_optab, "cmp", '2'); 542218334Speter 5423132718Skan /* EQ etc are floating point only. */ 5424132718Skan init_floating_libfuncs (eq_optab, "eq", '2'); 5425132718Skan init_floating_libfuncs (ne_optab, "ne", '2'); 5426132718Skan init_floating_libfuncs (gt_optab, "gt", '2'); 5427132718Skan init_floating_libfuncs (ge_optab, "ge", '2'); 5428132718Skan init_floating_libfuncs (lt_optab, "lt", '2'); 5429132718Skan init_floating_libfuncs (le_optab, "le", '2'); 5430132718Skan init_floating_libfuncs (unord_optab, "unord", '2'); 543118334Speter 5432169689Skan init_floating_libfuncs (powi_optab, "powi", '2'); 5433169689Skan 5434132718Skan /* Conversions. */ 5435169689Skan init_interclass_conv_libfuncs (sfloat_optab, "float", 5436169689Skan MODE_INT, MODE_FLOAT); 5437169689Skan init_interclass_conv_libfuncs (sfloat_optab, "float", 5438169689Skan MODE_INT, MODE_DECIMAL_FLOAT); 5439169689Skan init_interclass_conv_libfuncs (ufloat_optab, "floatun", 5440169689Skan MODE_INT, MODE_FLOAT); 5441169689Skan init_interclass_conv_libfuncs (ufloat_optab, "floatun", 5442169689Skan MODE_INT, MODE_DECIMAL_FLOAT); 5443169689Skan init_interclass_conv_libfuncs (sfix_optab, "fix", 5444169689Skan MODE_FLOAT, MODE_INT); 5445169689Skan init_interclass_conv_libfuncs (sfix_optab, "fix", 5446169689Skan MODE_DECIMAL_FLOAT, MODE_INT); 5447169689Skan init_interclass_conv_libfuncs (ufix_optab, "fixuns", 5448169689Skan MODE_FLOAT, MODE_INT); 5449169689Skan init_interclass_conv_libfuncs (ufix_optab, "fixuns", 5450169689Skan MODE_DECIMAL_FLOAT, MODE_INT); 5451169689Skan init_interclass_conv_libfuncs (ufloat_optab, "floatuns", 5452169689Skan MODE_INT, MODE_DECIMAL_FLOAT); 545318334Speter 5454132718Skan /* sext_optab is also used for FLOAT_EXTEND. */ 5455132718Skan init_intraclass_conv_libfuncs (sext_optab, "extend", MODE_FLOAT, true); 5456169689Skan init_intraclass_conv_libfuncs (sext_optab, "extend", MODE_DECIMAL_FLOAT, true); 5457169689Skan init_interclass_conv_libfuncs (sext_optab, "extend", MODE_FLOAT, MODE_DECIMAL_FLOAT); 5458169689Skan init_interclass_conv_libfuncs (sext_optab, "extend", MODE_DECIMAL_FLOAT, MODE_FLOAT); 5459132718Skan init_intraclass_conv_libfuncs (trunc_optab, "trunc", MODE_FLOAT, false); 5460169689Skan init_intraclass_conv_libfuncs (trunc_optab, "trunc", MODE_DECIMAL_FLOAT, false); 5461169689Skan init_interclass_conv_libfuncs (trunc_optab, "trunc", MODE_FLOAT, MODE_DECIMAL_FLOAT); 5462169689Skan init_interclass_conv_libfuncs (trunc_optab, "trunc", MODE_DECIMAL_FLOAT, MODE_FLOAT); 546318334Speter 5464259563Spfg /* Explicitly initialize the bswap libfuncs since we need them to be 5465259563Spfg valid for things other than word_mode. */ 5466259563Spfg set_optab_libfunc (bswap_optab, SImode, "__bswapsi2"); 5467259563Spfg set_optab_libfunc (bswap_optab, DImode, "__bswapdi2"); 5468259563Spfg 5469132718Skan /* Use cabs for double complex abs, since systems generally have cabs. 5470132718Skan Don't define any libcall for float complex, so that cabs will be used. */ 5471132718Skan if (complex_double_type_node) 5472132718Skan abs_optab->handlers[TYPE_MODE (complex_double_type_node)].libfunc 5473132718Skan = init_one_libfunc ("cabs"); 547418334Speter 547518334Speter /* The ffs function operates on `int'. */ 547690075Sobrien ffs_optab->handlers[(int) mode_for_size (INT_TYPE_SIZE, MODE_INT, 0)].libfunc 547790075Sobrien = init_one_libfunc ("ffs"); 547818334Speter 547996263Sobrien abort_libfunc = init_one_libfunc ("abort"); 548090075Sobrien memcpy_libfunc = init_one_libfunc ("memcpy"); 548190075Sobrien memmove_libfunc = init_one_libfunc ("memmove"); 548290075Sobrien memcmp_libfunc = init_one_libfunc ("memcmp"); 548390075Sobrien memset_libfunc = init_one_libfunc ("memset"); 5484132718Skan setbits_libfunc = init_one_libfunc ("__setbits"); 548518334Speter 548650397Sobrien#ifndef DONT_USE_BUILTIN_SETJMP 548790075Sobrien setjmp_libfunc = init_one_libfunc ("__builtin_setjmp"); 548890075Sobrien longjmp_libfunc = init_one_libfunc ("__builtin_longjmp"); 548950397Sobrien#else 549090075Sobrien setjmp_libfunc = init_one_libfunc ("setjmp"); 549190075Sobrien longjmp_libfunc = init_one_libfunc ("longjmp"); 549250397Sobrien#endif 549390075Sobrien unwind_sjlj_register_libfunc = init_one_libfunc ("_Unwind_SjLj_Register"); 549490075Sobrien unwind_sjlj_unregister_libfunc 549590075Sobrien = init_one_libfunc ("_Unwind_SjLj_Unregister"); 549618334Speter 549752284Sobrien /* For function entry/exit instrumentation. */ 549852284Sobrien profile_function_entry_libfunc 549990075Sobrien = init_one_libfunc ("__cyg_profile_func_enter"); 550052284Sobrien profile_function_exit_libfunc 550190075Sobrien = init_one_libfunc ("__cyg_profile_func_exit"); 550252284Sobrien 5503132718Skan gcov_flush_libfunc = init_one_libfunc ("__gcov_flush"); 5504132718Skan 5505117395Skan if (HAVE_conditional_trap) 5506117395Skan trap_rtx = gen_rtx_fmt_ee (EQ, VOIDmode, NULL_RTX, NULL_RTX); 550750397Sobrien 550818334Speter /* Allow the target to add more libcalls or rename some, etc. */ 5509132718Skan targetm.init_libfuncs (); 551018334Speter} 5511169689Skan 5512169689Skan#ifdef DEBUG 5513169689Skan 5514169689Skan/* Print information about the current contents of the optabs on 5515169689Skan STDERR. */ 5516169689Skan 5517169689Skanstatic void 5518169689Skandebug_optab_libfuncs (void) 5519169689Skan{ 5520169689Skan int i; 5521169689Skan int j; 5522169689Skan int k; 5523169689Skan 5524169689Skan /* Dump the arithmetic optabs. */ 5525169689Skan for (i = 0; i != (int) OTI_MAX; i++) 5526169689Skan for (j = 0; j < NUM_MACHINE_MODES; ++j) 5527169689Skan { 5528169689Skan optab o; 5529169689Skan struct optab_handlers *h; 5530169689Skan 5531169689Skan o = optab_table[i]; 5532169689Skan h = &o->handlers[j]; 5533169689Skan if (h->libfunc) 5534169689Skan { 5535169689Skan gcc_assert (GET_CODE (h->libfunc) = SYMBOL_REF); 5536169689Skan fprintf (stderr, "%s\t%s:\t%s\n", 5537169689Skan GET_RTX_NAME (o->code), 5538169689Skan GET_MODE_NAME (j), 5539169689Skan XSTR (h->libfunc, 0)); 5540169689Skan } 5541169689Skan } 5542169689Skan 5543169689Skan /* Dump the conversion optabs. */ 5544169689Skan for (i = 0; i < (int) COI_MAX; ++i) 5545169689Skan for (j = 0; j < NUM_MACHINE_MODES; ++j) 5546169689Skan for (k = 0; k < NUM_MACHINE_MODES; ++k) 5547169689Skan { 5548169689Skan convert_optab o; 5549169689Skan struct optab_handlers *h; 5550169689Skan 5551169689Skan o = &convert_optab_table[i]; 5552169689Skan h = &o->handlers[j][k]; 5553169689Skan if (h->libfunc) 5554169689Skan { 5555169689Skan gcc_assert (GET_CODE (h->libfunc) = SYMBOL_REF); 5556169689Skan fprintf (stderr, "%s\t%s\t%s:\t%s\n", 5557169689Skan GET_RTX_NAME (o->code), 5558169689Skan GET_MODE_NAME (j), 5559169689Skan GET_MODE_NAME (k), 5560169689Skan XSTR (h->libfunc, 0)); 5561169689Skan } 5562169689Skan } 5563169689Skan} 5564169689Skan 5565169689Skan#endif /* DEBUG */ 5566169689Skan 556750397Sobrien 556850397Sobrien/* Generate insns to trap with code TCODE if OP1 and OP2 satisfy condition 556950397Sobrien CODE. Return 0 on failure. */ 557050397Sobrien 557150397Sobrienrtx 5572132718Skangen_cond_trap (enum rtx_code code ATTRIBUTE_UNUSED, rtx op1, 5573132718Skan rtx op2 ATTRIBUTE_UNUSED, rtx tcode ATTRIBUTE_UNUSED) 557450397Sobrien{ 557550397Sobrien enum machine_mode mode = GET_MODE (op1); 5576117395Skan enum insn_code icode; 5577117395Skan rtx insn; 557850397Sobrien 5579117395Skan if (!HAVE_conditional_trap) 5580117395Skan return 0; 5581117395Skan 558250397Sobrien if (mode == VOIDmode) 558350397Sobrien return 0; 558450397Sobrien 5585117395Skan icode = cmp_optab->handlers[(int) mode].insn_code; 5586117395Skan if (icode == CODE_FOR_nothing) 5587117395Skan return 0; 5588117395Skan 5589117395Skan start_sequence (); 5590117395Skan op1 = prepare_operand (icode, op1, 0, mode, mode, 0); 5591119256Skan op2 = prepare_operand (icode, op2, 1, mode, mode, 0); 5592119256Skan if (!op1 || !op2) 5593119256Skan { 5594119256Skan end_sequence (); 5595119256Skan return 0; 5596119256Skan } 5597117395Skan emit_insn (GEN_FCN (icode) (op1, op2)); 5598117395Skan 5599117395Skan PUT_CODE (trap_rtx, code); 5600169689Skan gcc_assert (HAVE_conditional_trap); 5601117395Skan insn = gen_conditional_trap (trap_rtx, tcode); 5602117395Skan if (insn) 560350397Sobrien { 5604117395Skan emit_insn (insn); 5605117395Skan insn = get_insns (); 560650397Sobrien } 5607117395Skan end_sequence (); 560850397Sobrien 5609117395Skan return insn; 561050397Sobrien} 5611117395Skan 5612169689Skan/* Return rtx code for TCODE. Use UNSIGNEDP to select signed 5613169689Skan or unsigned operation code. */ 5614169689Skan 5615169689Skanstatic enum rtx_code 5616169689Skanget_rtx_code (enum tree_code tcode, bool unsignedp) 5617169689Skan{ 5618169689Skan enum rtx_code code; 5619169689Skan switch (tcode) 5620169689Skan { 5621169689Skan case EQ_EXPR: 5622169689Skan code = EQ; 5623169689Skan break; 5624169689Skan case NE_EXPR: 5625169689Skan code = NE; 5626169689Skan break; 5627169689Skan case LT_EXPR: 5628169689Skan code = unsignedp ? LTU : LT; 5629169689Skan break; 5630169689Skan case LE_EXPR: 5631169689Skan code = unsignedp ? LEU : LE; 5632169689Skan break; 5633169689Skan case GT_EXPR: 5634169689Skan code = unsignedp ? GTU : GT; 5635169689Skan break; 5636169689Skan case GE_EXPR: 5637169689Skan code = unsignedp ? GEU : GE; 5638169689Skan break; 5639169689Skan 5640169689Skan case UNORDERED_EXPR: 5641169689Skan code = UNORDERED; 5642169689Skan break; 5643169689Skan case ORDERED_EXPR: 5644169689Skan code = ORDERED; 5645169689Skan break; 5646169689Skan case UNLT_EXPR: 5647169689Skan code = UNLT; 5648169689Skan break; 5649169689Skan case UNLE_EXPR: 5650169689Skan code = UNLE; 5651169689Skan break; 5652169689Skan case UNGT_EXPR: 5653169689Skan code = UNGT; 5654169689Skan break; 5655169689Skan case UNGE_EXPR: 5656169689Skan code = UNGE; 5657169689Skan break; 5658169689Skan case UNEQ_EXPR: 5659169689Skan code = UNEQ; 5660169689Skan break; 5661169689Skan case LTGT_EXPR: 5662169689Skan code = LTGT; 5663169689Skan break; 5664169689Skan 5665169689Skan default: 5666169689Skan gcc_unreachable (); 5667169689Skan } 5668169689Skan return code; 5669169689Skan} 5670169689Skan 5671169689Skan/* Return comparison rtx for COND. Use UNSIGNEDP to select signed or 5672169689Skan unsigned operators. Do not generate compare instruction. */ 5673169689Skan 5674169689Skanstatic rtx 5675169689Skanvector_compare_rtx (tree cond, bool unsignedp, enum insn_code icode) 5676169689Skan{ 5677169689Skan enum rtx_code rcode; 5678169689Skan tree t_op0, t_op1; 5679169689Skan rtx rtx_op0, rtx_op1; 5680169689Skan 5681169689Skan /* This is unlikely. While generating VEC_COND_EXPR, auto vectorizer 5682169689Skan ensures that condition is a relational operation. */ 5683169689Skan gcc_assert (COMPARISON_CLASS_P (cond)); 5684169689Skan 5685169689Skan rcode = get_rtx_code (TREE_CODE (cond), unsignedp); 5686169689Skan t_op0 = TREE_OPERAND (cond, 0); 5687169689Skan t_op1 = TREE_OPERAND (cond, 1); 5688169689Skan 5689169689Skan /* Expand operands. */ 5690169689Skan rtx_op0 = expand_expr (t_op0, NULL_RTX, TYPE_MODE (TREE_TYPE (t_op0)), 1); 5691169689Skan rtx_op1 = expand_expr (t_op1, NULL_RTX, TYPE_MODE (TREE_TYPE (t_op1)), 1); 5692169689Skan 5693169689Skan if (!insn_data[icode].operand[4].predicate (rtx_op0, GET_MODE (rtx_op0)) 5694169689Skan && GET_MODE (rtx_op0) != VOIDmode) 5695169689Skan rtx_op0 = force_reg (GET_MODE (rtx_op0), rtx_op0); 5696169689Skan 5697169689Skan if (!insn_data[icode].operand[5].predicate (rtx_op1, GET_MODE (rtx_op1)) 5698169689Skan && GET_MODE (rtx_op1) != VOIDmode) 5699169689Skan rtx_op1 = force_reg (GET_MODE (rtx_op1), rtx_op1); 5700169689Skan 5701169689Skan return gen_rtx_fmt_ee (rcode, VOIDmode, rtx_op0, rtx_op1); 5702169689Skan} 5703169689Skan 5704169689Skan/* Return insn code for VEC_COND_EXPR EXPR. */ 5705169689Skan 5706169689Skanstatic inline enum insn_code 5707169689Skanget_vcond_icode (tree expr, enum machine_mode mode) 5708169689Skan{ 5709169689Skan enum insn_code icode = CODE_FOR_nothing; 5710169689Skan 5711169689Skan if (TYPE_UNSIGNED (TREE_TYPE (expr))) 5712169689Skan icode = vcondu_gen_code[mode]; 5713169689Skan else 5714169689Skan icode = vcond_gen_code[mode]; 5715169689Skan return icode; 5716169689Skan} 5717169689Skan 5718169689Skan/* Return TRUE iff, appropriate vector insns are available 5719169689Skan for vector cond expr expr in VMODE mode. */ 5720169689Skan 5721169689Skanbool 5722169689Skanexpand_vec_cond_expr_p (tree expr, enum machine_mode vmode) 5723169689Skan{ 5724169689Skan if (get_vcond_icode (expr, vmode) == CODE_FOR_nothing) 5725169689Skan return false; 5726169689Skan return true; 5727169689Skan} 5728169689Skan 5729169689Skan/* Generate insns for VEC_COND_EXPR. */ 5730169689Skan 5731169689Skanrtx 5732169689Skanexpand_vec_cond_expr (tree vec_cond_expr, rtx target) 5733169689Skan{ 5734169689Skan enum insn_code icode; 5735169689Skan rtx comparison, rtx_op1, rtx_op2, cc_op0, cc_op1; 5736169689Skan enum machine_mode mode = TYPE_MODE (TREE_TYPE (vec_cond_expr)); 5737169689Skan bool unsignedp = TYPE_UNSIGNED (TREE_TYPE (vec_cond_expr)); 5738169689Skan 5739169689Skan icode = get_vcond_icode (vec_cond_expr, mode); 5740169689Skan if (icode == CODE_FOR_nothing) 5741169689Skan return 0; 5742169689Skan 5743169689Skan if (!target || !insn_data[icode].operand[0].predicate (target, mode)) 5744169689Skan target = gen_reg_rtx (mode); 5745169689Skan 5746169689Skan /* Get comparison rtx. First expand both cond expr operands. */ 5747169689Skan comparison = vector_compare_rtx (TREE_OPERAND (vec_cond_expr, 0), 5748169689Skan unsignedp, icode); 5749169689Skan cc_op0 = XEXP (comparison, 0); 5750169689Skan cc_op1 = XEXP (comparison, 1); 5751169689Skan /* Expand both operands and force them in reg, if required. */ 5752169689Skan rtx_op1 = expand_expr (TREE_OPERAND (vec_cond_expr, 1), 5753169689Skan NULL_RTX, VOIDmode, EXPAND_NORMAL); 5754169689Skan if (!insn_data[icode].operand[1].predicate (rtx_op1, mode) 5755169689Skan && mode != VOIDmode) 5756169689Skan rtx_op1 = force_reg (mode, rtx_op1); 5757169689Skan 5758169689Skan rtx_op2 = expand_expr (TREE_OPERAND (vec_cond_expr, 2), 5759169689Skan NULL_RTX, VOIDmode, EXPAND_NORMAL); 5760169689Skan if (!insn_data[icode].operand[2].predicate (rtx_op2, mode) 5761169689Skan && mode != VOIDmode) 5762169689Skan rtx_op2 = force_reg (mode, rtx_op2); 5763169689Skan 5764169689Skan /* Emit instruction! */ 5765169689Skan emit_insn (GEN_FCN (icode) (target, rtx_op1, rtx_op2, 5766169689Skan comparison, cc_op0, cc_op1)); 5767169689Skan 5768169689Skan return target; 5769169689Skan} 5770169689Skan 5771169689Skan 5772169689Skan/* This is an internal subroutine of the other compare_and_swap expanders. 5773169689Skan MEM, OLD_VAL and NEW_VAL are as you'd expect for a compare-and-swap 5774169689Skan operation. TARGET is an optional place to store the value result of 5775169689Skan the operation. ICODE is the particular instruction to expand. Return 5776169689Skan the result of the operation. */ 5777169689Skan 5778169689Skanstatic rtx 5779169689Skanexpand_val_compare_and_swap_1 (rtx mem, rtx old_val, rtx new_val, 5780169689Skan rtx target, enum insn_code icode) 5781169689Skan{ 5782169689Skan enum machine_mode mode = GET_MODE (mem); 5783169689Skan rtx insn; 5784169689Skan 5785169689Skan if (!target || !insn_data[icode].operand[0].predicate (target, mode)) 5786169689Skan target = gen_reg_rtx (mode); 5787169689Skan 5788169689Skan if (GET_MODE (old_val) != VOIDmode && GET_MODE (old_val) != mode) 5789169689Skan old_val = convert_modes (mode, GET_MODE (old_val), old_val, 1); 5790169689Skan if (!insn_data[icode].operand[2].predicate (old_val, mode)) 5791169689Skan old_val = force_reg (mode, old_val); 5792169689Skan 5793169689Skan if (GET_MODE (new_val) != VOIDmode && GET_MODE (new_val) != mode) 5794169689Skan new_val = convert_modes (mode, GET_MODE (new_val), new_val, 1); 5795169689Skan if (!insn_data[icode].operand[3].predicate (new_val, mode)) 5796169689Skan new_val = force_reg (mode, new_val); 5797169689Skan 5798169689Skan insn = GEN_FCN (icode) (target, mem, old_val, new_val); 5799169689Skan if (insn == NULL_RTX) 5800169689Skan return NULL_RTX; 5801169689Skan emit_insn (insn); 5802169689Skan 5803169689Skan return target; 5804169689Skan} 5805169689Skan 5806169689Skan/* Expand a compare-and-swap operation and return its value. */ 5807169689Skan 5808169689Skanrtx 5809169689Skanexpand_val_compare_and_swap (rtx mem, rtx old_val, rtx new_val, rtx target) 5810169689Skan{ 5811169689Skan enum machine_mode mode = GET_MODE (mem); 5812169689Skan enum insn_code icode = sync_compare_and_swap[mode]; 5813169689Skan 5814169689Skan if (icode == CODE_FOR_nothing) 5815169689Skan return NULL_RTX; 5816169689Skan 5817169689Skan return expand_val_compare_and_swap_1 (mem, old_val, new_val, target, icode); 5818169689Skan} 5819169689Skan 5820169689Skan/* Expand a compare-and-swap operation and store true into the result if 5821169689Skan the operation was successful and false otherwise. Return the result. 5822169689Skan Unlike other routines, TARGET is not optional. */ 5823169689Skan 5824169689Skanrtx 5825169689Skanexpand_bool_compare_and_swap (rtx mem, rtx old_val, rtx new_val, rtx target) 5826169689Skan{ 5827169689Skan enum machine_mode mode = GET_MODE (mem); 5828169689Skan enum insn_code icode; 5829169689Skan rtx subtarget, label0, label1; 5830169689Skan 5831169689Skan /* If the target supports a compare-and-swap pattern that simultaneously 5832169689Skan sets some flag for success, then use it. Otherwise use the regular 5833169689Skan compare-and-swap and follow that immediately with a compare insn. */ 5834169689Skan icode = sync_compare_and_swap_cc[mode]; 5835169689Skan switch (icode) 5836169689Skan { 5837169689Skan default: 5838169689Skan subtarget = expand_val_compare_and_swap_1 (mem, old_val, new_val, 5839169689Skan NULL_RTX, icode); 5840169689Skan if (subtarget != NULL_RTX) 5841169689Skan break; 5842169689Skan 5843169689Skan /* FALLTHRU */ 5844169689Skan case CODE_FOR_nothing: 5845169689Skan icode = sync_compare_and_swap[mode]; 5846169689Skan if (icode == CODE_FOR_nothing) 5847169689Skan return NULL_RTX; 5848169689Skan 5849169689Skan /* Ensure that if old_val == mem, that we're not comparing 5850169689Skan against an old value. */ 5851169689Skan if (MEM_P (old_val)) 5852169689Skan old_val = force_reg (mode, old_val); 5853169689Skan 5854169689Skan subtarget = expand_val_compare_and_swap_1 (mem, old_val, new_val, 5855169689Skan NULL_RTX, icode); 5856169689Skan if (subtarget == NULL_RTX) 5857169689Skan return NULL_RTX; 5858169689Skan 5859169689Skan emit_cmp_insn (subtarget, old_val, EQ, const0_rtx, mode, true); 5860169689Skan } 5861169689Skan 5862169689Skan /* If the target has a sane STORE_FLAG_VALUE, then go ahead and use a 5863169689Skan setcc instruction from the beginning. We don't work too hard here, 5864169689Skan but it's nice to not be stupid about initial code gen either. */ 5865169689Skan if (STORE_FLAG_VALUE == 1) 5866169689Skan { 5867169689Skan icode = setcc_gen_code[EQ]; 5868169689Skan if (icode != CODE_FOR_nothing) 5869169689Skan { 5870169689Skan enum machine_mode cmode = insn_data[icode].operand[0].mode; 5871169689Skan rtx insn; 5872169689Skan 5873169689Skan subtarget = target; 5874169689Skan if (!insn_data[icode].operand[0].predicate (target, cmode)) 5875169689Skan subtarget = gen_reg_rtx (cmode); 5876169689Skan 5877169689Skan insn = GEN_FCN (icode) (subtarget); 5878169689Skan if (insn) 5879169689Skan { 5880169689Skan emit_insn (insn); 5881169689Skan if (GET_MODE (target) != GET_MODE (subtarget)) 5882169689Skan { 5883169689Skan convert_move (target, subtarget, 1); 5884169689Skan subtarget = target; 5885169689Skan } 5886169689Skan return subtarget; 5887169689Skan } 5888169689Skan } 5889169689Skan } 5890169689Skan 5891169689Skan /* Without an appropriate setcc instruction, use a set of branches to 5892169689Skan get 1 and 0 stored into target. Presumably if the target has a 5893169689Skan STORE_FLAG_VALUE that isn't 1, then this will get cleaned up by ifcvt. */ 5894169689Skan 5895169689Skan label0 = gen_label_rtx (); 5896169689Skan label1 = gen_label_rtx (); 5897169689Skan 5898169689Skan emit_jump_insn (bcc_gen_fctn[EQ] (label0)); 5899169689Skan emit_move_insn (target, const0_rtx); 5900169689Skan emit_jump_insn (gen_jump (label1)); 5901169689Skan emit_barrier (); 5902169689Skan emit_label (label0); 5903169689Skan emit_move_insn (target, const1_rtx); 5904169689Skan emit_label (label1); 5905169689Skan 5906169689Skan return target; 5907169689Skan} 5908169689Skan 5909169689Skan/* This is a helper function for the other atomic operations. This function 5910169689Skan emits a loop that contains SEQ that iterates until a compare-and-swap 5911169689Skan operation at the end succeeds. MEM is the memory to be modified. SEQ is 5912169689Skan a set of instructions that takes a value from OLD_REG as an input and 5913169689Skan produces a value in NEW_REG as an output. Before SEQ, OLD_REG will be 5914169689Skan set to the current contents of MEM. After SEQ, a compare-and-swap will 5915169689Skan attempt to update MEM with NEW_REG. The function returns true when the 5916169689Skan loop was generated successfully. */ 5917169689Skan 5918169689Skanstatic bool 5919169689Skanexpand_compare_and_swap_loop (rtx mem, rtx old_reg, rtx new_reg, rtx seq) 5920169689Skan{ 5921169689Skan enum machine_mode mode = GET_MODE (mem); 5922169689Skan enum insn_code icode; 5923169689Skan rtx label, cmp_reg, subtarget; 5924169689Skan 5925169689Skan /* The loop we want to generate looks like 5926169689Skan 5927169689Skan cmp_reg = mem; 5928169689Skan label: 5929169689Skan old_reg = cmp_reg; 5930169689Skan seq; 5931169689Skan cmp_reg = compare-and-swap(mem, old_reg, new_reg) 5932169689Skan if (cmp_reg != old_reg) 5933169689Skan goto label; 5934169689Skan 5935169689Skan Note that we only do the plain load from memory once. Subsequent 5936169689Skan iterations use the value loaded by the compare-and-swap pattern. */ 5937169689Skan 5938169689Skan label = gen_label_rtx (); 5939169689Skan cmp_reg = gen_reg_rtx (mode); 5940169689Skan 5941169689Skan emit_move_insn (cmp_reg, mem); 5942169689Skan emit_label (label); 5943169689Skan emit_move_insn (old_reg, cmp_reg); 5944169689Skan if (seq) 5945169689Skan emit_insn (seq); 5946169689Skan 5947169689Skan /* If the target supports a compare-and-swap pattern that simultaneously 5948169689Skan sets some flag for success, then use it. Otherwise use the regular 5949169689Skan compare-and-swap and follow that immediately with a compare insn. */ 5950169689Skan icode = sync_compare_and_swap_cc[mode]; 5951169689Skan switch (icode) 5952169689Skan { 5953169689Skan default: 5954169689Skan subtarget = expand_val_compare_and_swap_1 (mem, old_reg, new_reg, 5955169689Skan cmp_reg, icode); 5956169689Skan if (subtarget != NULL_RTX) 5957169689Skan { 5958169689Skan gcc_assert (subtarget == cmp_reg); 5959169689Skan break; 5960169689Skan } 5961169689Skan 5962169689Skan /* FALLTHRU */ 5963169689Skan case CODE_FOR_nothing: 5964169689Skan icode = sync_compare_and_swap[mode]; 5965169689Skan if (icode == CODE_FOR_nothing) 5966169689Skan return false; 5967169689Skan 5968169689Skan subtarget = expand_val_compare_and_swap_1 (mem, old_reg, new_reg, 5969169689Skan cmp_reg, icode); 5970169689Skan if (subtarget == NULL_RTX) 5971169689Skan return false; 5972169689Skan if (subtarget != cmp_reg) 5973169689Skan emit_move_insn (cmp_reg, subtarget); 5974169689Skan 5975169689Skan emit_cmp_insn (cmp_reg, old_reg, EQ, const0_rtx, mode, true); 5976169689Skan } 5977169689Skan 5978169689Skan /* ??? Mark this jump predicted not taken? */ 5979169689Skan emit_jump_insn (bcc_gen_fctn[NE] (label)); 5980169689Skan 5981169689Skan return true; 5982169689Skan} 5983169689Skan 5984169689Skan/* This function generates the atomic operation MEM CODE= VAL. In this 5985169689Skan case, we do not care about any resulting value. Returns NULL if we 5986169689Skan cannot generate the operation. */ 5987169689Skan 5988169689Skanrtx 5989169689Skanexpand_sync_operation (rtx mem, rtx val, enum rtx_code code) 5990169689Skan{ 5991169689Skan enum machine_mode mode = GET_MODE (mem); 5992169689Skan enum insn_code icode; 5993169689Skan rtx insn; 5994169689Skan 5995169689Skan /* Look to see if the target supports the operation directly. */ 5996169689Skan switch (code) 5997169689Skan { 5998169689Skan case PLUS: 5999169689Skan icode = sync_add_optab[mode]; 6000169689Skan break; 6001169689Skan case IOR: 6002169689Skan icode = sync_ior_optab[mode]; 6003169689Skan break; 6004169689Skan case XOR: 6005169689Skan icode = sync_xor_optab[mode]; 6006169689Skan break; 6007169689Skan case AND: 6008169689Skan icode = sync_and_optab[mode]; 6009169689Skan break; 6010169689Skan case NOT: 6011169689Skan icode = sync_nand_optab[mode]; 6012169689Skan break; 6013169689Skan 6014169689Skan case MINUS: 6015169689Skan icode = sync_sub_optab[mode]; 6016169689Skan if (icode == CODE_FOR_nothing) 6017169689Skan { 6018169689Skan icode = sync_add_optab[mode]; 6019169689Skan if (icode != CODE_FOR_nothing) 6020169689Skan { 6021169689Skan val = expand_simple_unop (mode, NEG, val, NULL_RTX, 1); 6022169689Skan code = PLUS; 6023169689Skan } 6024169689Skan } 6025169689Skan break; 6026169689Skan 6027169689Skan default: 6028169689Skan gcc_unreachable (); 6029169689Skan } 6030169689Skan 6031169689Skan /* Generate the direct operation, if present. */ 6032169689Skan if (icode != CODE_FOR_nothing) 6033169689Skan { 6034169689Skan if (GET_MODE (val) != VOIDmode && GET_MODE (val) != mode) 6035169689Skan val = convert_modes (mode, GET_MODE (val), val, 1); 6036169689Skan if (!insn_data[icode].operand[1].predicate (val, mode)) 6037169689Skan val = force_reg (mode, val); 6038169689Skan 6039169689Skan insn = GEN_FCN (icode) (mem, val); 6040169689Skan if (insn) 6041169689Skan { 6042169689Skan emit_insn (insn); 6043169689Skan return const0_rtx; 6044169689Skan } 6045169689Skan } 6046169689Skan 6047169689Skan /* Failing that, generate a compare-and-swap loop in which we perform the 6048169689Skan operation with normal arithmetic instructions. */ 6049169689Skan if (sync_compare_and_swap[mode] != CODE_FOR_nothing) 6050169689Skan { 6051169689Skan rtx t0 = gen_reg_rtx (mode), t1; 6052169689Skan 6053169689Skan start_sequence (); 6054169689Skan 6055169689Skan t1 = t0; 6056169689Skan if (code == NOT) 6057169689Skan { 6058169689Skan t1 = expand_simple_unop (mode, NOT, t1, NULL_RTX, true); 6059169689Skan code = AND; 6060169689Skan } 6061169689Skan t1 = expand_simple_binop (mode, code, t1, val, NULL_RTX, 6062169689Skan true, OPTAB_LIB_WIDEN); 6063169689Skan 6064169689Skan insn = get_insns (); 6065169689Skan end_sequence (); 6066169689Skan 6067169689Skan if (t1 != NULL && expand_compare_and_swap_loop (mem, t0, t1, insn)) 6068169689Skan return const0_rtx; 6069169689Skan } 6070169689Skan 6071169689Skan return NULL_RTX; 6072169689Skan} 6073169689Skan 6074169689Skan/* This function generates the atomic operation MEM CODE= VAL. In this 6075169689Skan case, we do care about the resulting value: if AFTER is true then 6076169689Skan return the value MEM holds after the operation, if AFTER is false 6077169689Skan then return the value MEM holds before the operation. TARGET is an 6078169689Skan optional place for the result value to be stored. */ 6079169689Skan 6080169689Skanrtx 6081169689Skanexpand_sync_fetch_operation (rtx mem, rtx val, enum rtx_code code, 6082169689Skan bool after, rtx target) 6083169689Skan{ 6084169689Skan enum machine_mode mode = GET_MODE (mem); 6085169689Skan enum insn_code old_code, new_code, icode; 6086169689Skan bool compensate; 6087169689Skan rtx insn; 6088169689Skan 6089169689Skan /* Look to see if the target supports the operation directly. */ 6090169689Skan switch (code) 6091169689Skan { 6092169689Skan case PLUS: 6093169689Skan old_code = sync_old_add_optab[mode]; 6094169689Skan new_code = sync_new_add_optab[mode]; 6095169689Skan break; 6096169689Skan case IOR: 6097169689Skan old_code = sync_old_ior_optab[mode]; 6098169689Skan new_code = sync_new_ior_optab[mode]; 6099169689Skan break; 6100169689Skan case XOR: 6101169689Skan old_code = sync_old_xor_optab[mode]; 6102169689Skan new_code = sync_new_xor_optab[mode]; 6103169689Skan break; 6104169689Skan case AND: 6105169689Skan old_code = sync_old_and_optab[mode]; 6106169689Skan new_code = sync_new_and_optab[mode]; 6107169689Skan break; 6108169689Skan case NOT: 6109169689Skan old_code = sync_old_nand_optab[mode]; 6110169689Skan new_code = sync_new_nand_optab[mode]; 6111169689Skan break; 6112169689Skan 6113169689Skan case MINUS: 6114169689Skan old_code = sync_old_sub_optab[mode]; 6115169689Skan new_code = sync_new_sub_optab[mode]; 6116169689Skan if (old_code == CODE_FOR_nothing && new_code == CODE_FOR_nothing) 6117169689Skan { 6118169689Skan old_code = sync_old_add_optab[mode]; 6119169689Skan new_code = sync_new_add_optab[mode]; 6120169689Skan if (old_code != CODE_FOR_nothing || new_code != CODE_FOR_nothing) 6121169689Skan { 6122169689Skan val = expand_simple_unop (mode, NEG, val, NULL_RTX, 1); 6123169689Skan code = PLUS; 6124169689Skan } 6125169689Skan } 6126169689Skan break; 6127169689Skan 6128169689Skan default: 6129169689Skan gcc_unreachable (); 6130169689Skan } 6131169689Skan 6132169689Skan /* If the target does supports the proper new/old operation, great. But 6133169689Skan if we only support the opposite old/new operation, check to see if we 6134169689Skan can compensate. In the case in which the old value is supported, then 6135169689Skan we can always perform the operation again with normal arithmetic. In 6136169689Skan the case in which the new value is supported, then we can only handle 6137169689Skan this in the case the operation is reversible. */ 6138169689Skan compensate = false; 6139169689Skan if (after) 6140169689Skan { 6141169689Skan icode = new_code; 6142169689Skan if (icode == CODE_FOR_nothing) 6143169689Skan { 6144169689Skan icode = old_code; 6145169689Skan if (icode != CODE_FOR_nothing) 6146169689Skan compensate = true; 6147169689Skan } 6148169689Skan } 6149169689Skan else 6150169689Skan { 6151169689Skan icode = old_code; 6152169689Skan if (icode == CODE_FOR_nothing 6153169689Skan && (code == PLUS || code == MINUS || code == XOR)) 6154169689Skan { 6155169689Skan icode = new_code; 6156169689Skan if (icode != CODE_FOR_nothing) 6157169689Skan compensate = true; 6158169689Skan } 6159169689Skan } 6160169689Skan 6161169689Skan /* If we found something supported, great. */ 6162169689Skan if (icode != CODE_FOR_nothing) 6163169689Skan { 6164169689Skan if (!target || !insn_data[icode].operand[0].predicate (target, mode)) 6165169689Skan target = gen_reg_rtx (mode); 6166169689Skan 6167169689Skan if (GET_MODE (val) != VOIDmode && GET_MODE (val) != mode) 6168169689Skan val = convert_modes (mode, GET_MODE (val), val, 1); 6169169689Skan if (!insn_data[icode].operand[2].predicate (val, mode)) 6170169689Skan val = force_reg (mode, val); 6171169689Skan 6172169689Skan insn = GEN_FCN (icode) (target, mem, val); 6173169689Skan if (insn) 6174169689Skan { 6175169689Skan emit_insn (insn); 6176169689Skan 6177169689Skan /* If we need to compensate for using an operation with the 6178169689Skan wrong return value, do so now. */ 6179169689Skan if (compensate) 6180169689Skan { 6181169689Skan if (!after) 6182169689Skan { 6183169689Skan if (code == PLUS) 6184169689Skan code = MINUS; 6185169689Skan else if (code == MINUS) 6186169689Skan code = PLUS; 6187169689Skan } 6188169689Skan 6189169689Skan if (code == NOT) 6190169689Skan target = expand_simple_unop (mode, NOT, target, NULL_RTX, true); 6191169689Skan target = expand_simple_binop (mode, code, target, val, NULL_RTX, 6192169689Skan true, OPTAB_LIB_WIDEN); 6193169689Skan } 6194169689Skan 6195169689Skan return target; 6196169689Skan } 6197169689Skan } 6198169689Skan 6199169689Skan /* Failing that, generate a compare-and-swap loop in which we perform the 6200169689Skan operation with normal arithmetic instructions. */ 6201169689Skan if (sync_compare_and_swap[mode] != CODE_FOR_nothing) 6202169689Skan { 6203169689Skan rtx t0 = gen_reg_rtx (mode), t1; 6204169689Skan 6205169689Skan if (!target || !register_operand (target, mode)) 6206169689Skan target = gen_reg_rtx (mode); 6207169689Skan 6208169689Skan start_sequence (); 6209169689Skan 6210169689Skan if (!after) 6211169689Skan emit_move_insn (target, t0); 6212169689Skan t1 = t0; 6213169689Skan if (code == NOT) 6214169689Skan { 6215169689Skan t1 = expand_simple_unop (mode, NOT, t1, NULL_RTX, true); 6216169689Skan code = AND; 6217169689Skan } 6218169689Skan t1 = expand_simple_binop (mode, code, t1, val, NULL_RTX, 6219169689Skan true, OPTAB_LIB_WIDEN); 6220169689Skan if (after) 6221169689Skan emit_move_insn (target, t1); 6222169689Skan 6223169689Skan insn = get_insns (); 6224169689Skan end_sequence (); 6225169689Skan 6226169689Skan if (t1 != NULL && expand_compare_and_swap_loop (mem, t0, t1, insn)) 6227169689Skan return target; 6228169689Skan } 6229169689Skan 6230169689Skan return NULL_RTX; 6231169689Skan} 6232169689Skan 6233169689Skan/* This function expands a test-and-set operation. Ideally we atomically 6234169689Skan store VAL in MEM and return the previous value in MEM. Some targets 6235169689Skan may not support this operation and only support VAL with the constant 1; 6236169689Skan in this case while the return value will be 0/1, but the exact value 6237169689Skan stored in MEM is target defined. TARGET is an option place to stick 6238169689Skan the return value. */ 6239169689Skan 6240169689Skanrtx 6241169689Skanexpand_sync_lock_test_and_set (rtx mem, rtx val, rtx target) 6242169689Skan{ 6243169689Skan enum machine_mode mode = GET_MODE (mem); 6244169689Skan enum insn_code icode; 6245169689Skan rtx insn; 6246169689Skan 6247169689Skan /* If the target supports the test-and-set directly, great. */ 6248169689Skan icode = sync_lock_test_and_set[mode]; 6249169689Skan if (icode != CODE_FOR_nothing) 6250169689Skan { 6251169689Skan if (!target || !insn_data[icode].operand[0].predicate (target, mode)) 6252169689Skan target = gen_reg_rtx (mode); 6253169689Skan 6254169689Skan if (GET_MODE (val) != VOIDmode && GET_MODE (val) != mode) 6255169689Skan val = convert_modes (mode, GET_MODE (val), val, 1); 6256169689Skan if (!insn_data[icode].operand[2].predicate (val, mode)) 6257169689Skan val = force_reg (mode, val); 6258169689Skan 6259169689Skan insn = GEN_FCN (icode) (target, mem, val); 6260169689Skan if (insn) 6261169689Skan { 6262169689Skan emit_insn (insn); 6263169689Skan return target; 6264169689Skan } 6265169689Skan } 6266169689Skan 6267169689Skan /* Otherwise, use a compare-and-swap loop for the exchange. */ 6268169689Skan if (sync_compare_and_swap[mode] != CODE_FOR_nothing) 6269169689Skan { 6270169689Skan if (!target || !register_operand (target, mode)) 6271169689Skan target = gen_reg_rtx (mode); 6272169689Skan if (GET_MODE (val) != VOIDmode && GET_MODE (val) != mode) 6273169689Skan val = convert_modes (mode, GET_MODE (val), val, 1); 6274169689Skan if (expand_compare_and_swap_loop (mem, target, val, NULL_RTX)) 6275169689Skan return target; 6276169689Skan } 6277169689Skan 6278169689Skan return NULL_RTX; 6279169689Skan} 6280169689Skan 6281117395Skan#include "gt-optabs.h" 6282