;; Mips.md Machine Description for MIPS based processors
|
;; Mips.md Machine Description for MIPS based processors
|
;; Copyright (C) 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998,
|
;; Copyright (C) 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998,
|
;; 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010
|
;; 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010
|
;; Free Software Foundation, Inc.
|
;; Free Software Foundation, Inc.
|
;; Contributed by A. Lichnewsky, lich@inria.inria.fr
|
;; Contributed by A. Lichnewsky, lich@inria.inria.fr
|
;; Changes by Michael Meissner, meissner@osf.org
|
;; Changes by Michael Meissner, meissner@osf.org
|
;; 64-bit r4000 support by Ian Lance Taylor, ian@cygnus.com, and
|
;; 64-bit r4000 support by Ian Lance Taylor, ian@cygnus.com, and
|
;; Brendan Eich, brendan@microunity.com.
|
;; Brendan Eich, brendan@microunity.com.
|
|
|
;; This file is part of GCC.
|
;; This file is part of GCC.
|
|
|
;; GCC is free software; you can redistribute it and/or modify
|
;; GCC is free software; you can redistribute it and/or modify
|
;; it under the terms of the GNU General Public License as published by
|
;; it under the terms of the GNU General Public License as published by
|
;; the Free Software Foundation; either version 3, or (at your option)
|
;; the Free Software Foundation; either version 3, or (at your option)
|
;; any later version.
|
;; any later version.
|
|
|
;; GCC is distributed in the hope that it will be useful,
|
;; GCC is distributed in the hope that it will be useful,
|
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
|
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
|
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
;; GNU General Public License for more details.
|
;; GNU General Public License for more details.
|
|
|
;; You should have received a copy of the GNU General Public License
|
;; You should have received a copy of the GNU General Public License
|
;; along with GCC; see the file COPYING3. If not see
|
;; along with GCC; see the file COPYING3. If not see
|
;; .
|
;; .
|
|
|
(define_constants
|
(define_constants
|
[(UNSPEC_LOAD_LOW 0)
|
[(UNSPEC_LOAD_LOW 0)
|
(UNSPEC_LOAD_HIGH 1)
|
(UNSPEC_LOAD_HIGH 1)
|
(UNSPEC_STORE_WORD 2)
|
(UNSPEC_STORE_WORD 2)
|
(UNSPEC_GET_FNADDR 3)
|
(UNSPEC_GET_FNADDR 3)
|
(UNSPEC_BLOCKAGE 4)
|
(UNSPEC_BLOCKAGE 4)
|
(UNSPEC_POTENTIAL_CPRESTORE 5)
|
(UNSPEC_POTENTIAL_CPRESTORE 5)
|
(UNSPEC_CPRESTORE 6)
|
(UNSPEC_CPRESTORE 6)
|
(UNSPEC_RESTORE_GP 7)
|
(UNSPEC_RESTORE_GP 7)
|
(UNSPEC_MOVE_GP 8)
|
(UNSPEC_MOVE_GP 8)
|
(UNSPEC_EH_RETURN 9)
|
(UNSPEC_EH_RETURN 9)
|
(UNSPEC_CONSTTABLE_INT 10)
|
(UNSPEC_CONSTTABLE_INT 10)
|
(UNSPEC_CONSTTABLE_FLOAT 11)
|
(UNSPEC_CONSTTABLE_FLOAT 11)
|
(UNSPEC_ALIGN 14)
|
(UNSPEC_ALIGN 14)
|
(UNSPEC_HIGH 17)
|
(UNSPEC_HIGH 17)
|
(UNSPEC_LOAD_LEFT 18)
|
(UNSPEC_LOAD_LEFT 18)
|
(UNSPEC_LOAD_RIGHT 19)
|
(UNSPEC_LOAD_RIGHT 19)
|
(UNSPEC_STORE_LEFT 20)
|
(UNSPEC_STORE_LEFT 20)
|
(UNSPEC_STORE_RIGHT 21)
|
(UNSPEC_STORE_RIGHT 21)
|
(UNSPEC_LOADGP 22)
|
(UNSPEC_LOADGP 22)
|
(UNSPEC_LOAD_CALL 23)
|
(UNSPEC_LOAD_CALL 23)
|
(UNSPEC_LOAD_GOT 24)
|
(UNSPEC_LOAD_GOT 24)
|
(UNSPEC_GP 25)
|
(UNSPEC_GP 25)
|
(UNSPEC_MFHI 26)
|
(UNSPEC_MFHI 26)
|
(UNSPEC_MTHI 27)
|
(UNSPEC_MTHI 27)
|
(UNSPEC_SET_HILO 28)
|
(UNSPEC_SET_HILO 28)
|
(UNSPEC_TLS_LDM 29)
|
(UNSPEC_TLS_LDM 29)
|
(UNSPEC_TLS_GET_TP 30)
|
(UNSPEC_TLS_GET_TP 30)
|
(UNSPEC_MFHC1 31)
|
(UNSPEC_MFHC1 31)
|
(UNSPEC_MTHC1 32)
|
(UNSPEC_MTHC1 32)
|
(UNSPEC_CLEAR_HAZARD 33)
|
(UNSPEC_CLEAR_HAZARD 33)
|
(UNSPEC_RDHWR 34)
|
(UNSPEC_RDHWR 34)
|
(UNSPEC_SYNCI 35)
|
(UNSPEC_SYNCI 35)
|
(UNSPEC_SYNC 36)
|
(UNSPEC_SYNC 36)
|
(UNSPEC_COMPARE_AND_SWAP 37)
|
(UNSPEC_COMPARE_AND_SWAP 37)
|
(UNSPEC_COMPARE_AND_SWAP_12 38)
|
(UNSPEC_COMPARE_AND_SWAP_12 38)
|
(UNSPEC_SYNC_OLD_OP 39)
|
(UNSPEC_SYNC_OLD_OP 39)
|
(UNSPEC_SYNC_NEW_OP 40)
|
(UNSPEC_SYNC_NEW_OP 40)
|
(UNSPEC_SYNC_NEW_OP_12 41)
|
(UNSPEC_SYNC_NEW_OP_12 41)
|
(UNSPEC_SYNC_OLD_OP_12 42)
|
(UNSPEC_SYNC_OLD_OP_12 42)
|
(UNSPEC_SYNC_EXCHANGE 43)
|
(UNSPEC_SYNC_EXCHANGE 43)
|
(UNSPEC_SYNC_EXCHANGE_12 44)
|
(UNSPEC_SYNC_EXCHANGE_12 44)
|
(UNSPEC_MEMORY_BARRIER 45)
|
(UNSPEC_MEMORY_BARRIER 45)
|
(UNSPEC_SET_GOT_VERSION 46)
|
(UNSPEC_SET_GOT_VERSION 46)
|
(UNSPEC_UPDATE_GOT_VERSION 47)
|
(UNSPEC_UPDATE_GOT_VERSION 47)
|
(UNSPEC_COPYGP 48)
|
(UNSPEC_COPYGP 48)
|
(UNSPEC_ERET 49)
|
(UNSPEC_ERET 49)
|
(UNSPEC_DERET 50)
|
(UNSPEC_DERET 50)
|
(UNSPEC_DI 51)
|
(UNSPEC_DI 51)
|
(UNSPEC_EHB 52)
|
(UNSPEC_EHB 52)
|
(UNSPEC_RDPGPR 53)
|
(UNSPEC_RDPGPR 53)
|
(UNSPEC_COP0 54)
|
(UNSPEC_COP0 54)
|
;; Used in a call expression in place of args_size. It's present for PIC
|
;; Used in a call expression in place of args_size. It's present for PIC
|
;; indirect calls where it contains args_size and the function symbol.
|
;; indirect calls where it contains args_size and the function symbol.
|
(UNSPEC_CALL_ATTR 55)
|
(UNSPEC_CALL_ATTR 55)
|
|
|
(UNSPEC_ADDRESS_FIRST 100)
|
(UNSPEC_ADDRESS_FIRST 100)
|
|
|
(TLS_GET_TP_REGNUM 3)
|
(TLS_GET_TP_REGNUM 3)
|
(RETURN_ADDR_REGNUM 31)
|
(RETURN_ADDR_REGNUM 31)
|
(CPRESTORE_SLOT_REGNUM 76)
|
(CPRESTORE_SLOT_REGNUM 76)
|
(GOT_VERSION_REGNUM 79)
|
(GOT_VERSION_REGNUM 79)
|
|
|
;; For MIPS Paired-Singled Floating Point Instructions.
|
;; For MIPS Paired-Singled Floating Point Instructions.
|
|
|
(UNSPEC_MOVE_TF_PS 200)
|
(UNSPEC_MOVE_TF_PS 200)
|
(UNSPEC_C 201)
|
(UNSPEC_C 201)
|
|
|
;; MIPS64/MIPS32R2 alnv.ps
|
;; MIPS64/MIPS32R2 alnv.ps
|
(UNSPEC_ALNV_PS 202)
|
(UNSPEC_ALNV_PS 202)
|
|
|
;; MIPS-3D instructions
|
;; MIPS-3D instructions
|
(UNSPEC_CABS 203)
|
(UNSPEC_CABS 203)
|
|
|
(UNSPEC_ADDR_PS 204)
|
(UNSPEC_ADDR_PS 204)
|
(UNSPEC_CVT_PW_PS 205)
|
(UNSPEC_CVT_PW_PS 205)
|
(UNSPEC_CVT_PS_PW 206)
|
(UNSPEC_CVT_PS_PW 206)
|
(UNSPEC_MULR_PS 207)
|
(UNSPEC_MULR_PS 207)
|
(UNSPEC_ABS_PS 208)
|
(UNSPEC_ABS_PS 208)
|
|
|
(UNSPEC_RSQRT1 209)
|
(UNSPEC_RSQRT1 209)
|
(UNSPEC_RSQRT2 210)
|
(UNSPEC_RSQRT2 210)
|
(UNSPEC_RECIP1 211)
|
(UNSPEC_RECIP1 211)
|
(UNSPEC_RECIP2 212)
|
(UNSPEC_RECIP2 212)
|
(UNSPEC_SINGLE_CC 213)
|
(UNSPEC_SINGLE_CC 213)
|
(UNSPEC_SCC 214)
|
(UNSPEC_SCC 214)
|
|
|
;; MIPS DSP ASE Revision 0.98 3/24/2005
|
;; MIPS DSP ASE Revision 0.98 3/24/2005
|
(UNSPEC_ADDQ 300)
|
(UNSPEC_ADDQ 300)
|
(UNSPEC_ADDQ_S 301)
|
(UNSPEC_ADDQ_S 301)
|
(UNSPEC_SUBQ 302)
|
(UNSPEC_SUBQ 302)
|
(UNSPEC_SUBQ_S 303)
|
(UNSPEC_SUBQ_S 303)
|
(UNSPEC_ADDSC 304)
|
(UNSPEC_ADDSC 304)
|
(UNSPEC_ADDWC 305)
|
(UNSPEC_ADDWC 305)
|
(UNSPEC_MODSUB 306)
|
(UNSPEC_MODSUB 306)
|
(UNSPEC_RADDU_W_QB 307)
|
(UNSPEC_RADDU_W_QB 307)
|
(UNSPEC_ABSQ_S 308)
|
(UNSPEC_ABSQ_S 308)
|
(UNSPEC_PRECRQ_QB_PH 309)
|
(UNSPEC_PRECRQ_QB_PH 309)
|
(UNSPEC_PRECRQ_PH_W 310)
|
(UNSPEC_PRECRQ_PH_W 310)
|
(UNSPEC_PRECRQ_RS_PH_W 311)
|
(UNSPEC_PRECRQ_RS_PH_W 311)
|
(UNSPEC_PRECRQU_S_QB_PH 312)
|
(UNSPEC_PRECRQU_S_QB_PH 312)
|
(UNSPEC_PRECEQ_W_PHL 313)
|
(UNSPEC_PRECEQ_W_PHL 313)
|
(UNSPEC_PRECEQ_W_PHR 314)
|
(UNSPEC_PRECEQ_W_PHR 314)
|
(UNSPEC_PRECEQU_PH_QBL 315)
|
(UNSPEC_PRECEQU_PH_QBL 315)
|
(UNSPEC_PRECEQU_PH_QBR 316)
|
(UNSPEC_PRECEQU_PH_QBR 316)
|
(UNSPEC_PRECEQU_PH_QBLA 317)
|
(UNSPEC_PRECEQU_PH_QBLA 317)
|
(UNSPEC_PRECEQU_PH_QBRA 318)
|
(UNSPEC_PRECEQU_PH_QBRA 318)
|
(UNSPEC_PRECEU_PH_QBL 319)
|
(UNSPEC_PRECEU_PH_QBL 319)
|
(UNSPEC_PRECEU_PH_QBR 320)
|
(UNSPEC_PRECEU_PH_QBR 320)
|
(UNSPEC_PRECEU_PH_QBLA 321)
|
(UNSPEC_PRECEU_PH_QBLA 321)
|
(UNSPEC_PRECEU_PH_QBRA 322)
|
(UNSPEC_PRECEU_PH_QBRA 322)
|
(UNSPEC_SHLL 323)
|
(UNSPEC_SHLL 323)
|
(UNSPEC_SHLL_S 324)
|
(UNSPEC_SHLL_S 324)
|
(UNSPEC_SHRL_QB 325)
|
(UNSPEC_SHRL_QB 325)
|
(UNSPEC_SHRA_PH 326)
|
(UNSPEC_SHRA_PH 326)
|
(UNSPEC_SHRA_R 327)
|
(UNSPEC_SHRA_R 327)
|
(UNSPEC_MULEU_S_PH_QBL 328)
|
(UNSPEC_MULEU_S_PH_QBL 328)
|
(UNSPEC_MULEU_S_PH_QBR 329)
|
(UNSPEC_MULEU_S_PH_QBR 329)
|
(UNSPEC_MULQ_RS_PH 330)
|
(UNSPEC_MULQ_RS_PH 330)
|
(UNSPEC_MULEQ_S_W_PHL 331)
|
(UNSPEC_MULEQ_S_W_PHL 331)
|
(UNSPEC_MULEQ_S_W_PHR 332)
|
(UNSPEC_MULEQ_S_W_PHR 332)
|
(UNSPEC_DPAU_H_QBL 333)
|
(UNSPEC_DPAU_H_QBL 333)
|
(UNSPEC_DPAU_H_QBR 334)
|
(UNSPEC_DPAU_H_QBR 334)
|
(UNSPEC_DPSU_H_QBL 335)
|
(UNSPEC_DPSU_H_QBL 335)
|
(UNSPEC_DPSU_H_QBR 336)
|
(UNSPEC_DPSU_H_QBR 336)
|
(UNSPEC_DPAQ_S_W_PH 337)
|
(UNSPEC_DPAQ_S_W_PH 337)
|
(UNSPEC_DPSQ_S_W_PH 338)
|
(UNSPEC_DPSQ_S_W_PH 338)
|
(UNSPEC_MULSAQ_S_W_PH 339)
|
(UNSPEC_MULSAQ_S_W_PH 339)
|
(UNSPEC_DPAQ_SA_L_W 340)
|
(UNSPEC_DPAQ_SA_L_W 340)
|
(UNSPEC_DPSQ_SA_L_W 341)
|
(UNSPEC_DPSQ_SA_L_W 341)
|
(UNSPEC_MAQ_S_W_PHL 342)
|
(UNSPEC_MAQ_S_W_PHL 342)
|
(UNSPEC_MAQ_S_W_PHR 343)
|
(UNSPEC_MAQ_S_W_PHR 343)
|
(UNSPEC_MAQ_SA_W_PHL 344)
|
(UNSPEC_MAQ_SA_W_PHL 344)
|
(UNSPEC_MAQ_SA_W_PHR 345)
|
(UNSPEC_MAQ_SA_W_PHR 345)
|
(UNSPEC_BITREV 346)
|
(UNSPEC_BITREV 346)
|
(UNSPEC_INSV 347)
|
(UNSPEC_INSV 347)
|
(UNSPEC_REPL_QB 348)
|
(UNSPEC_REPL_QB 348)
|
(UNSPEC_REPL_PH 349)
|
(UNSPEC_REPL_PH 349)
|
(UNSPEC_CMP_EQ 350)
|
(UNSPEC_CMP_EQ 350)
|
(UNSPEC_CMP_LT 351)
|
(UNSPEC_CMP_LT 351)
|
(UNSPEC_CMP_LE 352)
|
(UNSPEC_CMP_LE 352)
|
(UNSPEC_CMPGU_EQ_QB 353)
|
(UNSPEC_CMPGU_EQ_QB 353)
|
(UNSPEC_CMPGU_LT_QB 354)
|
(UNSPEC_CMPGU_LT_QB 354)
|
(UNSPEC_CMPGU_LE_QB 355)
|
(UNSPEC_CMPGU_LE_QB 355)
|
(UNSPEC_PICK 356)
|
(UNSPEC_PICK 356)
|
(UNSPEC_PACKRL_PH 357)
|
(UNSPEC_PACKRL_PH 357)
|
(UNSPEC_EXTR_W 358)
|
(UNSPEC_EXTR_W 358)
|
(UNSPEC_EXTR_R_W 359)
|
(UNSPEC_EXTR_R_W 359)
|
(UNSPEC_EXTR_RS_W 360)
|
(UNSPEC_EXTR_RS_W 360)
|
(UNSPEC_EXTR_S_H 361)
|
(UNSPEC_EXTR_S_H 361)
|
(UNSPEC_EXTP 362)
|
(UNSPEC_EXTP 362)
|
(UNSPEC_EXTPDP 363)
|
(UNSPEC_EXTPDP 363)
|
(UNSPEC_SHILO 364)
|
(UNSPEC_SHILO 364)
|
(UNSPEC_MTHLIP 365)
|
(UNSPEC_MTHLIP 365)
|
(UNSPEC_WRDSP 366)
|
(UNSPEC_WRDSP 366)
|
(UNSPEC_RDDSP 367)
|
(UNSPEC_RDDSP 367)
|
|
|
;; MIPS DSP ASE REV 2 Revision 0.02 11/24/2006
|
;; MIPS DSP ASE REV 2 Revision 0.02 11/24/2006
|
(UNSPEC_ABSQ_S_QB 400)
|
(UNSPEC_ABSQ_S_QB 400)
|
(UNSPEC_ADDU_PH 401)
|
(UNSPEC_ADDU_PH 401)
|
(UNSPEC_ADDU_S_PH 402)
|
(UNSPEC_ADDU_S_PH 402)
|
(UNSPEC_ADDUH_QB 403)
|
(UNSPEC_ADDUH_QB 403)
|
(UNSPEC_ADDUH_R_QB 404)
|
(UNSPEC_ADDUH_R_QB 404)
|
(UNSPEC_APPEND 405)
|
(UNSPEC_APPEND 405)
|
(UNSPEC_BALIGN 406)
|
(UNSPEC_BALIGN 406)
|
(UNSPEC_CMPGDU_EQ_QB 407)
|
(UNSPEC_CMPGDU_EQ_QB 407)
|
(UNSPEC_CMPGDU_LT_QB 408)
|
(UNSPEC_CMPGDU_LT_QB 408)
|
(UNSPEC_CMPGDU_LE_QB 409)
|
(UNSPEC_CMPGDU_LE_QB 409)
|
(UNSPEC_DPA_W_PH 410)
|
(UNSPEC_DPA_W_PH 410)
|
(UNSPEC_DPS_W_PH 411)
|
(UNSPEC_DPS_W_PH 411)
|
(UNSPEC_MADD 412)
|
(UNSPEC_MADD 412)
|
(UNSPEC_MADDU 413)
|
(UNSPEC_MADDU 413)
|
(UNSPEC_MSUB 414)
|
(UNSPEC_MSUB 414)
|
(UNSPEC_MSUBU 415)
|
(UNSPEC_MSUBU 415)
|
(UNSPEC_MUL_PH 416)
|
(UNSPEC_MUL_PH 416)
|
(UNSPEC_MUL_S_PH 417)
|
(UNSPEC_MUL_S_PH 417)
|
(UNSPEC_MULQ_RS_W 418)
|
(UNSPEC_MULQ_RS_W 418)
|
(UNSPEC_MULQ_S_PH 419)
|
(UNSPEC_MULQ_S_PH 419)
|
(UNSPEC_MULQ_S_W 420)
|
(UNSPEC_MULQ_S_W 420)
|
(UNSPEC_MULSA_W_PH 421)
|
(UNSPEC_MULSA_W_PH 421)
|
(UNSPEC_MULT 422)
|
(UNSPEC_MULT 422)
|
(UNSPEC_MULTU 423)
|
(UNSPEC_MULTU 423)
|
(UNSPEC_PRECR_QB_PH 424)
|
(UNSPEC_PRECR_QB_PH 424)
|
(UNSPEC_PRECR_SRA_PH_W 425)
|
(UNSPEC_PRECR_SRA_PH_W 425)
|
(UNSPEC_PRECR_SRA_R_PH_W 426)
|
(UNSPEC_PRECR_SRA_R_PH_W 426)
|
(UNSPEC_PREPEND 427)
|
(UNSPEC_PREPEND 427)
|
(UNSPEC_SHRA_QB 428)
|
(UNSPEC_SHRA_QB 428)
|
(UNSPEC_SHRA_R_QB 429)
|
(UNSPEC_SHRA_R_QB 429)
|
(UNSPEC_SHRL_PH 430)
|
(UNSPEC_SHRL_PH 430)
|
(UNSPEC_SUBU_PH 431)
|
(UNSPEC_SUBU_PH 431)
|
(UNSPEC_SUBU_S_PH 432)
|
(UNSPEC_SUBU_S_PH 432)
|
(UNSPEC_SUBUH_QB 433)
|
(UNSPEC_SUBUH_QB 433)
|
(UNSPEC_SUBUH_R_QB 434)
|
(UNSPEC_SUBUH_R_QB 434)
|
(UNSPEC_ADDQH_PH 435)
|
(UNSPEC_ADDQH_PH 435)
|
(UNSPEC_ADDQH_R_PH 436)
|
(UNSPEC_ADDQH_R_PH 436)
|
(UNSPEC_ADDQH_W 437)
|
(UNSPEC_ADDQH_W 437)
|
(UNSPEC_ADDQH_R_W 438)
|
(UNSPEC_ADDQH_R_W 438)
|
(UNSPEC_SUBQH_PH 439)
|
(UNSPEC_SUBQH_PH 439)
|
(UNSPEC_SUBQH_R_PH 440)
|
(UNSPEC_SUBQH_R_PH 440)
|
(UNSPEC_SUBQH_W 441)
|
(UNSPEC_SUBQH_W 441)
|
(UNSPEC_SUBQH_R_W 442)
|
(UNSPEC_SUBQH_R_W 442)
|
(UNSPEC_DPAX_W_PH 443)
|
(UNSPEC_DPAX_W_PH 443)
|
(UNSPEC_DPSX_W_PH 444)
|
(UNSPEC_DPSX_W_PH 444)
|
(UNSPEC_DPAQX_S_W_PH 445)
|
(UNSPEC_DPAQX_S_W_PH 445)
|
(UNSPEC_DPAQX_SA_W_PH 446)
|
(UNSPEC_DPAQX_SA_W_PH 446)
|
(UNSPEC_DPSQX_S_W_PH 447)
|
(UNSPEC_DPSQX_S_W_PH 447)
|
(UNSPEC_DPSQX_SA_W_PH 448)
|
(UNSPEC_DPSQX_SA_W_PH 448)
|
|
|
;; ST Microelectronics Loongson-2E/2F.
|
;; ST Microelectronics Loongson-2E/2F.
|
(UNSPEC_LOONGSON_PAVG 500)
|
(UNSPEC_LOONGSON_PAVG 500)
|
(UNSPEC_LOONGSON_PCMPEQ 501)
|
(UNSPEC_LOONGSON_PCMPEQ 501)
|
(UNSPEC_LOONGSON_PCMPGT 502)
|
(UNSPEC_LOONGSON_PCMPGT 502)
|
(UNSPEC_LOONGSON_PEXTR 503)
|
(UNSPEC_LOONGSON_PEXTR 503)
|
(UNSPEC_LOONGSON_PINSR_0 504)
|
(UNSPEC_LOONGSON_PINSR_0 504)
|
(UNSPEC_LOONGSON_PINSR_1 505)
|
(UNSPEC_LOONGSON_PINSR_1 505)
|
(UNSPEC_LOONGSON_PINSR_2 506)
|
(UNSPEC_LOONGSON_PINSR_2 506)
|
(UNSPEC_LOONGSON_PINSR_3 507)
|
(UNSPEC_LOONGSON_PINSR_3 507)
|
(UNSPEC_LOONGSON_PMADD 508)
|
(UNSPEC_LOONGSON_PMADD 508)
|
(UNSPEC_LOONGSON_PMOVMSK 509)
|
(UNSPEC_LOONGSON_PMOVMSK 509)
|
(UNSPEC_LOONGSON_PMULHU 510)
|
(UNSPEC_LOONGSON_PMULHU 510)
|
(UNSPEC_LOONGSON_PMULH 511)
|
(UNSPEC_LOONGSON_PMULH 511)
|
(UNSPEC_LOONGSON_PMULL 512)
|
(UNSPEC_LOONGSON_PMULL 512)
|
(UNSPEC_LOONGSON_PMULU 513)
|
(UNSPEC_LOONGSON_PMULU 513)
|
(UNSPEC_LOONGSON_PASUBUB 514)
|
(UNSPEC_LOONGSON_PASUBUB 514)
|
(UNSPEC_LOONGSON_BIADD 515)
|
(UNSPEC_LOONGSON_BIADD 515)
|
(UNSPEC_LOONGSON_PSADBH 516)
|
(UNSPEC_LOONGSON_PSADBH 516)
|
(UNSPEC_LOONGSON_PSHUFH 517)
|
(UNSPEC_LOONGSON_PSHUFH 517)
|
(UNSPEC_LOONGSON_PUNPCKH 518)
|
(UNSPEC_LOONGSON_PUNPCKH 518)
|
(UNSPEC_LOONGSON_PUNPCKL 519)
|
(UNSPEC_LOONGSON_PUNPCKL 519)
|
(UNSPEC_LOONGSON_PADDD 520)
|
(UNSPEC_LOONGSON_PADDD 520)
|
(UNSPEC_LOONGSON_PSUBD 521)
|
(UNSPEC_LOONGSON_PSUBD 521)
|
|
|
;; Used in loongson2ef.md
|
;; Used in loongson2ef.md
|
(UNSPEC_LOONGSON_ALU1_TURN_ENABLED_INSN 530)
|
(UNSPEC_LOONGSON_ALU1_TURN_ENABLED_INSN 530)
|
(UNSPEC_LOONGSON_ALU2_TURN_ENABLED_INSN 531)
|
(UNSPEC_LOONGSON_ALU2_TURN_ENABLED_INSN 531)
|
(UNSPEC_LOONGSON_FALU1_TURN_ENABLED_INSN 532)
|
(UNSPEC_LOONGSON_FALU1_TURN_ENABLED_INSN 532)
|
(UNSPEC_LOONGSON_FALU2_TURN_ENABLED_INSN 533)
|
(UNSPEC_LOONGSON_FALU2_TURN_ENABLED_INSN 533)
|
|
|
(UNSPEC_MIPS_CACHE 600)
|
(UNSPEC_MIPS_CACHE 600)
|
(UNSPEC_R10K_CACHE_BARRIER 601)
|
(UNSPEC_R10K_CACHE_BARRIER 601)
|
|
|
;; PIC long branch sequences are never longer than 100 bytes.
|
;; PIC long branch sequences are never longer than 100 bytes.
|
(MAX_PIC_BRANCH_LENGTH 100)
|
(MAX_PIC_BRANCH_LENGTH 100)
|
]
|
]
|
)
|
)
|
|
|
(include "predicates.md")
|
(include "predicates.md")
|
(include "constraints.md")
|
(include "constraints.md")
|
|
|
;; ....................
|
;; ....................
|
;;
|
;;
|
;; Attributes
|
;; Attributes
|
;;
|
;;
|
;; ....................
|
;; ....................
|
|
|
(define_attr "got" "unset,xgot_high,load"
|
(define_attr "got" "unset,xgot_high,load"
|
(const_string "unset"))
|
(const_string "unset"))
|
|
|
;; For jal instructions, this attribute is DIRECT when the target address
|
;; For jal instructions, this attribute is DIRECT when the target address
|
;; is symbolic and INDIRECT when it is a register.
|
;; is symbolic and INDIRECT when it is a register.
|
(define_attr "jal" "unset,direct,indirect"
|
(define_attr "jal" "unset,direct,indirect"
|
(const_string "unset"))
|
(const_string "unset"))
|
|
|
;; This attribute is YES if the instruction is a jal macro (not a
|
;; This attribute is YES if the instruction is a jal macro (not a
|
;; real jal instruction).
|
;; real jal instruction).
|
;;
|
;;
|
;; jal is always a macro for TARGET_CALL_CLOBBERED_GP because it includes
|
;; jal is always a macro for TARGET_CALL_CLOBBERED_GP because it includes
|
;; an instruction to restore $gp. Direct jals are also macros for
|
;; an instruction to restore $gp. Direct jals are also macros for
|
;; !TARGET_ABSOLUTE_JUMPS because they first load the target address
|
;; !TARGET_ABSOLUTE_JUMPS because they first load the target address
|
;; into a register.
|
;; into a register.
|
(define_attr "jal_macro" "no,yes"
|
(define_attr "jal_macro" "no,yes"
|
(cond [(eq_attr "jal" "direct")
|
(cond [(eq_attr "jal" "direct")
|
(symbol_ref "(TARGET_CALL_CLOBBERED_GP || !TARGET_ABSOLUTE_JUMPS
|
(symbol_ref "(TARGET_CALL_CLOBBERED_GP || !TARGET_ABSOLUTE_JUMPS
|
? JAL_MACRO_YES : JAL_MACRO_NO)")
|
? JAL_MACRO_YES : JAL_MACRO_NO)")
|
(eq_attr "jal" "indirect")
|
(eq_attr "jal" "indirect")
|
(symbol_ref "(TARGET_CALL_CLOBBERED_GP
|
(symbol_ref "(TARGET_CALL_CLOBBERED_GP
|
? JAL_MACRO_YES : JAL_MACRO_NO)")]
|
? JAL_MACRO_YES : JAL_MACRO_NO)")]
|
(const_string "no")))
|
(const_string "no")))
|
|
|
;; Classification of moves, extensions and truncations. Most values
|
;; Classification of moves, extensions and truncations. Most values
|
;; are as for "type" (see below) but there are also the following
|
;; are as for "type" (see below) but there are also the following
|
;; move-specific values:
|
;; move-specific values:
|
;;
|
;;
|
;; constN move an N-constraint integer into a MIPS16 register
|
;; constN move an N-constraint integer into a MIPS16 register
|
;; sll0 "sll DEST,SRC,0", which on 64-bit targets is guaranteed
|
;; sll0 "sll DEST,SRC,0", which on 64-bit targets is guaranteed
|
;; to produce a sign-extended DEST, even if SRC is not
|
;; to produce a sign-extended DEST, even if SRC is not
|
;; properly sign-extended
|
;; properly sign-extended
|
;; ext_ins EXT, DEXT, INS or DINS instruction
|
;; ext_ins EXT, DEXT, INS or DINS instruction
|
;; andi a single ANDI instruction
|
;; andi a single ANDI instruction
|
;; loadpool move a constant into a MIPS16 register by loading it
|
;; loadpool move a constant into a MIPS16 register by loading it
|
;; from the pool
|
;; from the pool
|
;; shift_shift a shift left followed by a shift right
|
;; shift_shift a shift left followed by a shift right
|
;; lui_movf an LUI followed by a MOVF (for d<-z CC moves)
|
;; lui_movf an LUI followed by a MOVF (for d<-z CC moves)
|
;;
|
;;
|
;; This attribute is used to determine the instruction's length and
|
;; This attribute is used to determine the instruction's length and
|
;; scheduling type. For doubleword moves, the attribute always describes
|
;; scheduling type. For doubleword moves, the attribute always describes
|
;; the split instructions; in some cases, it is more appropriate for the
|
;; the split instructions; in some cases, it is more appropriate for the
|
;; scheduling type to be "multi" instead.
|
;; scheduling type to be "multi" instead.
|
(define_attr "move_type"
|
(define_attr "move_type"
|
"unknown,load,fpload,store,fpstore,mtc,mfc,mthilo,mfhilo,move,fmove,
|
"unknown,load,fpload,store,fpstore,mtc,mfc,mthilo,mfhilo,move,fmove,
|
const,constN,signext,ext_ins,logical,arith,sll0,andi,loadpool,
|
const,constN,signext,ext_ins,logical,arith,sll0,andi,loadpool,
|
shift_shift,lui_movf"
|
shift_shift,lui_movf"
|
(const_string "unknown"))
|
(const_string "unknown"))
|
|
|
;; Main data type used by the insn
|
;; Main data type used by the insn
|
(define_attr "mode" "unknown,none,QI,HI,SI,DI,TI,SF,DF,TF,FPSW"
|
(define_attr "mode" "unknown,none,QI,HI,SI,DI,TI,SF,DF,TF,FPSW"
|
(const_string "unknown"))
|
(const_string "unknown"))
|
|
|
;; True if the main data type is twice the size of a word.
|
;; True if the main data type is twice the size of a word.
|
(define_attr "dword_mode" "no,yes"
|
(define_attr "dword_mode" "no,yes"
|
(cond [(and (eq_attr "mode" "DI,DF")
|
(cond [(and (eq_attr "mode" "DI,DF")
|
(eq (symbol_ref "TARGET_64BIT") (const_int 0)))
|
(eq (symbol_ref "TARGET_64BIT") (const_int 0)))
|
(const_string "yes")
|
(const_string "yes")
|
|
|
(and (eq_attr "mode" "TI,TF")
|
(and (eq_attr "mode" "TI,TF")
|
(ne (symbol_ref "TARGET_64BIT") (const_int 0)))
|
(ne (symbol_ref "TARGET_64BIT") (const_int 0)))
|
(const_string "yes")]
|
(const_string "yes")]
|
(const_string "no")))
|
(const_string "no")))
|
|
|
;; Classification of each insn.
|
;; Classification of each insn.
|
;; branch conditional branch
|
;; branch conditional branch
|
;; jump unconditional jump
|
;; jump unconditional jump
|
;; call unconditional call
|
;; call unconditional call
|
;; load load instruction(s)
|
;; load load instruction(s)
|
;; fpload floating point load
|
;; fpload floating point load
|
;; fpidxload floating point indexed load
|
;; fpidxload floating point indexed load
|
;; store store instruction(s)
|
;; store store instruction(s)
|
;; fpstore floating point store
|
;; fpstore floating point store
|
;; fpidxstore floating point indexed store
|
;; fpidxstore floating point indexed store
|
;; prefetch memory prefetch (register + offset)
|
;; prefetch memory prefetch (register + offset)
|
;; prefetchx memory indexed prefetch (register + register)
|
;; prefetchx memory indexed prefetch (register + register)
|
;; condmove conditional moves
|
;; condmove conditional moves
|
;; mtc transfer to coprocessor
|
;; mtc transfer to coprocessor
|
;; mfc transfer from coprocessor
|
;; mfc transfer from coprocessor
|
;; mthilo transfer to hi/lo registers
|
;; mthilo transfer to hi/lo registers
|
;; mfhilo transfer from hi/lo registers
|
;; mfhilo transfer from hi/lo registers
|
;; const load constant
|
;; const load constant
|
;; arith integer arithmetic instructions
|
;; arith integer arithmetic instructions
|
;; logical integer logical instructions
|
;; logical integer logical instructions
|
;; shift integer shift instructions
|
;; shift integer shift instructions
|
;; slt set less than instructions
|
;; slt set less than instructions
|
;; signext sign extend instructions
|
;; signext sign extend instructions
|
;; clz the clz and clo instructions
|
;; clz the clz and clo instructions
|
;; pop the pop instruction
|
;; pop the pop instruction
|
;; trap trap if instructions
|
;; trap trap if instructions
|
;; imul integer multiply 2 operands
|
;; imul integer multiply 2 operands
|
;; imul3 integer multiply 3 operands
|
;; imul3 integer multiply 3 operands
|
;; imul3nc integer multiply 3 operands without clobbering HI/LO
|
;; imul3nc integer multiply 3 operands without clobbering HI/LO
|
;; imadd integer multiply-add
|
;; imadd integer multiply-add
|
;; idiv integer divide 2 operands
|
;; idiv integer divide 2 operands
|
;; idiv3 integer divide 3 operands
|
;; idiv3 integer divide 3 operands
|
;; move integer register move ({,D}ADD{,U} with rt = 0)
|
;; move integer register move ({,D}ADD{,U} with rt = 0)
|
;; fmove floating point register move
|
;; fmove floating point register move
|
;; fadd floating point add/subtract
|
;; fadd floating point add/subtract
|
;; fmul floating point multiply
|
;; fmul floating point multiply
|
;; fmadd floating point multiply-add
|
;; fmadd floating point multiply-add
|
;; fdiv floating point divide
|
;; fdiv floating point divide
|
;; frdiv floating point reciprocal divide
|
;; frdiv floating point reciprocal divide
|
;; frdiv1 floating point reciprocal divide step 1
|
;; frdiv1 floating point reciprocal divide step 1
|
;; frdiv2 floating point reciprocal divide step 2
|
;; frdiv2 floating point reciprocal divide step 2
|
;; fabs floating point absolute value
|
;; fabs floating point absolute value
|
;; fneg floating point negation
|
;; fneg floating point negation
|
;; fcmp floating point compare
|
;; fcmp floating point compare
|
;; fcvt floating point convert
|
;; fcvt floating point convert
|
;; fsqrt floating point square root
|
;; fsqrt floating point square root
|
;; frsqrt floating point reciprocal square root
|
;; frsqrt floating point reciprocal square root
|
;; frsqrt1 floating point reciprocal square root step1
|
;; frsqrt1 floating point reciprocal square root step1
|
;; frsqrt2 floating point reciprocal square root step2
|
;; frsqrt2 floating point reciprocal square root step2
|
;; multi multiword sequence (or user asm statements)
|
;; multi multiword sequence (or user asm statements)
|
;; nop no operation
|
;; nop no operation
|
;; ghost an instruction that produces no real code
|
;; ghost an instruction that produces no real code
|
(define_attr "type"
|
(define_attr "type"
|
"unknown,branch,jump,call,load,fpload,fpidxload,store,fpstore,fpidxstore,
|
"unknown,branch,jump,call,load,fpload,fpidxload,store,fpstore,fpidxstore,
|
prefetch,prefetchx,condmove,mtc,mfc,mthilo,mfhilo,const,arith,logical,
|
prefetch,prefetchx,condmove,mtc,mfc,mthilo,mfhilo,const,arith,logical,
|
shift,slt,signext,clz,pop,trap,imul,imul3,imul3nc,imadd,idiv,idiv3,move,
|
shift,slt,signext,clz,pop,trap,imul,imul3,imul3nc,imadd,idiv,idiv3,move,
|
fmove,fadd,fmul,fmadd,fdiv,frdiv,frdiv1,frdiv2,fabs,fneg,fcmp,fcvt,fsqrt,
|
fmove,fadd,fmul,fmadd,fdiv,frdiv,frdiv1,frdiv2,fabs,fneg,fcmp,fcvt,fsqrt,
|
frsqrt,frsqrt1,frsqrt2,multi,nop,ghost"
|
frsqrt,frsqrt1,frsqrt2,multi,nop,ghost"
|
(cond [(eq_attr "jal" "!unset") (const_string "call")
|
(cond [(eq_attr "jal" "!unset") (const_string "call")
|
(eq_attr "got" "load") (const_string "load")
|
(eq_attr "got" "load") (const_string "load")
|
|
|
;; If a doubleword move uses these expensive instructions,
|
;; If a doubleword move uses these expensive instructions,
|
;; it is usually better to schedule them in the same way
|
;; it is usually better to schedule them in the same way
|
;; as the singleword form, rather than as "multi".
|
;; as the singleword form, rather than as "multi".
|
(eq_attr "move_type" "load") (const_string "load")
|
(eq_attr "move_type" "load") (const_string "load")
|
(eq_attr "move_type" "fpload") (const_string "fpload")
|
(eq_attr "move_type" "fpload") (const_string "fpload")
|
(eq_attr "move_type" "store") (const_string "store")
|
(eq_attr "move_type" "store") (const_string "store")
|
(eq_attr "move_type" "fpstore") (const_string "fpstore")
|
(eq_attr "move_type" "fpstore") (const_string "fpstore")
|
(eq_attr "move_type" "mtc") (const_string "mtc")
|
(eq_attr "move_type" "mtc") (const_string "mtc")
|
(eq_attr "move_type" "mfc") (const_string "mfc")
|
(eq_attr "move_type" "mfc") (const_string "mfc")
|
(eq_attr "move_type" "mthilo") (const_string "mthilo")
|
(eq_attr "move_type" "mthilo") (const_string "mthilo")
|
(eq_attr "move_type" "mfhilo") (const_string "mfhilo")
|
(eq_attr "move_type" "mfhilo") (const_string "mfhilo")
|
|
|
;; These types of move are always single insns.
|
;; These types of move are always single insns.
|
(eq_attr "move_type" "fmove") (const_string "fmove")
|
(eq_attr "move_type" "fmove") (const_string "fmove")
|
(eq_attr "move_type" "loadpool") (const_string "load")
|
(eq_attr "move_type" "loadpool") (const_string "load")
|
(eq_attr "move_type" "signext") (const_string "signext")
|
(eq_attr "move_type" "signext") (const_string "signext")
|
(eq_attr "move_type" "ext_ins") (const_string "arith")
|
(eq_attr "move_type" "ext_ins") (const_string "arith")
|
(eq_attr "move_type" "arith") (const_string "arith")
|
(eq_attr "move_type" "arith") (const_string "arith")
|
(eq_attr "move_type" "logical") (const_string "logical")
|
(eq_attr "move_type" "logical") (const_string "logical")
|
(eq_attr "move_type" "sll0") (const_string "shift")
|
(eq_attr "move_type" "sll0") (const_string "shift")
|
(eq_attr "move_type" "andi") (const_string "logical")
|
(eq_attr "move_type" "andi") (const_string "logical")
|
|
|
;; These types of move are always split.
|
;; These types of move are always split.
|
(eq_attr "move_type" "constN,shift_shift")
|
(eq_attr "move_type" "constN,shift_shift")
|
(const_string "multi")
|
(const_string "multi")
|
|
|
;; These types of move are split for doubleword modes only.
|
;; These types of move are split for doubleword modes only.
|
(and (eq_attr "move_type" "move,const")
|
(and (eq_attr "move_type" "move,const")
|
(eq_attr "dword_mode" "yes"))
|
(eq_attr "dword_mode" "yes"))
|
(const_string "multi")
|
(const_string "multi")
|
(eq_attr "move_type" "move") (const_string "move")
|
(eq_attr "move_type" "move") (const_string "move")
|
(eq_attr "move_type" "const") (const_string "const")]
|
(eq_attr "move_type" "const") (const_string "const")]
|
;; We classify "lui_movf" as "unknown" rather than "multi"
|
;; We classify "lui_movf" as "unknown" rather than "multi"
|
;; because we don't split it. FIXME: we should split instead.
|
;; because we don't split it. FIXME: we should split instead.
|
(const_string "unknown")))
|
(const_string "unknown")))
|
|
|
;; Mode for conversion types (fcvt)
|
;; Mode for conversion types (fcvt)
|
;; I2S integer to float single (SI/DI to SF)
|
;; I2S integer to float single (SI/DI to SF)
|
;; I2D integer to float double (SI/DI to DF)
|
;; I2D integer to float double (SI/DI to DF)
|
;; S2I float to integer (SF to SI/DI)
|
;; S2I float to integer (SF to SI/DI)
|
;; D2I float to integer (DF to SI/DI)
|
;; D2I float to integer (DF to SI/DI)
|
;; D2S double to float single
|
;; D2S double to float single
|
;; S2D float single to double
|
;; S2D float single to double
|
|
|
(define_attr "cnv_mode" "unknown,I2S,I2D,S2I,D2I,D2S,S2D"
|
(define_attr "cnv_mode" "unknown,I2S,I2D,S2I,D2I,D2S,S2D"
|
(const_string "unknown"))
|
(const_string "unknown"))
|
|
|
;; Is this an extended instruction in mips16 mode?
|
;; Is this an extended instruction in mips16 mode?
|
(define_attr "extended_mips16" "no,yes"
|
(define_attr "extended_mips16" "no,yes"
|
(if_then_else (ior (eq_attr "move_type" "sll0")
|
(if_then_else (ior (eq_attr "move_type" "sll0")
|
(eq_attr "type" "branch")
|
(eq_attr "type" "branch")
|
(eq_attr "jal" "direct"))
|
(eq_attr "jal" "direct"))
|
(const_string "yes")
|
(const_string "yes")
|
(const_string "no")))
|
(const_string "no")))
|
|
|
;; Attributes describing a sync loop. These loops have the form:
|
;; Attributes describing a sync loop. These loops have the form:
|
;;
|
;;
|
;; if (RELEASE_BARRIER == YES) sync
|
;; if (RELEASE_BARRIER == YES) sync
|
;; 1: OLDVAL = *MEM
|
;; 1: OLDVAL = *MEM
|
;; if ((OLDVAL & INCLUSIVE_MASK) != REQUIRED_OLDVAL) goto 2
|
;; if ((OLDVAL & INCLUSIVE_MASK) != REQUIRED_OLDVAL) goto 2
|
;; $TMP1 = OLDVAL & EXCLUSIVE_MASK
|
;; $TMP1 = OLDVAL & EXCLUSIVE_MASK
|
;; $TMP2 = INSN1 (OLDVAL, INSN1_OP2)
|
;; $TMP2 = INSN1 (OLDVAL, INSN1_OP2)
|
;; $TMP3 = INSN2 ($TMP2, INCLUSIVE_MASK)
|
;; $TMP3 = INSN2 ($TMP2, INCLUSIVE_MASK)
|
;; $AT |= $TMP1 | $TMP3
|
;; $AT |= $TMP1 | $TMP3
|
;; if (!commit (*MEM = $AT)) goto 1.
|
;; if (!commit (*MEM = $AT)) goto 1.
|
;; if (INSN1 != MOVE && INSN1 != LI) NEWVAL = $TMP3 [delay slot]
|
;; if (INSN1 != MOVE && INSN1 != LI) NEWVAL = $TMP3 [delay slot]
|
;; sync
|
;; sync
|
;; 2:
|
;; 2:
|
;;
|
;;
|
;; where "$" values are temporaries and where the other values are
|
;; where "$" values are temporaries and where the other values are
|
;; specified by the attributes below. Values are specified as operand
|
;; specified by the attributes below. Values are specified as operand
|
;; numbers and insns are specified as enums. If no operand number is
|
;; numbers and insns are specified as enums. If no operand number is
|
;; specified, the following values are used instead:
|
;; specified, the following values are used instead:
|
;;
|
;;
|
;; - OLDVAL: $AT
|
;; - OLDVAL: $AT
|
;; - NEWVAL: $AT
|
;; - NEWVAL: $AT
|
;; - INCLUSIVE_MASK: -1
|
;; - INCLUSIVE_MASK: -1
|
;; - REQUIRED_OLDVAL: OLDVAL & INCLUSIVE_MASK
|
;; - REQUIRED_OLDVAL: OLDVAL & INCLUSIVE_MASK
|
;; - EXCLUSIVE_MASK: 0
|
;; - EXCLUSIVE_MASK: 0
|
;;
|
;;
|
;; MEM and INSN1_OP2 are required.
|
;; MEM and INSN1_OP2 are required.
|
;;
|
;;
|
;; Ideally, the operand attributes would be integers, with -1 meaning "none",
|
;; Ideally, the operand attributes would be integers, with -1 meaning "none",
|
;; but the gen* programs don't yet support that.
|
;; but the gen* programs don't yet support that.
|
(define_attr "sync_mem" "none,0,1,2,3,4,5" (const_string "none"))
|
(define_attr "sync_mem" "none,0,1,2,3,4,5" (const_string "none"))
|
(define_attr "sync_oldval" "none,0,1,2,3,4,5" (const_string "none"))
|
(define_attr "sync_oldval" "none,0,1,2,3,4,5" (const_string "none"))
|
(define_attr "sync_newval" "none,0,1,2,3,4,5" (const_string "none"))
|
(define_attr "sync_newval" "none,0,1,2,3,4,5" (const_string "none"))
|
(define_attr "sync_inclusive_mask" "none,0,1,2,3,4,5" (const_string "none"))
|
(define_attr "sync_inclusive_mask" "none,0,1,2,3,4,5" (const_string "none"))
|
(define_attr "sync_exclusive_mask" "none,0,1,2,3,4,5" (const_string "none"))
|
(define_attr "sync_exclusive_mask" "none,0,1,2,3,4,5" (const_string "none"))
|
(define_attr "sync_required_oldval" "none,0,1,2,3,4,5" (const_string "none"))
|
(define_attr "sync_required_oldval" "none,0,1,2,3,4,5" (const_string "none"))
|
(define_attr "sync_insn1_op2" "none,0,1,2,3,4,5" (const_string "none"))
|
(define_attr "sync_insn1_op2" "none,0,1,2,3,4,5" (const_string "none"))
|
(define_attr "sync_insn1" "move,li,addu,addiu,subu,and,andi,or,ori,xor,xori"
|
(define_attr "sync_insn1" "move,li,addu,addiu,subu,and,andi,or,ori,xor,xori"
|
(const_string "move"))
|
(const_string "move"))
|
(define_attr "sync_insn2" "nop,and,xor,not"
|
(define_attr "sync_insn2" "nop,and,xor,not"
|
(const_string "nop"))
|
(const_string "nop"))
|
(define_attr "sync_release_barrier" "yes,no"
|
(define_attr "sync_release_barrier" "yes,no"
|
(const_string "yes"))
|
(const_string "yes"))
|
|
|
;; Length of instruction in bytes.
|
;; Length of instruction in bytes.
|
(define_attr "length" ""
|
(define_attr "length" ""
|
(cond [(and (eq_attr "extended_mips16" "yes")
|
(cond [(and (eq_attr "extended_mips16" "yes")
|
(ne (symbol_ref "TARGET_MIPS16") (const_int 0)))
|
(ne (symbol_ref "TARGET_MIPS16") (const_int 0)))
|
(const_int 8)
|
(const_int 8)
|
|
|
;; Direct branch instructions have a range of [-0x20000,0x1fffc],
|
;; Direct branch instructions have a range of [-0x20000,0x1fffc],
|
;; relative to the address of the delay slot. If a branch is
|
;; relative to the address of the delay slot. If a branch is
|
;; outside this range, we have a choice of two sequences.
|
;; outside this range, we have a choice of two sequences.
|
;; For PIC, an out-of-range branch like:
|
;; For PIC, an out-of-range branch like:
|
;;
|
;;
|
;; bne r1,r2,target
|
;; bne r1,r2,target
|
;; dslot
|
;; dslot
|
;;
|
;;
|
;; becomes the equivalent of:
|
;; becomes the equivalent of:
|
;;
|
;;
|
;; beq r1,r2,1f
|
;; beq r1,r2,1f
|
;; dslot
|
;; dslot
|
;; la $at,target
|
;; la $at,target
|
;; jr $at
|
;; jr $at
|
;; nop
|
;; nop
|
;; 1:
|
;; 1:
|
;;
|
;;
|
;; The non-PIC case is similar except that we use a direct
|
;; The non-PIC case is similar except that we use a direct
|
;; jump instead of an la/jr pair. Since the target of this
|
;; jump instead of an la/jr pair. Since the target of this
|
;; jump is an absolute 28-bit bit address (the other bits
|
;; jump is an absolute 28-bit bit address (the other bits
|
;; coming from the address of the delay slot) this form cannot
|
;; coming from the address of the delay slot) this form cannot
|
;; cross a 256MB boundary. We could provide the option of
|
;; cross a 256MB boundary. We could provide the option of
|
;; using la/jr in this case too, but we do not do so at
|
;; using la/jr in this case too, but we do not do so at
|
;; present.
|
;; present.
|
;;
|
;;
|
;; Note that this value does not account for the delay slot
|
;; Note that this value does not account for the delay slot
|
;; instruction, whose length is added separately. If the RTL
|
;; instruction, whose length is added separately. If the RTL
|
;; pattern has no explicit delay slot, mips_adjust_insn_length
|
;; pattern has no explicit delay slot, mips_adjust_insn_length
|
;; will add the length of the implicit nop. The values for
|
;; will add the length of the implicit nop. The values for
|
;; forward and backward branches will be different as well.
|
;; forward and backward branches will be different as well.
|
(eq_attr "type" "branch")
|
(eq_attr "type" "branch")
|
(cond [(and (le (minus (match_dup 0) (pc)) (const_int 131064))
|
(cond [(and (le (minus (match_dup 0) (pc)) (const_int 131064))
|
(le (minus (pc) (match_dup 0)) (const_int 131068)))
|
(le (minus (pc) (match_dup 0)) (const_int 131068)))
|
(const_int 4)
|
(const_int 4)
|
|
|
;; The non-PIC case: branch, first delay slot, and J.
|
;; The non-PIC case: branch, first delay slot, and J.
|
(ne (symbol_ref "TARGET_ABSOLUTE_JUMPS") (const_int 0))
|
(ne (symbol_ref "TARGET_ABSOLUTE_JUMPS") (const_int 0))
|
(const_int 12)]
|
(const_int 12)]
|
|
|
;; Use MAX_PIC_BRANCH_LENGTH as a (gross) overestimate.
|
;; Use MAX_PIC_BRANCH_LENGTH as a (gross) overestimate.
|
;; mips_adjust_insn_length substitutes the correct length.
|
;; mips_adjust_insn_length substitutes the correct length.
|
;;
|
;;
|
;; Note that we can't simply use (symbol_ref ...) here
|
;; Note that we can't simply use (symbol_ref ...) here
|
;; because genattrtab needs to know the maximum length
|
;; because genattrtab needs to know the maximum length
|
;; of an insn.
|
;; of an insn.
|
(const_int MAX_PIC_BRANCH_LENGTH))
|
(const_int MAX_PIC_BRANCH_LENGTH))
|
|
|
;; "Ghost" instructions occupy no space.
|
;; "Ghost" instructions occupy no space.
|
(eq_attr "type" "ghost")
|
(eq_attr "type" "ghost")
|
(const_int 0)
|
(const_int 0)
|
|
|
(eq_attr "got" "load")
|
(eq_attr "got" "load")
|
(if_then_else (ne (symbol_ref "TARGET_MIPS16") (const_int 0))
|
(if_then_else (ne (symbol_ref "TARGET_MIPS16") (const_int 0))
|
(const_int 8)
|
(const_int 8)
|
(const_int 4))
|
(const_int 4))
|
(eq_attr "got" "xgot_high")
|
(eq_attr "got" "xgot_high")
|
(const_int 8)
|
(const_int 8)
|
|
|
;; In general, constant-pool loads are extended instructions.
|
;; In general, constant-pool loads are extended instructions.
|
(eq_attr "move_type" "loadpool")
|
(eq_attr "move_type" "loadpool")
|
(const_int 8)
|
(const_int 8)
|
|
|
;; LUI_MOVFs are decomposed into two separate instructions.
|
;; LUI_MOVFs are decomposed into two separate instructions.
|
(eq_attr "move_type" "lui_movf")
|
(eq_attr "move_type" "lui_movf")
|
(const_int 8)
|
(const_int 8)
|
|
|
;; SHIFT_SHIFTs are decomposed into two separate instructions.
|
;; SHIFT_SHIFTs are decomposed into two separate instructions.
|
;; They are extended instructions on MIPS16 targets.
|
;; They are extended instructions on MIPS16 targets.
|
(eq_attr "move_type" "shift_shift")
|
(eq_attr "move_type" "shift_shift")
|
(if_then_else (ne (symbol_ref "TARGET_MIPS16") (const_int 0))
|
(if_then_else (ne (symbol_ref "TARGET_MIPS16") (const_int 0))
|
(const_int 16)
|
(const_int 16)
|
(const_int 8))
|
(const_int 8))
|
|
|
;; Check for doubleword moves that are decomposed into two
|
;; Check for doubleword moves that are decomposed into two
|
;; instructions.
|
;; instructions.
|
(and (eq_attr "move_type" "mtc,mfc,mthilo,mfhilo,move")
|
(and (eq_attr "move_type" "mtc,mfc,mthilo,mfhilo,move")
|
(eq_attr "dword_mode" "yes"))
|
(eq_attr "dword_mode" "yes"))
|
(const_int 8)
|
(const_int 8)
|
|
|
;; Doubleword CONST{,N} moves are split into two word
|
;; Doubleword CONST{,N} moves are split into two word
|
;; CONST{,N} moves.
|
;; CONST{,N} moves.
|
(and (eq_attr "move_type" "const,constN")
|
(and (eq_attr "move_type" "const,constN")
|
(eq_attr "dword_mode" "yes"))
|
(eq_attr "dword_mode" "yes"))
|
(symbol_ref "mips_split_const_insns (operands[1]) * 4")
|
(symbol_ref "mips_split_const_insns (operands[1]) * 4")
|
|
|
;; Otherwise, constants, loads and stores are handled by external
|
;; Otherwise, constants, loads and stores are handled by external
|
;; routines.
|
;; routines.
|
(eq_attr "move_type" "const,constN")
|
(eq_attr "move_type" "const,constN")
|
(symbol_ref "mips_const_insns (operands[1]) * 4")
|
(symbol_ref "mips_const_insns (operands[1]) * 4")
|
(eq_attr "move_type" "load,fpload")
|
(eq_attr "move_type" "load,fpload")
|
(symbol_ref "mips_load_store_insns (operands[1], insn) * 4")
|
(symbol_ref "mips_load_store_insns (operands[1], insn) * 4")
|
(eq_attr "move_type" "store,fpstore")
|
(eq_attr "move_type" "store,fpstore")
|
(symbol_ref "mips_load_store_insns (operands[0], insn) * 4")
|
(symbol_ref "mips_load_store_insns (operands[0], insn) * 4")
|
|
|
;; In the worst case, a call macro will take 8 instructions:
|
;; In the worst case, a call macro will take 8 instructions:
|
;;
|
;;
|
;; lui $25,%call_hi(FOO)
|
;; lui $25,%call_hi(FOO)
|
;; addu $25,$25,$28
|
;; addu $25,$25,$28
|
;; lw $25,%call_lo(FOO)($25)
|
;; lw $25,%call_lo(FOO)($25)
|
;; nop
|
;; nop
|
;; jalr $25
|
;; jalr $25
|
;; nop
|
;; nop
|
;; lw $gp,X($sp)
|
;; lw $gp,X($sp)
|
;; nop
|
;; nop
|
(eq_attr "jal_macro" "yes")
|
(eq_attr "jal_macro" "yes")
|
(const_int 32)
|
(const_int 32)
|
|
|
;; Various VR4120 errata require a nop to be inserted after a macc
|
;; Various VR4120 errata require a nop to be inserted after a macc
|
;; instruction. The assembler does this for us, so account for
|
;; instruction. The assembler does this for us, so account for
|
;; the worst-case length here.
|
;; the worst-case length here.
|
(and (eq_attr "type" "imadd")
|
(and (eq_attr "type" "imadd")
|
(ne (symbol_ref "TARGET_FIX_VR4120") (const_int 0)))
|
(ne (symbol_ref "TARGET_FIX_VR4120") (const_int 0)))
|
(const_int 8)
|
(const_int 8)
|
|
|
;; VR4120 errata MD(4): if there are consecutive dmult instructions,
|
;; VR4120 errata MD(4): if there are consecutive dmult instructions,
|
;; the result of the second one is missed. The assembler should work
|
;; the result of the second one is missed. The assembler should work
|
;; around this by inserting a nop after the first dmult.
|
;; around this by inserting a nop after the first dmult.
|
(and (eq_attr "type" "imul,imul3")
|
(and (eq_attr "type" "imul,imul3")
|
(and (eq_attr "mode" "DI")
|
(and (eq_attr "mode" "DI")
|
(ne (symbol_ref "TARGET_FIX_VR4120") (const_int 0))))
|
(ne (symbol_ref "TARGET_FIX_VR4120") (const_int 0))))
|
(const_int 8)
|
(const_int 8)
|
|
|
(eq_attr "type" "idiv,idiv3")
|
(eq_attr "type" "idiv,idiv3")
|
(symbol_ref "mips_idiv_insns () * 4")
|
(symbol_ref "mips_idiv_insns () * 4")
|
|
|
(not (eq_attr "sync_mem" "none"))
|
(not (eq_attr "sync_mem" "none"))
|
(symbol_ref "mips_sync_loop_insns (insn, operands) * 4")
|
(symbol_ref "mips_sync_loop_insns (insn, operands) * 4")
|
] (const_int 4)))
|
] (const_int 4)))
|
|
|
;; Attribute describing the processor. This attribute must match exactly
|
;; Attribute describing the processor. This attribute must match exactly
|
;; with the processor_type enumeration in mips.h.
|
;; with the processor_type enumeration in mips.h.
|
(define_attr "cpu"
|
(define_attr "cpu"
|
"r3000,4kc,4kp,5kc,5kf,20kc,24kc,24kf2_1,24kf1_1,74kc,74kf2_1,74kf1_1,74kf3_2,loongson_2e,loongson_2f,m4k,octeon,r3900,r6000,r4000,r4100,r4111,r4120,r4130,r4300,r4600,r4650,r5000,r5400,r5500,r7000,r8000,r9000,r10000,sb1,sb1a,sr71000,xlr"
|
"r3000,4kc,4kp,5kc,5kf,20kc,24kc,24kf2_1,24kf1_1,74kc,74kf2_1,74kf1_1,74kf3_2,loongson_2e,loongson_2f,m4k,octeon,r3900,r6000,r4000,r4100,r4111,r4120,r4130,r4300,r4600,r4650,r5000,r5400,r5500,r7000,r8000,r9000,r10000,sb1,sb1a,sr71000,xlr"
|
(const (symbol_ref "mips_tune_attr")))
|
(const (symbol_ref "mips_tune_attr")))
|
|
|
;; The type of hardware hazard associated with this instruction.
|
;; The type of hardware hazard associated with this instruction.
|
;; DELAY means that the next instruction cannot read the result
|
;; DELAY means that the next instruction cannot read the result
|
;; of this one. HILO means that the next two instructions cannot
|
;; of this one. HILO means that the next two instructions cannot
|
;; write to HI or LO.
|
;; write to HI or LO.
|
(define_attr "hazard" "none,delay,hilo"
|
(define_attr "hazard" "none,delay,hilo"
|
(cond [(and (eq_attr "type" "load,fpload,fpidxload")
|
(cond [(and (eq_attr "type" "load,fpload,fpidxload")
|
(ne (symbol_ref "ISA_HAS_LOAD_DELAY") (const_int 0)))
|
(ne (symbol_ref "ISA_HAS_LOAD_DELAY") (const_int 0)))
|
(const_string "delay")
|
(const_string "delay")
|
|
|
(and (eq_attr "type" "mfc,mtc")
|
(and (eq_attr "type" "mfc,mtc")
|
(ne (symbol_ref "ISA_HAS_XFER_DELAY") (const_int 0)))
|
(ne (symbol_ref "ISA_HAS_XFER_DELAY") (const_int 0)))
|
(const_string "delay")
|
(const_string "delay")
|
|
|
(and (eq_attr "type" "fcmp")
|
(and (eq_attr "type" "fcmp")
|
(ne (symbol_ref "ISA_HAS_FCMP_DELAY") (const_int 0)))
|
(ne (symbol_ref "ISA_HAS_FCMP_DELAY") (const_int 0)))
|
(const_string "delay")
|
(const_string "delay")
|
|
|
;; The r4000 multiplication patterns include an mflo instruction.
|
;; The r4000 multiplication patterns include an mflo instruction.
|
(and (eq_attr "type" "imul")
|
(and (eq_attr "type" "imul")
|
(ne (symbol_ref "TARGET_FIX_R4000") (const_int 0)))
|
(ne (symbol_ref "TARGET_FIX_R4000") (const_int 0)))
|
(const_string "hilo")
|
(const_string "hilo")
|
|
|
(and (eq_attr "type" "mfhilo")
|
(and (eq_attr "type" "mfhilo")
|
(eq (symbol_ref "ISA_HAS_HILO_INTERLOCKS") (const_int 0)))
|
(eq (symbol_ref "ISA_HAS_HILO_INTERLOCKS") (const_int 0)))
|
(const_string "hilo")]
|
(const_string "hilo")]
|
(const_string "none")))
|
(const_string "none")))
|
|
|
;; Is it a single instruction?
|
;; Is it a single instruction?
|
(define_attr "single_insn" "no,yes"
|
(define_attr "single_insn" "no,yes"
|
(symbol_ref "(get_attr_length (insn) == (TARGET_MIPS16 ? 2 : 4)
|
(symbol_ref "(get_attr_length (insn) == (TARGET_MIPS16 ? 2 : 4)
|
? SINGLE_INSN_YES : SINGLE_INSN_NO)"))
|
? SINGLE_INSN_YES : SINGLE_INSN_NO)"))
|
|
|
;; Can the instruction be put into a delay slot?
|
;; Can the instruction be put into a delay slot?
|
(define_attr "can_delay" "no,yes"
|
(define_attr "can_delay" "no,yes"
|
(if_then_else (and (eq_attr "type" "!branch,call,jump")
|
(if_then_else (and (eq_attr "type" "!branch,call,jump")
|
(and (eq_attr "hazard" "none")
|
(and (eq_attr "hazard" "none")
|
(eq_attr "single_insn" "yes")))
|
(eq_attr "single_insn" "yes")))
|
(const_string "yes")
|
(const_string "yes")
|
(const_string "no")))
|
(const_string "no")))
|
|
|
;; Attribute defining whether or not we can use the branch-likely
|
;; Attribute defining whether or not we can use the branch-likely
|
;; instructions.
|
;; instructions.
|
(define_attr "branch_likely" "no,yes"
|
(define_attr "branch_likely" "no,yes"
|
(if_then_else (ne (symbol_ref "GENERATE_BRANCHLIKELY") (const_int 0))
|
(if_then_else (ne (symbol_ref "GENERATE_BRANCHLIKELY") (const_int 0))
|
(const_string "yes")
|
(const_string "yes")
|
(const_string "no")))
|
(const_string "no")))
|
|
|
;; True if an instruction might assign to hi or lo when reloaded.
|
;; True if an instruction might assign to hi or lo when reloaded.
|
;; This is used by the TUNE_MACC_CHAINS code.
|
;; This is used by the TUNE_MACC_CHAINS code.
|
(define_attr "may_clobber_hilo" "no,yes"
|
(define_attr "may_clobber_hilo" "no,yes"
|
(if_then_else (eq_attr "type" "imul,imul3,imadd,idiv,mthilo")
|
(if_then_else (eq_attr "type" "imul,imul3,imadd,idiv,mthilo")
|
(const_string "yes")
|
(const_string "yes")
|
(const_string "no")))
|
(const_string "no")))
|
|
|
;; Describe a user's asm statement.
|
;; Describe a user's asm statement.
|
(define_asm_attributes
|
(define_asm_attributes
|
[(set_attr "type" "multi")
|
[(set_attr "type" "multi")
|
(set_attr "can_delay" "no")])
|
(set_attr "can_delay" "no")])
|
|
|
;; This mode iterator allows 32-bit and 64-bit GPR patterns to be generated
|
;; This mode iterator allows 32-bit and 64-bit GPR patterns to be generated
|
;; from the same template.
|
;; from the same template.
|
(define_mode_iterator GPR [SI (DI "TARGET_64BIT")])
|
(define_mode_iterator GPR [SI (DI "TARGET_64BIT")])
|
|
|
;; A copy of GPR that can be used when a pattern has two independent
|
;; A copy of GPR that can be used when a pattern has two independent
|
;; modes.
|
;; modes.
|
(define_mode_iterator GPR2 [SI (DI "TARGET_64BIT")])
|
(define_mode_iterator GPR2 [SI (DI "TARGET_64BIT")])
|
|
|
;; This mode iterator allows :HILO to be used as the mode of the
|
;; This mode iterator allows :HILO to be used as the mode of the
|
;; concatenated HI and LO registers.
|
;; concatenated HI and LO registers.
|
(define_mode_iterator HILO [(DI "!TARGET_64BIT") (TI "TARGET_64BIT")])
|
(define_mode_iterator HILO [(DI "!TARGET_64BIT") (TI "TARGET_64BIT")])
|
|
|
;; This mode iterator allows :P to be used for patterns that operate on
|
;; This mode iterator allows :P to be used for patterns that operate on
|
;; pointer-sized quantities. Exactly one of the two alternatives will match.
|
;; pointer-sized quantities. Exactly one of the two alternatives will match.
|
(define_mode_iterator P [(SI "Pmode == SImode") (DI "Pmode == DImode")])
|
(define_mode_iterator P [(SI "Pmode == SImode") (DI "Pmode == DImode")])
|
|
|
;; This mode iterator allows :MOVECC to be used anywhere that a
|
;; This mode iterator allows :MOVECC to be used anywhere that a
|
;; conditional-move-type condition is needed.
|
;; conditional-move-type condition is needed.
|
(define_mode_iterator MOVECC [SI (DI "TARGET_64BIT")
|
(define_mode_iterator MOVECC [SI (DI "TARGET_64BIT")
|
(CC "TARGET_HARD_FLOAT && !TARGET_LOONGSON_2EF")])
|
(CC "TARGET_HARD_FLOAT && !TARGET_LOONGSON_2EF")])
|
|
|
;; 32-bit integer moves for which we provide move patterns.
|
;; 32-bit integer moves for which we provide move patterns.
|
(define_mode_iterator IMOVE32
|
(define_mode_iterator IMOVE32
|
[SI
|
[SI
|
(V2HI "TARGET_DSP")
|
(V2HI "TARGET_DSP")
|
(V4QI "TARGET_DSP")
|
(V4QI "TARGET_DSP")
|
(V2HQ "TARGET_DSP")
|
(V2HQ "TARGET_DSP")
|
(V2UHQ "TARGET_DSP")
|
(V2UHQ "TARGET_DSP")
|
(V2HA "TARGET_DSP")
|
(V2HA "TARGET_DSP")
|
(V2UHA "TARGET_DSP")
|
(V2UHA "TARGET_DSP")
|
(V4QQ "TARGET_DSP")
|
(V4QQ "TARGET_DSP")
|
(V4UQQ "TARGET_DSP")])
|
(V4UQQ "TARGET_DSP")])
|
|
|
;; 64-bit modes for which we provide move patterns.
|
;; 64-bit modes for which we provide move patterns.
|
(define_mode_iterator MOVE64
|
(define_mode_iterator MOVE64
|
[DI DF
|
[DI DF
|
(V2SF "TARGET_HARD_FLOAT && TARGET_PAIRED_SINGLE_FLOAT")
|
(V2SF "TARGET_HARD_FLOAT && TARGET_PAIRED_SINGLE_FLOAT")
|
(V2SI "TARGET_HARD_FLOAT && TARGET_LOONGSON_VECTORS")
|
(V2SI "TARGET_HARD_FLOAT && TARGET_LOONGSON_VECTORS")
|
(V4HI "TARGET_HARD_FLOAT && TARGET_LOONGSON_VECTORS")
|
(V4HI "TARGET_HARD_FLOAT && TARGET_LOONGSON_VECTORS")
|
(V8QI "TARGET_HARD_FLOAT && TARGET_LOONGSON_VECTORS")])
|
(V8QI "TARGET_HARD_FLOAT && TARGET_LOONGSON_VECTORS")])
|
|
|
;; 128-bit modes for which we provide move patterns on 64-bit targets.
|
;; 128-bit modes for which we provide move patterns on 64-bit targets.
|
(define_mode_iterator MOVE128 [TI TF])
|
(define_mode_iterator MOVE128 [TI TF])
|
|
|
;; This mode iterator allows the QI and HI extension patterns to be
|
;; This mode iterator allows the QI and HI extension patterns to be
|
;; defined from the same template.
|
;; defined from the same template.
|
(define_mode_iterator SHORT [QI HI])
|
(define_mode_iterator SHORT [QI HI])
|
|
|
;; Likewise the 64-bit truncate-and-shift patterns.
|
;; Likewise the 64-bit truncate-and-shift patterns.
|
(define_mode_iterator SUBDI [QI HI SI])
|
(define_mode_iterator SUBDI [QI HI SI])
|
|
|
;; This mode iterator allows :ANYF to be used wherever a scalar or vector
|
;; This mode iterator allows :ANYF to be used wherever a scalar or vector
|
;; floating-point mode is allowed.
|
;; floating-point mode is allowed.
|
(define_mode_iterator ANYF [(SF "TARGET_HARD_FLOAT")
|
(define_mode_iterator ANYF [(SF "TARGET_HARD_FLOAT")
|
(DF "TARGET_HARD_FLOAT && TARGET_DOUBLE_FLOAT")
|
(DF "TARGET_HARD_FLOAT && TARGET_DOUBLE_FLOAT")
|
(V2SF "TARGET_HARD_FLOAT && TARGET_PAIRED_SINGLE_FLOAT")])
|
(V2SF "TARGET_HARD_FLOAT && TARGET_PAIRED_SINGLE_FLOAT")])
|
|
|
;; Like ANYF, but only applies to scalar modes.
|
;; Like ANYF, but only applies to scalar modes.
|
(define_mode_iterator SCALARF [(SF "TARGET_HARD_FLOAT")
|
(define_mode_iterator SCALARF [(SF "TARGET_HARD_FLOAT")
|
(DF "TARGET_HARD_FLOAT && TARGET_DOUBLE_FLOAT")])
|
(DF "TARGET_HARD_FLOAT && TARGET_DOUBLE_FLOAT")])
|
|
|
;; A floating-point mode for which moves involving FPRs may need to be split.
|
;; A floating-point mode for which moves involving FPRs may need to be split.
|
(define_mode_iterator SPLITF
|
(define_mode_iterator SPLITF
|
[(DF "!TARGET_64BIT && TARGET_DOUBLE_FLOAT")
|
[(DF "!TARGET_64BIT && TARGET_DOUBLE_FLOAT")
|
(DI "!TARGET_64BIT && TARGET_DOUBLE_FLOAT")
|
(DI "!TARGET_64BIT && TARGET_DOUBLE_FLOAT")
|
(V2SF "!TARGET_64BIT && TARGET_PAIRED_SINGLE_FLOAT")
|
(V2SF "!TARGET_64BIT && TARGET_PAIRED_SINGLE_FLOAT")
|
(V2SI "!TARGET_64BIT && TARGET_LOONGSON_VECTORS")
|
(V2SI "!TARGET_64BIT && TARGET_LOONGSON_VECTORS")
|
(V4HI "!TARGET_64BIT && TARGET_LOONGSON_VECTORS")
|
(V4HI "!TARGET_64BIT && TARGET_LOONGSON_VECTORS")
|
(V8QI "!TARGET_64BIT && TARGET_LOONGSON_VECTORS")
|
(V8QI "!TARGET_64BIT && TARGET_LOONGSON_VECTORS")
|
(TF "TARGET_64BIT && TARGET_FLOAT64")])
|
(TF "TARGET_64BIT && TARGET_FLOAT64")])
|
|
|
;; In GPR templates, a string like "subu" will expand to "subu" in the
|
;; In GPR templates, a string like "subu" will expand to "subu" in the
|
;; 32-bit version and "dsubu" in the 64-bit version.
|
;; 32-bit version and "dsubu" in the 64-bit version.
|
(define_mode_attr d [(SI "") (DI "d")
|
(define_mode_attr d [(SI "") (DI "d")
|
(QQ "") (HQ "") (SQ "") (DQ "d")
|
(QQ "") (HQ "") (SQ "") (DQ "d")
|
(UQQ "") (UHQ "") (USQ "") (UDQ "d")
|
(UQQ "") (UHQ "") (USQ "") (UDQ "d")
|
(HA "") (SA "") (DA "d")
|
(HA "") (SA "") (DA "d")
|
(UHA "") (USA "") (UDA "d")])
|
(UHA "") (USA "") (UDA "d")])
|
|
|
;; Same as d but upper-case.
|
;; Same as d but upper-case.
|
(define_mode_attr D [(SI "") (DI "D")
|
(define_mode_attr D [(SI "") (DI "D")
|
(QQ "") (HQ "") (SQ "") (DQ "D")
|
(QQ "") (HQ "") (SQ "") (DQ "D")
|
(UQQ "") (UHQ "") (USQ "") (UDQ "D")
|
(UQQ "") (UHQ "") (USQ "") (UDQ "D")
|
(HA "") (SA "") (DA "D")
|
(HA "") (SA "") (DA "D")
|
(UHA "") (USA "") (UDA "D")])
|
(UHA "") (USA "") (UDA "D")])
|
|
|
;; This attribute gives the length suffix for a sign- or zero-extension
|
;; This attribute gives the length suffix for a sign- or zero-extension
|
;; instruction.
|
;; instruction.
|
(define_mode_attr size [(QI "b") (HI "h")])
|
(define_mode_attr size [(QI "b") (HI "h")])
|
|
|
;; This attributes gives the mode mask of a SHORT.
|
;; This attributes gives the mode mask of a SHORT.
|
(define_mode_attr mask [(QI "0x00ff") (HI "0xffff")])
|
(define_mode_attr mask [(QI "0x00ff") (HI "0xffff")])
|
|
|
;; Mode attributes for GPR loads.
|
;; Mode attributes for GPR loads.
|
(define_mode_attr load [(SI "lw") (DI "ld")])
|
(define_mode_attr load [(SI "lw") (DI "ld")])
|
;; Instruction names for stores.
|
;; Instruction names for stores.
|
(define_mode_attr store [(QI "sb") (HI "sh") (SI "sw") (DI "sd")])
|
(define_mode_attr store [(QI "sb") (HI "sh") (SI "sw") (DI "sd")])
|
|
|
;; Similarly for MIPS IV indexed FPR loads and stores.
|
;; Similarly for MIPS IV indexed FPR loads and stores.
|
(define_mode_attr loadx [(SF "lwxc1") (DF "ldxc1") (V2SF "ldxc1")])
|
(define_mode_attr loadx [(SF "lwxc1") (DF "ldxc1") (V2SF "ldxc1")])
|
(define_mode_attr storex [(SF "swxc1") (DF "sdxc1") (V2SF "sdxc1")])
|
(define_mode_attr storex [(SF "swxc1") (DF "sdxc1") (V2SF "sdxc1")])
|
|
|
;; The unextended ranges of the MIPS16 addiu and daddiu instructions
|
;; The unextended ranges of the MIPS16 addiu and daddiu instructions
|
;; are different. Some forms of unextended addiu have an 8-bit immediate
|
;; are different. Some forms of unextended addiu have an 8-bit immediate
|
;; field but the equivalent daddiu has only a 5-bit field.
|
;; field but the equivalent daddiu has only a 5-bit field.
|
(define_mode_attr si8_di5 [(SI "8") (DI "5")])
|
(define_mode_attr si8_di5 [(SI "8") (DI "5")])
|
|
|
;; This attribute gives the best constraint to use for registers of
|
;; This attribute gives the best constraint to use for registers of
|
;; a given mode.
|
;; a given mode.
|
(define_mode_attr reg [(SI "d") (DI "d") (CC "z")])
|
(define_mode_attr reg [(SI "d") (DI "d") (CC "z")])
|
|
|
;; This attribute gives the format suffix for floating-point operations.
|
;; This attribute gives the format suffix for floating-point operations.
|
(define_mode_attr fmt [(SF "s") (DF "d") (V2SF "ps")])
|
(define_mode_attr fmt [(SF "s") (DF "d") (V2SF "ps")])
|
|
|
;; This attribute gives the upper-case mode name for one unit of a
|
;; This attribute gives the upper-case mode name for one unit of a
|
;; floating-point mode.
|
;; floating-point mode.
|
(define_mode_attr UNITMODE [(SF "SF") (DF "DF") (V2SF "SF")])
|
(define_mode_attr UNITMODE [(SF "SF") (DF "DF") (V2SF "SF")])
|
|
|
;; This attribute gives the integer mode that has the same size as a
|
;; This attribute gives the integer mode that has the same size as a
|
;; fixed-point mode.
|
;; fixed-point mode.
|
(define_mode_attr IMODE [(QQ "QI") (HQ "HI") (SQ "SI") (DQ "DI")
|
(define_mode_attr IMODE [(QQ "QI") (HQ "HI") (SQ "SI") (DQ "DI")
|
(UQQ "QI") (UHQ "HI") (USQ "SI") (UDQ "DI")
|
(UQQ "QI") (UHQ "HI") (USQ "SI") (UDQ "DI")
|
(HA "HI") (SA "SI") (DA "DI")
|
(HA "HI") (SA "SI") (DA "DI")
|
(UHA "HI") (USA "SI") (UDA "DI")
|
(UHA "HI") (USA "SI") (UDA "DI")
|
(V4UQQ "SI") (V2UHQ "SI") (V2UHA "SI")
|
(V4UQQ "SI") (V2UHQ "SI") (V2UHA "SI")
|
(V2HQ "SI") (V2HA "SI")])
|
(V2HQ "SI") (V2HA "SI")])
|
|
|
;; This attribute gives the integer mode that has half the size of
|
;; This attribute gives the integer mode that has half the size of
|
;; the controlling mode.
|
;; the controlling mode.
|
(define_mode_attr HALFMODE [(DF "SI") (DI "SI") (V2SF "SI")
|
(define_mode_attr HALFMODE [(DF "SI") (DI "SI") (V2SF "SI")
|
(V2SI "SI") (V4HI "SI") (V8QI "SI")
|
(V2SI "SI") (V4HI "SI") (V8QI "SI")
|
(TF "DI")])
|
(TF "DI")])
|
|
|
;; This attribute works around the early SB-1 rev2 core "F2" erratum:
|
;; This attribute works around the early SB-1 rev2 core "F2" erratum:
|
;;
|
;;
|
;; In certain cases, div.s and div.ps may have a rounding error
|
;; In certain cases, div.s and div.ps may have a rounding error
|
;; and/or wrong inexact flag.
|
;; and/or wrong inexact flag.
|
;;
|
;;
|
;; Therefore, we only allow div.s if not working around SB-1 rev2
|
;; Therefore, we only allow div.s if not working around SB-1 rev2
|
;; errata or if a slight loss of precision is OK.
|
;; errata or if a slight loss of precision is OK.
|
(define_mode_attr divide_condition
|
(define_mode_attr divide_condition
|
[DF (SF "!TARGET_FIX_SB1 || flag_unsafe_math_optimizations")
|
[DF (SF "!TARGET_FIX_SB1 || flag_unsafe_math_optimizations")
|
(V2SF "TARGET_SB1 && (!TARGET_FIX_SB1 || flag_unsafe_math_optimizations)")])
|
(V2SF "TARGET_SB1 && (!TARGET_FIX_SB1 || flag_unsafe_math_optimizations)")])
|
|
|
;; This attribute gives the conditions under which SQRT.fmt instructions
|
;; This attribute gives the conditions under which SQRT.fmt instructions
|
;; can be used.
|
;; can be used.
|
(define_mode_attr sqrt_condition
|
(define_mode_attr sqrt_condition
|
[(SF "!ISA_MIPS1") (DF "!ISA_MIPS1") (V2SF "TARGET_SB1")])
|
[(SF "!ISA_MIPS1") (DF "!ISA_MIPS1") (V2SF "TARGET_SB1")])
|
|
|
;; This attribute gives the conditions under which RECIP.fmt and RSQRT.fmt
|
;; This attribute gives the conditions under which RECIP.fmt and RSQRT.fmt
|
;; instructions can be used. The MIPS32 and MIPS64 ISAs say that RECIP.D
|
;; instructions can be used. The MIPS32 and MIPS64 ISAs say that RECIP.D
|
;; and RSQRT.D are unpredictable when doubles are stored in pairs of FPRs,
|
;; and RSQRT.D are unpredictable when doubles are stored in pairs of FPRs,
|
;; so for safety's sake, we apply this restriction to all targets.
|
;; so for safety's sake, we apply this restriction to all targets.
|
(define_mode_attr recip_condition
|
(define_mode_attr recip_condition
|
[(SF "ISA_HAS_FP4")
|
[(SF "ISA_HAS_FP4")
|
(DF "ISA_HAS_FP4 && TARGET_FLOAT64")
|
(DF "ISA_HAS_FP4 && TARGET_FLOAT64")
|
(V2SF "TARGET_SB1")])
|
(V2SF "TARGET_SB1")])
|
|
|
;; This code iterator allows signed and unsigned widening multiplications
|
;; This code iterator allows signed and unsigned widening multiplications
|
;; to use the same template.
|
;; to use the same template.
|
(define_code_iterator any_extend [sign_extend zero_extend])
|
(define_code_iterator any_extend [sign_extend zero_extend])
|
|
|
;; This code iterator allows the two right shift instructions to be
|
;; This code iterator allows the two right shift instructions to be
|
;; generated from the same template.
|
;; generated from the same template.
|
(define_code_iterator any_shiftrt [ashiftrt lshiftrt])
|
(define_code_iterator any_shiftrt [ashiftrt lshiftrt])
|
|
|
;; This code iterator allows the three shift instructions to be generated
|
;; This code iterator allows the three shift instructions to be generated
|
;; from the same template.
|
;; from the same template.
|
(define_code_iterator any_shift [ashift ashiftrt lshiftrt])
|
(define_code_iterator any_shift [ashift ashiftrt lshiftrt])
|
|
|
;; This code iterator allows unsigned and signed division to be generated
|
;; This code iterator allows unsigned and signed division to be generated
|
;; from the same template.
|
;; from the same template.
|
(define_code_iterator any_div [div udiv])
|
(define_code_iterator any_div [div udiv])
|
|
|
;; This code iterator allows unsigned and signed modulus to be generated
|
;; This code iterator allows unsigned and signed modulus to be generated
|
;; from the same template.
|
;; from the same template.
|
(define_code_iterator any_mod [mod umod])
|
(define_code_iterator any_mod [mod umod])
|
|
|
;; This code iterator allows all native floating-point comparisons to be
|
;; This code iterator allows all native floating-point comparisons to be
|
;; generated from the same template.
|
;; generated from the same template.
|
(define_code_iterator fcond [unordered uneq unlt unle eq lt le])
|
(define_code_iterator fcond [unordered uneq unlt unle eq lt le])
|
|
|
;; This code iterator is used for comparisons that can be implemented
|
;; This code iterator is used for comparisons that can be implemented
|
;; by swapping the operands.
|
;; by swapping the operands.
|
(define_code_iterator swapped_fcond [ge gt unge ungt])
|
(define_code_iterator swapped_fcond [ge gt unge ungt])
|
|
|
;; Equality operators.
|
;; Equality operators.
|
(define_code_iterator equality_op [eq ne])
|
(define_code_iterator equality_op [eq ne])
|
|
|
;; These code iterators allow the signed and unsigned scc operations to use
|
;; These code iterators allow the signed and unsigned scc operations to use
|
;; the same template.
|
;; the same template.
|
(define_code_iterator any_gt [gt gtu])
|
(define_code_iterator any_gt [gt gtu])
|
(define_code_iterator any_ge [ge geu])
|
(define_code_iterator any_ge [ge geu])
|
(define_code_iterator any_lt [lt ltu])
|
(define_code_iterator any_lt [lt ltu])
|
(define_code_iterator any_le [le leu])
|
(define_code_iterator any_le [le leu])
|
|
|
;; expands to an empty string when doing a signed operation and
|
;; expands to an empty string when doing a signed operation and
|
;; "u" when doing an unsigned operation.
|
;; "u" when doing an unsigned operation.
|
(define_code_attr u [(sign_extend "") (zero_extend "u")
|
(define_code_attr u [(sign_extend "") (zero_extend "u")
|
(div "") (udiv "u")
|
(div "") (udiv "u")
|
(mod "") (umod "u")
|
(mod "") (umod "u")
|
(gt "") (gtu "u")
|
(gt "") (gtu "u")
|
(ge "") (geu "u")
|
(ge "") (geu "u")
|
(lt "") (ltu "u")
|
(lt "") (ltu "u")
|
(le "") (leu "u")])
|
(le "") (leu "u")])
|
|
|
;; is like , but the signed form expands to "s" rather than "".
|
;; is like , but the signed form expands to "s" rather than "".
|
(define_code_attr su [(sign_extend "s") (zero_extend "u")])
|
(define_code_attr su [(sign_extend "s") (zero_extend "u")])
|
|
|
;; expands to the name of the optab for a particular code.
|
;; expands to the name of the optab for a particular code.
|
(define_code_attr optab [(ashift "ashl")
|
(define_code_attr optab [(ashift "ashl")
|
(ashiftrt "ashr")
|
(ashiftrt "ashr")
|
(lshiftrt "lshr")
|
(lshiftrt "lshr")
|
(ior "ior")
|
(ior "ior")
|
(xor "xor")
|
(xor "xor")
|
(and "and")
|
(and "and")
|
(plus "add")
|
(plus "add")
|
(minus "sub")])
|
(minus "sub")])
|
|
|
;; expands to the name of the insn that implements a particular code.
|
;; expands to the name of the insn that implements a particular code.
|
(define_code_attr insn [(ashift "sll")
|
(define_code_attr insn [(ashift "sll")
|
(ashiftrt "sra")
|
(ashiftrt "sra")
|
(lshiftrt "srl")
|
(lshiftrt "srl")
|
(ior "or")
|
(ior "or")
|
(xor "xor")
|
(xor "xor")
|
(and "and")
|
(and "and")
|
(plus "addu")
|
(plus "addu")
|
(minus "subu")])
|
(minus "subu")])
|
|
|
;; expands to the name of the insn that implements
|
;; expands to the name of the insn that implements
|
;; a particular code to operate on immediate values.
|
;; a particular code to operate on immediate values.
|
(define_code_attr immediate_insn [(ior "ori")
|
(define_code_attr immediate_insn [(ior "ori")
|
(xor "xori")
|
(xor "xori")
|
(and "andi")])
|
(and "andi")])
|
|
|
;; is the c.cond.fmt condition associated with a particular code.
|
;; is the c.cond.fmt condition associated with a particular code.
|
(define_code_attr fcond [(unordered "un")
|
(define_code_attr fcond [(unordered "un")
|
(uneq "ueq")
|
(uneq "ueq")
|
(unlt "ult")
|
(unlt "ult")
|
(unle "ule")
|
(unle "ule")
|
(eq "eq")
|
(eq "eq")
|
(lt "lt")
|
(lt "lt")
|
(le "le")])
|
(le "le")])
|
|
|
;; Similar, but for swapped conditions.
|
;; Similar, but for swapped conditions.
|
(define_code_attr swapped_fcond [(ge "le")
|
(define_code_attr swapped_fcond [(ge "le")
|
(gt "lt")
|
(gt "lt")
|
(unge "ule")
|
(unge "ule")
|
(ungt "ult")])
|
(ungt "ult")])
|
|
|
;; The value of the bit when the branch is taken for branch_bit patterns.
|
;; The value of the bit when the branch is taken for branch_bit patterns.
|
;; Comparison is always against zero so this depends on the operator.
|
;; Comparison is always against zero so this depends on the operator.
|
(define_code_attr bbv [(eq "0") (ne "1")])
|
(define_code_attr bbv [(eq "0") (ne "1")])
|
|
|
;; This is the inverse value of bbv.
|
;; This is the inverse value of bbv.
|
(define_code_attr bbinv [(eq "1") (ne "0")])
|
(define_code_attr bbinv [(eq "1") (ne "0")])
|
|
|
;; .........................
|
;; .........................
|
;;
|
;;
|
;; Branch, call and jump delay slots
|
;; Branch, call and jump delay slots
|
;;
|
;;
|
;; .........................
|
;; .........................
|
|
|
(define_delay (and (eq_attr "type" "branch")
|
(define_delay (and (eq_attr "type" "branch")
|
(eq (symbol_ref "TARGET_MIPS16") (const_int 0))
|
(eq (symbol_ref "TARGET_MIPS16") (const_int 0))
|
(eq_attr "branch_likely" "yes"))
|
(eq_attr "branch_likely" "yes"))
|
[(eq_attr "can_delay" "yes")
|
[(eq_attr "can_delay" "yes")
|
(nil)
|
(nil)
|
(eq_attr "can_delay" "yes")])
|
(eq_attr "can_delay" "yes")])
|
|
|
;; Branches that don't have likely variants do not annul on false.
|
;; Branches that don't have likely variants do not annul on false.
|
(define_delay (and (eq_attr "type" "branch")
|
(define_delay (and (eq_attr "type" "branch")
|
(eq (symbol_ref "TARGET_MIPS16") (const_int 0))
|
(eq (symbol_ref "TARGET_MIPS16") (const_int 0))
|
(eq_attr "branch_likely" "no"))
|
(eq_attr "branch_likely" "no"))
|
[(eq_attr "can_delay" "yes")
|
[(eq_attr "can_delay" "yes")
|
(nil)
|
(nil)
|
(nil)])
|
(nil)])
|
|
|
(define_delay (eq_attr "type" "jump")
|
(define_delay (eq_attr "type" "jump")
|
[(eq_attr "can_delay" "yes")
|
[(eq_attr "can_delay" "yes")
|
(nil)
|
(nil)
|
(nil)])
|
(nil)])
|
|
|
(define_delay (and (eq_attr "type" "call")
|
(define_delay (and (eq_attr "type" "call")
|
(eq_attr "jal_macro" "no"))
|
(eq_attr "jal_macro" "no"))
|
[(eq_attr "can_delay" "yes")
|
[(eq_attr "can_delay" "yes")
|
(nil)
|
(nil)
|
(nil)])
|
(nil)])
|
|
|
;; Pipeline descriptions.
|
;; Pipeline descriptions.
|
;;
|
;;
|
;; generic.md provides a fallback for processors without a specific
|
;; generic.md provides a fallback for processors without a specific
|
;; pipeline description. It is derived from the old define_function_unit
|
;; pipeline description. It is derived from the old define_function_unit
|
;; version and uses the "alu" and "imuldiv" units declared below.
|
;; version and uses the "alu" and "imuldiv" units declared below.
|
;;
|
;;
|
;; Some of the processor-specific files are also derived from old
|
;; Some of the processor-specific files are also derived from old
|
;; define_function_unit descriptions and simply override the parts of
|
;; define_function_unit descriptions and simply override the parts of
|
;; generic.md that don't apply. The other processor-specific files
|
;; generic.md that don't apply. The other processor-specific files
|
;; are self-contained.
|
;; are self-contained.
|
(define_automaton "alu,imuldiv")
|
(define_automaton "alu,imuldiv")
|
|
|
(define_cpu_unit "alu" "alu")
|
(define_cpu_unit "alu" "alu")
|
(define_cpu_unit "imuldiv" "imuldiv")
|
(define_cpu_unit "imuldiv" "imuldiv")
|
|
|
;; Ghost instructions produce no real code and introduce no hazards.
|
;; Ghost instructions produce no real code and introduce no hazards.
|
;; They exist purely to express an effect on dataflow.
|
;; They exist purely to express an effect on dataflow.
|
(define_insn_reservation "ghost" 0
|
(define_insn_reservation "ghost" 0
|
(eq_attr "type" "ghost")
|
(eq_attr "type" "ghost")
|
"nothing")
|
"nothing")
|
|
|
(include "4k.md")
|
(include "4k.md")
|
(include "5k.md")
|
(include "5k.md")
|
(include "20kc.md")
|
(include "20kc.md")
|
(include "24k.md")
|
(include "24k.md")
|
(include "74k.md")
|
(include "74k.md")
|
(include "3000.md")
|
(include "3000.md")
|
(include "4000.md")
|
(include "4000.md")
|
(include "4100.md")
|
(include "4100.md")
|
(include "4130.md")
|
(include "4130.md")
|
(include "4300.md")
|
(include "4300.md")
|
(include "4600.md")
|
(include "4600.md")
|
(include "5000.md")
|
(include "5000.md")
|
(include "5400.md")
|
(include "5400.md")
|
(include "5500.md")
|
(include "5500.md")
|
(include "6000.md")
|
(include "6000.md")
|
(include "7000.md")
|
(include "7000.md")
|
(include "9000.md")
|
(include "9000.md")
|
(include "10000.md")
|
(include "10000.md")
|
(include "loongson2ef.md")
|
(include "loongson2ef.md")
|
(include "octeon.md")
|
(include "octeon.md")
|
(include "sb1.md")
|
(include "sb1.md")
|
(include "sr71k.md")
|
(include "sr71k.md")
|
(include "xlr.md")
|
(include "xlr.md")
|
(include "generic.md")
|
(include "generic.md")
|
|
|
;;
|
;;
|
;; ....................
|
;; ....................
|
;;
|
;;
|
;; CONDITIONAL TRAPS
|
;; CONDITIONAL TRAPS
|
;;
|
;;
|
;; ....................
|
;; ....................
|
;;
|
;;
|
|
|
(define_insn "trap"
|
(define_insn "trap"
|
[(trap_if (const_int 1) (const_int 0))]
|
[(trap_if (const_int 1) (const_int 0))]
|
""
|
""
|
{
|
{
|
if (ISA_HAS_COND_TRAP)
|
if (ISA_HAS_COND_TRAP)
|
return "teq\t$0,$0";
|
return "teq\t$0,$0";
|
else if (TARGET_MIPS16)
|
else if (TARGET_MIPS16)
|
return "break 0";
|
return "break 0";
|
else
|
else
|
return "break";
|
return "break";
|
}
|
}
|
[(set_attr "type" "trap")])
|
[(set_attr "type" "trap")])
|
|
|
(define_expand "ctrap4"
|
(define_expand "ctrap4"
|
[(trap_if (match_operator 0 "comparison_operator"
|
[(trap_if (match_operator 0 "comparison_operator"
|
[(match_operand:GPR 1 "reg_or_0_operand")
|
[(match_operand:GPR 1 "reg_or_0_operand")
|
(match_operand:GPR 2 "arith_operand")])
|
(match_operand:GPR 2 "arith_operand")])
|
(match_operand 3 "const_0_operand"))]
|
(match_operand 3 "const_0_operand"))]
|
"ISA_HAS_COND_TRAP"
|
"ISA_HAS_COND_TRAP"
|
{
|
{
|
mips_expand_conditional_trap (operands[0]);
|
mips_expand_conditional_trap (operands[0]);
|
DONE;
|
DONE;
|
})
|
})
|
|
|
(define_insn "*conditional_trap"
|
(define_insn "*conditional_trap"
|
[(trap_if (match_operator:GPR 0 "trap_comparison_operator"
|
[(trap_if (match_operator:GPR 0 "trap_comparison_operator"
|
[(match_operand:GPR 1 "reg_or_0_operand" "dJ")
|
[(match_operand:GPR 1 "reg_or_0_operand" "dJ")
|
(match_operand:GPR 2 "arith_operand" "dI")])
|
(match_operand:GPR 2 "arith_operand" "dI")])
|
(const_int 0))]
|
(const_int 0))]
|
"ISA_HAS_COND_TRAP"
|
"ISA_HAS_COND_TRAP"
|
"t%C0\t%z1,%2"
|
"t%C0\t%z1,%2"
|
[(set_attr "type" "trap")])
|
[(set_attr "type" "trap")])
|
|
|
;;
|
;;
|
;; ....................
|
;; ....................
|
;;
|
;;
|
;; ADDITION
|
;; ADDITION
|
;;
|
;;
|
;; ....................
|
;; ....................
|
;;
|
;;
|
|
|
(define_insn "add3"
|
(define_insn "add3"
|
[(set (match_operand:ANYF 0 "register_operand" "=f")
|
[(set (match_operand:ANYF 0 "register_operand" "=f")
|
(plus:ANYF (match_operand:ANYF 1 "register_operand" "f")
|
(plus:ANYF (match_operand:ANYF 1 "register_operand" "f")
|
(match_operand:ANYF 2 "register_operand" "f")))]
|
(match_operand:ANYF 2 "register_operand" "f")))]
|
""
|
""
|
"add.\t%0,%1,%2"
|
"add.\t%0,%1,%2"
|
[(set_attr "type" "fadd")
|
[(set_attr "type" "fadd")
|
(set_attr "mode" "")])
|
(set_attr "mode" "")])
|
|
|
(define_expand "add3"
|
(define_expand "add3"
|
[(set (match_operand:GPR 0 "register_operand")
|
[(set (match_operand:GPR 0 "register_operand")
|
(plus:GPR (match_operand:GPR 1 "register_operand")
|
(plus:GPR (match_operand:GPR 1 "register_operand")
|
(match_operand:GPR 2 "arith_operand")))]
|
(match_operand:GPR 2 "arith_operand")))]
|
"")
|
"")
|
|
|
(define_insn "*add3"
|
(define_insn "*add3"
|
[(set (match_operand:GPR 0 "register_operand" "=d,d")
|
[(set (match_operand:GPR 0 "register_operand" "=d,d")
|
(plus:GPR (match_operand:GPR 1 "register_operand" "d,d")
|
(plus:GPR (match_operand:GPR 1 "register_operand" "d,d")
|
(match_operand:GPR 2 "arith_operand" "d,Q")))]
|
(match_operand:GPR 2 "arith_operand" "d,Q")))]
|
"!TARGET_MIPS16"
|
"!TARGET_MIPS16"
|
"@
|
"@
|
addu\t%0,%1,%2
|
addu\t%0,%1,%2
|
addiu\t%0,%1,%2"
|
addiu\t%0,%1,%2"
|
[(set_attr "type" "arith")
|
[(set_attr "type" "arith")
|
(set_attr "mode" "")])
|
(set_attr "mode" "")])
|
|
|
(define_insn "*add3_mips16"
|
(define_insn "*add3_mips16"
|
[(set (match_operand:GPR 0 "register_operand" "=ks,d,d,d,d")
|
[(set (match_operand:GPR 0 "register_operand" "=ks,d,d,d,d")
|
(plus:GPR (match_operand:GPR 1 "register_operand" "ks,ks,0,d,d")
|
(plus:GPR (match_operand:GPR 1 "register_operand" "ks,ks,0,d,d")
|
(match_operand:GPR 2 "arith_operand" "Q,Q,Q,O,d")))]
|
(match_operand:GPR 2 "arith_operand" "Q,Q,Q,O,d")))]
|
"TARGET_MIPS16"
|
"TARGET_MIPS16"
|
"@
|
"@
|
addiu\t%0,%2
|
addiu\t%0,%2
|
addiu\t%0,%1,%2
|
addiu\t%0,%1,%2
|
addiu\t%0,%2
|
addiu\t%0,%2
|
addiu\t%0,%1,%2
|
addiu\t%0,%1,%2
|
addu\t%0,%1,%2"
|
addu\t%0,%1,%2"
|
[(set_attr "type" "arith")
|
[(set_attr "type" "arith")
|
(set_attr "mode" "")
|
(set_attr "mode" "")
|
(set_attr_alternative "length"
|
(set_attr_alternative "length"
|
[(if_then_else (match_operand 2 "m16_simm8_8")
|
[(if_then_else (match_operand 2 "m16_simm8_8")
|
(const_int 4)
|
(const_int 4)
|
(const_int 8))
|
(const_int 8))
|
(if_then_else (match_operand 2 "m16_uimm_4")
|
(if_then_else (match_operand 2 "m16_uimm_4")
|
(const_int 4)
|
(const_int 4)
|
(const_int 8))
|
(const_int 8))
|
(if_then_else (match_operand 2 "m16_simm_1")
|
(if_then_else (match_operand 2 "m16_simm_1")
|
(const_int 4)
|
(const_int 4)
|
(const_int 8))
|
(const_int 8))
|
(if_then_else (match_operand 2 "m16_simm4_1")
|
(if_then_else (match_operand 2 "m16_simm4_1")
|
(const_int 4)
|
(const_int 4)
|
(const_int 8))
|
(const_int 8))
|
(const_int 4)])])
|
(const_int 4)])])
|
|
|
;; On the mips16, we can sometimes split an add of a constant which is
|
;; On the mips16, we can sometimes split an add of a constant which is
|
;; a 4 byte instruction into two adds which are both 2 byte
|
;; a 4 byte instruction into two adds which are both 2 byte
|
;; instructions. There are two cases: one where we are adding a
|
;; instructions. There are two cases: one where we are adding a
|
;; constant plus a register to another register, and one where we are
|
;; constant plus a register to another register, and one where we are
|
;; simply adding a constant to a register.
|
;; simply adding a constant to a register.
|
|
|
(define_split
|
(define_split
|
[(set (match_operand:SI 0 "d_operand")
|
[(set (match_operand:SI 0 "d_operand")
|
(plus:SI (match_dup 0)
|
(plus:SI (match_dup 0)
|
(match_operand:SI 1 "const_int_operand")))]
|
(match_operand:SI 1 "const_int_operand")))]
|
"TARGET_MIPS16 && reload_completed && !TARGET_DEBUG_D_MODE
|
"TARGET_MIPS16 && reload_completed && !TARGET_DEBUG_D_MODE
|
&& ((INTVAL (operands[1]) > 0x7f
|
&& ((INTVAL (operands[1]) > 0x7f
|
&& INTVAL (operands[1]) <= 0x7f + 0x7f)
|
&& INTVAL (operands[1]) <= 0x7f + 0x7f)
|
|| (INTVAL (operands[1]) < - 0x80
|
|| (INTVAL (operands[1]) < - 0x80
|
&& INTVAL (operands[1]) >= - 0x80 - 0x80))"
|
&& INTVAL (operands[1]) >= - 0x80 - 0x80))"
|
[(set (match_dup 0) (plus:SI (match_dup 0) (match_dup 1)))
|
[(set (match_dup 0) (plus:SI (match_dup 0) (match_dup 1)))
|
(set (match_dup 0) (plus:SI (match_dup 0) (match_dup 2)))]
|
(set (match_dup 0) (plus:SI (match_dup 0) (match_dup 2)))]
|
{
|
{
|
HOST_WIDE_INT val = INTVAL (operands[1]);
|
HOST_WIDE_INT val = INTVAL (operands[1]);
|
|
|
if (val >= 0)
|
if (val >= 0)
|
{
|
{
|
operands[1] = GEN_INT (0x7f);
|
operands[1] = GEN_INT (0x7f);
|
operands[2] = GEN_INT (val - 0x7f);
|
operands[2] = GEN_INT (val - 0x7f);
|
}
|
}
|
else
|
else
|
{
|
{
|
operands[1] = GEN_INT (- 0x80);
|
operands[1] = GEN_INT (- 0x80);
|
operands[2] = GEN_INT (val + 0x80);
|
operands[2] = GEN_INT (val + 0x80);
|
}
|
}
|
})
|
})
|
|
|
(define_split
|
(define_split
|
[(set (match_operand:SI 0 "d_operand")
|
[(set (match_operand:SI 0 "d_operand")
|
(plus:SI (match_operand:SI 1 "d_operand")
|
(plus:SI (match_operand:SI 1 "d_operand")
|
(match_operand:SI 2 "const_int_operand")))]
|
(match_operand:SI 2 "const_int_operand")))]
|
"TARGET_MIPS16 && reload_completed && !TARGET_DEBUG_D_MODE
|
"TARGET_MIPS16 && reload_completed && !TARGET_DEBUG_D_MODE
|
&& REGNO (operands[0]) != REGNO (operands[1])
|
&& REGNO (operands[0]) != REGNO (operands[1])
|
&& ((INTVAL (operands[2]) > 0x7
|
&& ((INTVAL (operands[2]) > 0x7
|
&& INTVAL (operands[2]) <= 0x7 + 0x7f)
|
&& INTVAL (operands[2]) <= 0x7 + 0x7f)
|
|| (INTVAL (operands[2]) < - 0x8
|
|| (INTVAL (operands[2]) < - 0x8
|
&& INTVAL (operands[2]) >= - 0x8 - 0x80))"
|
&& INTVAL (operands[2]) >= - 0x8 - 0x80))"
|
[(set (match_dup 0) (plus:SI (match_dup 1) (match_dup 2)))
|
[(set (match_dup 0) (plus:SI (match_dup 1) (match_dup 2)))
|
(set (match_dup 0) (plus:SI (match_dup 0) (match_dup 3)))]
|
(set (match_dup 0) (plus:SI (match_dup 0) (match_dup 3)))]
|
{
|
{
|
HOST_WIDE_INT val = INTVAL (operands[2]);
|
HOST_WIDE_INT val = INTVAL (operands[2]);
|
|
|
if (val >= 0)
|
if (val >= 0)
|
{
|
{
|
operands[2] = GEN_INT (0x7);
|
operands[2] = GEN_INT (0x7);
|
operands[3] = GEN_INT (val - 0x7);
|
operands[3] = GEN_INT (val - 0x7);
|
}
|
}
|
else
|
else
|
{
|
{
|
operands[2] = GEN_INT (- 0x8);
|
operands[2] = GEN_INT (- 0x8);
|
operands[3] = GEN_INT (val + 0x8);
|
operands[3] = GEN_INT (val + 0x8);
|
}
|
}
|
})
|
})
|
|
|
(define_split
|
(define_split
|
[(set (match_operand:DI 0 "d_operand")
|
[(set (match_operand:DI 0 "d_operand")
|
(plus:DI (match_dup 0)
|
(plus:DI (match_dup 0)
|
(match_operand:DI 1 "const_int_operand")))]
|
(match_operand:DI 1 "const_int_operand")))]
|
"TARGET_MIPS16 && TARGET_64BIT && reload_completed && !TARGET_DEBUG_D_MODE
|
"TARGET_MIPS16 && TARGET_64BIT && reload_completed && !TARGET_DEBUG_D_MODE
|
&& ((INTVAL (operands[1]) > 0xf
|
&& ((INTVAL (operands[1]) > 0xf
|
&& INTVAL (operands[1]) <= 0xf + 0xf)
|
&& INTVAL (operands[1]) <= 0xf + 0xf)
|
|| (INTVAL (operands[1]) < - 0x10
|
|| (INTVAL (operands[1]) < - 0x10
|
&& INTVAL (operands[1]) >= - 0x10 - 0x10))"
|
&& INTVAL (operands[1]) >= - 0x10 - 0x10))"
|
[(set (match_dup 0) (plus:DI (match_dup 0) (match_dup 1)))
|
[(set (match_dup 0) (plus:DI (match_dup 0) (match_dup 1)))
|
(set (match_dup 0) (plus:DI (match_dup 0) (match_dup 2)))]
|
(set (match_dup 0) (plus:DI (match_dup 0) (match_dup 2)))]
|
{
|
{
|
HOST_WIDE_INT val = INTVAL (operands[1]);
|
HOST_WIDE_INT val = INTVAL (operands[1]);
|
|
|
if (val >= 0)
|
if (val >= 0)
|
{
|
{
|
operands[1] = GEN_INT (0xf);
|
operands[1] = GEN_INT (0xf);
|
operands[2] = GEN_INT (val - 0xf);
|
operands[2] = GEN_INT (val - 0xf);
|
}
|
}
|
else
|
else
|
{
|
{
|
operands[1] = GEN_INT (- 0x10);
|
operands[1] = GEN_INT (- 0x10);
|
operands[2] = GEN_INT (val + 0x10);
|
operands[2] = GEN_INT (val + 0x10);
|
}
|
}
|
})
|
})
|
|
|
(define_split
|
(define_split
|
[(set (match_operand:DI 0 "d_operand")
|
[(set (match_operand:DI 0 "d_operand")
|
(plus:DI (match_operand:DI 1 "d_operand")
|
(plus:DI (match_operand:DI 1 "d_operand")
|
(match_operand:DI 2 "const_int_operand")))]
|
(match_operand:DI 2 "const_int_operand")))]
|
"TARGET_MIPS16 && TARGET_64BIT && reload_completed && !TARGET_DEBUG_D_MODE
|
"TARGET_MIPS16 && TARGET_64BIT && reload_completed && !TARGET_DEBUG_D_MODE
|
&& REGNO (operands[0]) != REGNO (operands[1])
|
&& REGNO (operands[0]) != REGNO (operands[1])
|
&& ((INTVAL (operands[2]) > 0x7
|
&& ((INTVAL (operands[2]) > 0x7
|
&& INTVAL (operands[2]) <= 0x7 + 0xf)
|
&& INTVAL (operands[2]) <= 0x7 + 0xf)
|
|| (INTVAL (operands[2]) < - 0x8
|
|| (INTVAL (operands[2]) < - 0x8
|
&& INTVAL (operands[2]) >= - 0x8 - 0x10))"
|
&& INTVAL (operands[2]) >= - 0x8 - 0x10))"
|
[(set (match_dup 0) (plus:DI (match_dup 1) (match_dup 2)))
|
[(set (match_dup 0) (plus:DI (match_dup 1) (match_dup 2)))
|
(set (match_dup 0) (plus:DI (match_dup 0) (match_dup 3)))]
|
(set (match_dup 0) (plus:DI (match_dup 0) (match_dup 3)))]
|
{
|
{
|
HOST_WIDE_INT val = INTVAL (operands[2]);
|
HOST_WIDE_INT val = INTVAL (operands[2]);
|
|
|
if (val >= 0)
|
if (val >= 0)
|
{
|
{
|
operands[2] = GEN_INT (0x7);
|
operands[2] = GEN_INT (0x7);
|
operands[3] = GEN_INT (val - 0x7);
|
operands[3] = GEN_INT (val - 0x7);
|
}
|
}
|
else
|
else
|
{
|
{
|
operands[2] = GEN_INT (- 0x8);
|
operands[2] = GEN_INT (- 0x8);
|
operands[3] = GEN_INT (val + 0x8);
|
operands[3] = GEN_INT (val + 0x8);
|
}
|
}
|
})
|
})
|
|
|
(define_insn "*addsi3_extended"
|
(define_insn "*addsi3_extended"
|
[(set (match_operand:DI 0 "register_operand" "=d,d")
|
[(set (match_operand:DI 0 "register_operand" "=d,d")
|
(sign_extend:DI
|
(sign_extend:DI
|
(plus:SI (match_operand:SI 1 "register_operand" "d,d")
|
(plus:SI (match_operand:SI 1 "register_operand" "d,d")
|
(match_operand:SI 2 "arith_operand" "d,Q"))))]
|
(match_operand:SI 2 "arith_operand" "d,Q"))))]
|
"TARGET_64BIT && !TARGET_MIPS16"
|
"TARGET_64BIT && !TARGET_MIPS16"
|
"@
|
"@
|
addu\t%0,%1,%2
|
addu\t%0,%1,%2
|
addiu\t%0,%1,%2"
|
addiu\t%0,%1,%2"
|
[(set_attr "type" "arith")
|
[(set_attr "type" "arith")
|
(set_attr "mode" "SI")])
|
(set_attr "mode" "SI")])
|
|
|
;; Split this insn so that the addiu splitters can have a crack at it.
|
;; Split this insn so that the addiu splitters can have a crack at it.
|
;; Use a conservative length estimate until the split.
|
;; Use a conservative length estimate until the split.
|
(define_insn_and_split "*addsi3_extended_mips16"
|
(define_insn_and_split "*addsi3_extended_mips16"
|
[(set (match_operand:DI 0 "register_operand" "=d,d,d")
|
[(set (match_operand:DI 0 "register_operand" "=d,d,d")
|
(sign_extend:DI
|
(sign_extend:DI
|
(plus:SI (match_operand:SI 1 "register_operand" "0,d,d")
|
(plus:SI (match_operand:SI 1 "register_operand" "0,d,d")
|
(match_operand:SI 2 "arith_operand" "Q,O,d"))))]
|
(match_operand:SI 2 "arith_operand" "Q,O,d"))))]
|
"TARGET_64BIT && TARGET_MIPS16"
|
"TARGET_64BIT && TARGET_MIPS16"
|
"#"
|
"#"
|
"&& reload_completed"
|
"&& reload_completed"
|
[(set (match_dup 3) (plus:SI (match_dup 1) (match_dup 2)))]
|
[(set (match_dup 3) (plus:SI (match_dup 1) (match_dup 2)))]
|
{ operands[3] = gen_lowpart (SImode, operands[0]); }
|
{ operands[3] = gen_lowpart (SImode, operands[0]); }
|
[(set_attr "type" "arith")
|
[(set_attr "type" "arith")
|
(set_attr "mode" "SI")
|
(set_attr "mode" "SI")
|
(set_attr "extended_mips16" "yes")])
|
(set_attr "extended_mips16" "yes")])
|
|
|
;; Combiner patterns for unsigned byte-add.
|
;; Combiner patterns for unsigned byte-add.
|
|
|
(define_insn "*baddu_si_eb"
|
(define_insn "*baddu_si_eb"
|
[(set (match_operand:SI 0 "register_operand" "=d")
|
[(set (match_operand:SI 0 "register_operand" "=d")
|
(zero_extend:SI
|
(zero_extend:SI
|
(subreg:QI
|
(subreg:QI
|
(plus:SI (match_operand:SI 1 "register_operand" "d")
|
(plus:SI (match_operand:SI 1 "register_operand" "d")
|
(match_operand:SI 2 "register_operand" "d")) 3)))]
|
(match_operand:SI 2 "register_operand" "d")) 3)))]
|
"ISA_HAS_BADDU && BYTES_BIG_ENDIAN"
|
"ISA_HAS_BADDU && BYTES_BIG_ENDIAN"
|
"baddu\\t%0,%1,%2"
|
"baddu\\t%0,%1,%2"
|
[(set_attr "type" "arith")])
|
[(set_attr "type" "arith")])
|
|
|
(define_insn "*baddu_si_el"
|
(define_insn "*baddu_si_el"
|
[(set (match_operand:SI 0 "register_operand" "=d")
|
[(set (match_operand:SI 0 "register_operand" "=d")
|
(zero_extend:SI
|
(zero_extend:SI
|
(subreg:QI
|
(subreg:QI
|
(plus:SI (match_operand:SI 1 "register_operand" "d")
|
(plus:SI (match_operand:SI 1 "register_operand" "d")
|
(match_operand:SI 2 "register_operand" "d")) 0)))]
|
(match_operand:SI 2 "register_operand" "d")) 0)))]
|
"ISA_HAS_BADDU && !BYTES_BIG_ENDIAN"
|
"ISA_HAS_BADDU && !BYTES_BIG_ENDIAN"
|
"baddu\\t%0,%1,%2"
|
"baddu\\t%0,%1,%2"
|
[(set_attr "type" "arith")])
|
[(set_attr "type" "arith")])
|
|
|
(define_insn "*baddu_di"
|
(define_insn "*baddu_di"
|
[(set (match_operand:GPR 0 "register_operand" "=d")
|
[(set (match_operand:GPR 0 "register_operand" "=d")
|
(zero_extend:GPR
|
(zero_extend:GPR
|
(truncate:QI
|
(truncate:QI
|
(plus:DI (match_operand:DI 1 "register_operand" "d")
|
(plus:DI (match_operand:DI 1 "register_operand" "d")
|
(match_operand:DI 2 "register_operand" "d")))))]
|
(match_operand:DI 2 "register_operand" "d")))))]
|
"ISA_HAS_BADDU && TARGET_64BIT"
|
"ISA_HAS_BADDU && TARGET_64BIT"
|
"baddu\\t%0,%1,%2"
|
"baddu\\t%0,%1,%2"
|
[(set_attr "type" "arith")])
|
[(set_attr "type" "arith")])
|
|
|
;;
|
;;
|
;; ....................
|
;; ....................
|
;;
|
;;
|
;; SUBTRACTION
|
;; SUBTRACTION
|
;;
|
;;
|
;; ....................
|
;; ....................
|
;;
|
;;
|
|
|
(define_insn "sub3"
|
(define_insn "sub3"
|
[(set (match_operand:ANYF 0 "register_operand" "=f")
|
[(set (match_operand:ANYF 0 "register_operand" "=f")
|
(minus:ANYF (match_operand:ANYF 1 "register_operand" "f")
|
(minus:ANYF (match_operand:ANYF 1 "register_operand" "f")
|
(match_operand:ANYF 2 "register_operand" "f")))]
|
(match_operand:ANYF 2 "register_operand" "f")))]
|
""
|
""
|
"sub.\t%0,%1,%2"
|
"sub.\t%0,%1,%2"
|
[(set_attr "type" "fadd")
|
[(set_attr "type" "fadd")
|
(set_attr "mode" "")])
|
(set_attr "mode" "")])
|
|
|
(define_insn "sub3"
|
(define_insn "sub3"
|
[(set (match_operand:GPR 0 "register_operand" "=d")
|
[(set (match_operand:GPR 0 "register_operand" "=d")
|
(minus:GPR (match_operand:GPR 1 "register_operand" "d")
|
(minus:GPR (match_operand:GPR 1 "register_operand" "d")
|
(match_operand:GPR 2 "register_operand" "d")))]
|
(match_operand:GPR 2 "register_operand" "d")))]
|
""
|
""
|
"subu\t%0,%1,%2"
|
"subu\t%0,%1,%2"
|
[(set_attr "type" "arith")
|
[(set_attr "type" "arith")
|
(set_attr "mode" "")])
|
(set_attr "mode" "")])
|
|
|
(define_insn "*subsi3_extended"
|
(define_insn "*subsi3_extended"
|
[(set (match_operand:DI 0 "register_operand" "=d")
|
[(set (match_operand:DI 0 "register_operand" "=d")
|
(sign_extend:DI
|
(sign_extend:DI
|
(minus:SI (match_operand:SI 1 "register_operand" "d")
|
(minus:SI (match_operand:SI 1 "register_operand" "d")
|
(match_operand:SI 2 "register_operand" "d"))))]
|
(match_operand:SI 2 "register_operand" "d"))))]
|
"TARGET_64BIT"
|
"TARGET_64BIT"
|
"subu\t%0,%1,%2"
|
"subu\t%0,%1,%2"
|
[(set_attr "type" "arith")
|
[(set_attr "type" "arith")
|
(set_attr "mode" "DI")])
|
(set_attr "mode" "DI")])
|
|
|
;;
|
;;
|
;; ....................
|
;; ....................
|
;;
|
;;
|
;; MULTIPLICATION
|
;; MULTIPLICATION
|
;;
|
;;
|
;; ....................
|
;; ....................
|
;;
|
;;
|
|
|
(define_expand "mul3"
|
(define_expand "mul3"
|
[(set (match_operand:SCALARF 0 "register_operand")
|
[(set (match_operand:SCALARF 0 "register_operand")
|
(mult:SCALARF (match_operand:SCALARF 1 "register_operand")
|
(mult:SCALARF (match_operand:SCALARF 1 "register_operand")
|
(match_operand:SCALARF 2 "register_operand")))]
|
(match_operand:SCALARF 2 "register_operand")))]
|
""
|
""
|
"")
|
"")
|
|
|
(define_insn "*mul3"
|
(define_insn "*mul3"
|
[(set (match_operand:SCALARF 0 "register_operand" "=f")
|
[(set (match_operand:SCALARF 0 "register_operand" "=f")
|
(mult:SCALARF (match_operand:SCALARF 1 "register_operand" "f")
|
(mult:SCALARF (match_operand:SCALARF 1 "register_operand" "f")
|
(match_operand:SCALARF 2 "register_operand" "f")))]
|
(match_operand:SCALARF 2 "register_operand" "f")))]
|
"!TARGET_4300_MUL_FIX"
|
"!TARGET_4300_MUL_FIX"
|
"mul.\t%0,%1,%2"
|
"mul.\t%0,%1,%2"
|
[(set_attr "type" "fmul")
|
[(set_attr "type" "fmul")
|
(set_attr "mode" "")])
|
(set_attr "mode" "")])
|
|
|
;; Early VR4300 silicon has a CPU bug where multiplies with certain
|
;; Early VR4300 silicon has a CPU bug where multiplies with certain
|
;; operands may corrupt immediately following multiplies. This is a
|
;; operands may corrupt immediately following multiplies. This is a
|
;; simple fix to insert NOPs.
|
;; simple fix to insert NOPs.
|
|
|
(define_insn "*mul3_r4300"
|
(define_insn "*mul3_r4300"
|
[(set (match_operand:SCALARF 0 "register_operand" "=f")
|
[(set (match_operand:SCALARF 0 "register_operand" "=f")
|
(mult:SCALARF (match_operand:SCALARF 1 "register_operand" "f")
|
(mult:SCALARF (match_operand:SCALARF 1 "register_operand" "f")
|
(match_operand:SCALARF 2 "register_operand" "f")))]
|
(match_operand:SCALARF 2 "register_operand" "f")))]
|
"TARGET_4300_MUL_FIX"
|
"TARGET_4300_MUL_FIX"
|
"mul.\t%0,%1,%2\;nop"
|
"mul.\t%0,%1,%2\;nop"
|
[(set_attr "type" "fmul")
|
[(set_attr "type" "fmul")
|
(set_attr "mode" "")
|
(set_attr "mode" "")
|
(set_attr "length" "8")])
|
(set_attr "length" "8")])
|
|
|
(define_insn "mulv2sf3"
|
(define_insn "mulv2sf3"
|
[(set (match_operand:V2SF 0 "register_operand" "=f")
|
[(set (match_operand:V2SF 0 "register_operand" "=f")
|
(mult:V2SF (match_operand:V2SF 1 "register_operand" "f")
|
(mult:V2SF (match_operand:V2SF 1 "register_operand" "f")
|
(match_operand:V2SF 2 "register_operand" "f")))]
|
(match_operand:V2SF 2 "register_operand" "f")))]
|
"TARGET_HARD_FLOAT && TARGET_PAIRED_SINGLE_FLOAT"
|
"TARGET_HARD_FLOAT && TARGET_PAIRED_SINGLE_FLOAT"
|
"mul.ps\t%0,%1,%2"
|
"mul.ps\t%0,%1,%2"
|
[(set_attr "type" "fmul")
|
[(set_attr "type" "fmul")
|
(set_attr "mode" "SF")])
|
(set_attr "mode" "SF")])
|
|
|
;; The original R4000 has a cpu bug. If a double-word or a variable
|
;; The original R4000 has a cpu bug. If a double-word or a variable
|
;; shift executes while an integer multiplication is in progress, the
|
;; shift executes while an integer multiplication is in progress, the
|
;; shift may give an incorrect result. Avoid this by keeping the mflo
|
;; shift may give an incorrect result. Avoid this by keeping the mflo
|
;; with the mult on the R4000.
|
;; with the mult on the R4000.
|
;;
|
;;
|
;; From "MIPS R4000PC/SC Errata, Processor Revision 2.2 and 3.0"
|
;; From "MIPS R4000PC/SC Errata, Processor Revision 2.2 and 3.0"
|
;; (also valid for MIPS R4000MC processors):
|
;; (also valid for MIPS R4000MC processors):
|
;;
|
;;
|
;; "16. R4000PC, R4000SC: Please refer to errata 28 for an update to
|
;; "16. R4000PC, R4000SC: Please refer to errata 28 for an update to
|
;; this errata description.
|
;; this errata description.
|
;; The following code sequence causes the R4000 to incorrectly
|
;; The following code sequence causes the R4000 to incorrectly
|
;; execute the Double Shift Right Arithmetic 32 (dsra32)
|
;; execute the Double Shift Right Arithmetic 32 (dsra32)
|
;; instruction. If the dsra32 instruction is executed during an
|
;; instruction. If the dsra32 instruction is executed during an
|
;; integer multiply, the dsra32 will only shift by the amount in
|
;; integer multiply, the dsra32 will only shift by the amount in
|
;; specified in the instruction rather than the amount plus 32
|
;; specified in the instruction rather than the amount plus 32
|
;; bits.
|
;; bits.
|
;; instruction 1: mult rs,rt integer multiply
|
;; instruction 1: mult rs,rt integer multiply
|
;; instruction 2-12: dsra32 rd,rt,rs doubleword shift
|
;; instruction 2-12: dsra32 rd,rt,rs doubleword shift
|
;; right arithmetic + 32
|
;; right arithmetic + 32
|
;; Workaround: A dsra32 instruction placed after an integer
|
;; Workaround: A dsra32 instruction placed after an integer
|
;; multiply should not be one of the 11 instructions after the
|
;; multiply should not be one of the 11 instructions after the
|
;; multiply instruction."
|
;; multiply instruction."
|
;;
|
;;
|
;; and:
|
;; and:
|
;;
|
;;
|
;; "28. R4000PC, R4000SC: The text from errata 16 should be replaced by
|
;; "28. R4000PC, R4000SC: The text from errata 16 should be replaced by
|
;; the following description.
|
;; the following description.
|
;; All extended shifts (shift by n+32) and variable shifts (32 and
|
;; All extended shifts (shift by n+32) and variable shifts (32 and
|
;; 64-bit versions) may produce incorrect results under the
|
;; 64-bit versions) may produce incorrect results under the
|
;; following conditions:
|
;; following conditions:
|
;; 1) An integer multiply is currently executing
|
;; 1) An integer multiply is currently executing
|
;; 2) These types of shift instructions are executed immediately
|
;; 2) These types of shift instructions are executed immediately
|
;; following an integer divide instruction.
|
;; following an integer divide instruction.
|
;; Workaround:
|
;; Workaround:
|
;; 1) Make sure no integer multiply is running wihen these
|
;; 1) Make sure no integer multiply is running wihen these
|
;; instruction are executed. If this cannot be predicted at
|
;; instruction are executed. If this cannot be predicted at
|
;; compile time, then insert a "mfhi" to R0 instruction
|
;; compile time, then insert a "mfhi" to R0 instruction
|
;; immediately after the integer multiply instruction. This
|
;; immediately after the integer multiply instruction. This
|
;; will cause the integer multiply to complete before the shift
|
;; will cause the integer multiply to complete before the shift
|
;; is executed.
|
;; is executed.
|
;; 2) Separate integer divide and these two classes of shift
|
;; 2) Separate integer divide and these two classes of shift
|
;; instructions by another instruction or a noop."
|
;; instructions by another instruction or a noop."
|
;;
|
;;
|
;; These processors have PRId values of 0x00004220 and 0x00004300,
|
;; These processors have PRId values of 0x00004220 and 0x00004300,
|
;; respectively.
|
;; respectively.
|
|
|
(define_expand "mul3"
|
(define_expand "mul3"
|
[(set (match_operand:GPR 0 "register_operand")
|
[(set (match_operand:GPR 0 "register_operand")
|
(mult:GPR (match_operand:GPR 1 "register_operand")
|
(mult:GPR (match_operand:GPR 1 "register_operand")
|
(match_operand:GPR 2 "register_operand")))]
|
(match_operand:GPR 2 "register_operand")))]
|
""
|
""
|
{
|
{
|
if (TARGET_LOONGSON_2EF)
|
if (TARGET_LOONGSON_2EF)
|
emit_insn (gen_mul3_mul3_ls2ef (operands[0], operands[1],
|
emit_insn (gen_mul3_mul3_ls2ef (operands[0], operands[1],
|
operands[2]));
|
operands[2]));
|
else if (ISA_HAS_MUL3)
|
else if (ISA_HAS_MUL3)
|
emit_insn (gen_mul3_mul3 (operands[0], operands[1], operands[2]));
|
emit_insn (gen_mul3_mul3 (operands[0], operands[1], operands[2]));
|
else if (TARGET_FIX_R4000)
|
else if (TARGET_FIX_R4000)
|
emit_insn (gen_mul3_r4000 (operands[0], operands[1], operands[2]));
|
emit_insn (gen_mul3_r4000 (operands[0], operands[1], operands[2]));
|
else
|
else
|
emit_insn
|
emit_insn
|
(gen_mul3_internal (operands[0], operands[1], operands[2]));
|
(gen_mul3_internal (operands[0], operands[1], operands[2]));
|
DONE;
|
DONE;
|
})
|
})
|
|
|
(define_insn "mul3_mul3_ls2ef"
|
(define_insn "mul3_mul3_ls2ef"
|
[(set (match_operand:GPR 0 "register_operand" "=d")
|
[(set (match_operand:GPR 0 "register_operand" "=d")
|
(mult:GPR (match_operand:GPR 1 "register_operand" "d")
|
(mult:GPR (match_operand:GPR 1 "register_operand" "d")
|
(match_operand:GPR 2 "register_operand" "d")))]
|
(match_operand:GPR 2 "register_operand" "d")))]
|
"TARGET_LOONGSON_2EF"
|
"TARGET_LOONGSON_2EF"
|
"multu.g\t%0,%1,%2"
|
"multu.g\t%0,%1,%2"
|
[(set_attr "type" "imul3nc")
|
[(set_attr "type" "imul3nc")
|
(set_attr "mode" "")])
|
(set_attr "mode" "")])
|
|
|
(define_insn "mul3_mul3"
|
(define_insn "mul3_mul3"
|
[(set (match_operand:GPR 0 "register_operand" "=d,l")
|
[(set (match_operand:GPR 0 "register_operand" "=d,l")
|
(mult:GPR (match_operand:GPR 1 "register_operand" "d,d")
|
(mult:GPR (match_operand:GPR 1 "register_operand" "d,d")
|
(match_operand:GPR 2 "register_operand" "d,d")))
|
(match_operand:GPR 2 "register_operand" "d,d")))
|
(clobber (match_scratch:GPR 3 "=l,X"))]
|
(clobber (match_scratch:GPR 3 "=l,X"))]
|
"ISA_HAS_MUL3"
|
"ISA_HAS_MUL3"
|
{
|
{
|
if (which_alternative == 1)
|
if (which_alternative == 1)
|
return "mult\t%1,%2";
|
return "mult\t%1,%2";
|
if (mode == SImode && TARGET_MIPS3900)
|
if (mode == SImode && TARGET_MIPS3900)
|
return "mult\t%0,%1,%2";
|
return "mult\t%0,%1,%2";
|
return "mul\t%0,%1,%2";
|
return "mul\t%0,%1,%2";
|
}
|
}
|
[(set_attr "type" "imul3,imul")
|
[(set_attr "type" "imul3,imul")
|
(set_attr "mode" "")])
|
(set_attr "mode" "")])
|
|
|
;; If a register gets allocated to LO, and we spill to memory, the reload
|
;; If a register gets allocated to LO, and we spill to memory, the reload
|
;; will include a move from LO to a GPR. Merge it into the multiplication
|
;; will include a move from LO to a GPR. Merge it into the multiplication
|
;; if it can set the GPR directly.
|
;; if it can set the GPR directly.
|
;;
|
;;
|
;; Operand 0: LO
|
;; Operand 0: LO
|
;; Operand 1: GPR (1st multiplication operand)
|
;; Operand 1: GPR (1st multiplication operand)
|
;; Operand 2: GPR (2nd multiplication operand)
|
;; Operand 2: GPR (2nd multiplication operand)
|
;; Operand 3: GPR (destination)
|
;; Operand 3: GPR (destination)
|
(define_peephole2
|
(define_peephole2
|
[(parallel
|
[(parallel
|
[(set (match_operand:SI 0 "lo_operand")
|
[(set (match_operand:SI 0 "lo_operand")
|
(mult:SI (match_operand:SI 1 "d_operand")
|
(mult:SI (match_operand:SI 1 "d_operand")
|
(match_operand:SI 2 "d_operand")))
|
(match_operand:SI 2 "d_operand")))
|
(clobber (scratch:SI))])
|
(clobber (scratch:SI))])
|
(set (match_operand:SI 3 "d_operand")
|
(set (match_operand:SI 3 "d_operand")
|
(match_dup 0))]
|
(match_dup 0))]
|
"ISA_HAS_MUL3 && peep2_reg_dead_p (2, operands[0])"
|
"ISA_HAS_MUL3 && peep2_reg_dead_p (2, operands[0])"
|
[(parallel
|
[(parallel
|
[(set (match_dup 3)
|
[(set (match_dup 3)
|
(mult:SI (match_dup 1)
|
(mult:SI (match_dup 1)
|
(match_dup 2)))
|
(match_dup 2)))
|
(clobber (match_dup 0))])])
|
(clobber (match_dup 0))])])
|
|
|
(define_insn "mul3_internal"
|
(define_insn "mul3_internal"
|
[(set (match_operand:GPR 0 "register_operand" "=l")
|
[(set (match_operand:GPR 0 "register_operand" "=l")
|
(mult:GPR (match_operand:GPR 1 "register_operand" "d")
|
(mult:GPR (match_operand:GPR 1 "register_operand" "d")
|
(match_operand:GPR 2 "register_operand" "d")))]
|
(match_operand:GPR 2 "register_operand" "d")))]
|
"!TARGET_FIX_R4000"
|
"!TARGET_FIX_R4000"
|
"mult\t%1,%2"
|
"mult\t%1,%2"
|
[(set_attr "type" "imul")
|
[(set_attr "type" "imul")
|
(set_attr "mode" "")])
|
(set_attr "mode" "")])
|
|
|
(define_insn "mul3_r4000"
|
(define_insn "mul3_r4000"
|
[(set (match_operand:GPR 0 "register_operand" "=d")
|
[(set (match_operand:GPR 0 "register_operand" "=d")
|
(mult:GPR (match_operand:GPR 1 "register_operand" "d")
|
(mult:GPR (match_operand:GPR 1 "register_operand" "d")
|
(match_operand:GPR 2 "register_operand" "d")))
|
(match_operand:GPR 2 "register_operand" "d")))
|
(clobber (match_scratch:GPR 3 "=l"))]
|
(clobber (match_scratch:GPR 3 "=l"))]
|
"TARGET_FIX_R4000"
|
"TARGET_FIX_R4000"
|
"mult\t%1,%2\;mflo\t%0"
|
"mult\t%1,%2\;mflo\t%0"
|
[(set_attr "type" "imul")
|
[(set_attr "type" "imul")
|
(set_attr "mode" "")
|
(set_attr "mode" "")
|
(set_attr "length" "8")])
|
(set_attr "length" "8")])
|
|
|
;; On the VR4120 and VR4130, it is better to use "mtlo $0; macc" instead
|
;; On the VR4120 and VR4130, it is better to use "mtlo $0; macc" instead
|
;; of "mult; mflo". They have the same latency, but the first form gives
|
;; of "mult; mflo". They have the same latency, but the first form gives
|
;; us an extra cycle to compute the operands.
|
;; us an extra cycle to compute the operands.
|
|
|
;; Operand 0: LO
|
;; Operand 0: LO
|
;; Operand 1: GPR (1st multiplication operand)
|
;; Operand 1: GPR (1st multiplication operand)
|
;; Operand 2: GPR (2nd multiplication operand)
|
;; Operand 2: GPR (2nd multiplication operand)
|
;; Operand 3: GPR (destination)
|
;; Operand 3: GPR (destination)
|
(define_peephole2
|
(define_peephole2
|
[(set (match_operand:SI 0 "lo_operand")
|
[(set (match_operand:SI 0 "lo_operand")
|
(mult:SI (match_operand:SI 1 "d_operand")
|
(mult:SI (match_operand:SI 1 "d_operand")
|
(match_operand:SI 2 "d_operand")))
|
(match_operand:SI 2 "d_operand")))
|
(set (match_operand:SI 3 "d_operand")
|
(set (match_operand:SI 3 "d_operand")
|
(match_dup 0))]
|
(match_dup 0))]
|
"ISA_HAS_MACC && !ISA_HAS_MUL3"
|
"ISA_HAS_MACC && !ISA_HAS_MUL3"
|
[(set (match_dup 0)
|
[(set (match_dup 0)
|
(const_int 0))
|
(const_int 0))
|
(parallel
|
(parallel
|
[(set (match_dup 0)
|
[(set (match_dup 0)
|
(plus:SI (mult:SI (match_dup 1)
|
(plus:SI (mult:SI (match_dup 1)
|
(match_dup 2))
|
(match_dup 2))
|
(match_dup 0)))
|
(match_dup 0)))
|
(set (match_dup 3)
|
(set (match_dup 3)
|
(plus:SI (mult:SI (match_dup 1)
|
(plus:SI (mult:SI (match_dup 1)
|
(match_dup 2))
|
(match_dup 2))
|
(match_dup 0)))])])
|
(match_dup 0)))])])
|
|
|
;; Multiply-accumulate patterns
|
;; Multiply-accumulate patterns
|
|
|
;; This pattern is first matched by combine, which tries to use the
|
;; This pattern is first matched by combine, which tries to use the
|
;; pattern wherever it can. We don't know until later whether it
|
;; pattern wherever it can. We don't know until later whether it
|
;; is actually profitable to use MADD over a "MUL; ADDIU" sequence,
|
;; is actually profitable to use MADD over a "MUL; ADDIU" sequence,
|
;; so we need to keep both options open.
|
;; so we need to keep both options open.
|
;;
|
;;
|
;; The second alternative has a "?" marker because it is generally
|
;; The second alternative has a "?" marker because it is generally
|
;; one instruction more costly than the first alternative. This "?"
|
;; one instruction more costly than the first alternative. This "?"
|
;; marker is enough to convey the relative costs to the register
|
;; marker is enough to convey the relative costs to the register
|
;; allocator.
|
;; allocator.
|
;;
|
;;
|
;; However, reload counts reloads of operands 4 and 5 in the same way as
|
;; However, reload counts reloads of operands 4 and 5 in the same way as
|
;; reloads of the other operands, even though operands 4 and 5 need no
|
;; reloads of the other operands, even though operands 4 and 5 need no
|
;; copy instructions. Reload therefore thinks that the second alternative
|
;; copy instructions. Reload therefore thinks that the second alternative
|
;; is two reloads more costly than the first. We add "*?*?" to the first
|
;; is two reloads more costly than the first. We add "*?*?" to the first
|
;; alternative as a counterweight.
|
;; alternative as a counterweight.
|
(define_insn "*mul_acc_si"
|
(define_insn "*mul_acc_si"
|
[(set (match_operand:SI 0 "register_operand" "=l*?*?,d?")
|
[(set (match_operand:SI 0 "register_operand" "=l*?*?,d?")
|
(plus:SI (mult:SI (match_operand:SI 1 "register_operand" "d,d")
|
(plus:SI (mult:SI (match_operand:SI 1 "register_operand" "d,d")
|
(match_operand:SI 2 "register_operand" "d,d"))
|
(match_operand:SI 2 "register_operand" "d,d"))
|
(match_operand:SI 3 "register_operand" "0,d")))
|
(match_operand:SI 3 "register_operand" "0,d")))
|
(clobber (match_scratch:SI 4 "=X,l"))
|
(clobber (match_scratch:SI 4 "=X,l"))
|
(clobber (match_scratch:SI 5 "=X,&d"))]
|
(clobber (match_scratch:SI 5 "=X,&d"))]
|
"GENERATE_MADD_MSUB && !TARGET_MIPS16"
|
"GENERATE_MADD_MSUB && !TARGET_MIPS16"
|
"@
|
"@
|
madd\t%1,%2
|
madd\t%1,%2
|
#"
|
#"
|
[(set_attr "type" "imadd")
|
[(set_attr "type" "imadd")
|
(set_attr "mode" "SI")
|
(set_attr "mode" "SI")
|
(set_attr "length" "4,8")])
|
(set_attr "length" "4,8")])
|
|
|
;; The same idea applies here. The middle alternative needs one less
|
;; The same idea applies here. The middle alternative needs one less
|
;; clobber than the final alternative, so we add "*?" as a counterweight.
|
;; clobber than the final alternative, so we add "*?" as a counterweight.
|
(define_insn "*mul_acc_si_r3900"
|
(define_insn "*mul_acc_si_r3900"
|
[(set (match_operand:SI 0 "register_operand" "=l*?*?,d*?,d?")
|
[(set (match_operand:SI 0 "register_operand" "=l*?*?,d*?,d?")
|
(plus:SI (mult:SI (match_operand:SI 1 "register_operand" "d,d,d")
|
(plus:SI (mult:SI (match_operand:SI 1 "register_operand" "d,d,d")
|
(match_operand:SI 2 "register_operand" "d,d,d"))
|
(match_operand:SI 2 "register_operand" "d,d,d"))
|
(match_operand:SI 3 "register_operand" "0,l,d")))
|
(match_operand:SI 3 "register_operand" "0,l,d")))
|
(clobber (match_scratch:SI 4 "=X,3,l"))
|
(clobber (match_scratch:SI 4 "=X,3,l"))
|
(clobber (match_scratch:SI 5 "=X,X,&d"))]
|
(clobber (match_scratch:SI 5 "=X,X,&d"))]
|
"TARGET_MIPS3900 && !TARGET_MIPS16"
|
"TARGET_MIPS3900 && !TARGET_MIPS16"
|
"@
|
"@
|
madd\t%1,%2
|
madd\t%1,%2
|
madd\t%0,%1,%2
|
madd\t%0,%1,%2
|
#"
|
#"
|
[(set_attr "type" "imadd")
|
[(set_attr "type" "imadd")
|
(set_attr "mode" "SI")
|
(set_attr "mode" "SI")
|
(set_attr "length" "4,4,8")])
|
(set_attr "length" "4,4,8")])
|
|
|
;; Split *mul_acc_si if both the source and destination accumulator
|
;; Split *mul_acc_si if both the source and destination accumulator
|
;; values are GPRs.
|
;; values are GPRs.
|
(define_split
|
(define_split
|
[(set (match_operand:SI 0 "d_operand")
|
[(set (match_operand:SI 0 "d_operand")
|
(plus:SI (mult:SI (match_operand:SI 1 "d_operand")
|
(plus:SI (mult:SI (match_operand:SI 1 "d_operand")
|
(match_operand:SI 2 "d_operand"))
|
(match_operand:SI 2 "d_operand"))
|
(match_operand:SI 3 "d_operand")))
|
(match_operand:SI 3 "d_operand")))
|
(clobber (match_operand:SI 4 "lo_operand"))
|
(clobber (match_operand:SI 4 "lo_operand"))
|
(clobber (match_operand:SI 5 "d_operand"))]
|
(clobber (match_operand:SI 5 "d_operand"))]
|
"reload_completed"
|
"reload_completed"
|
[(parallel [(set (match_dup 5)
|
[(parallel [(set (match_dup 5)
|
(mult:SI (match_dup 1) (match_dup 2)))
|
(mult:SI (match_dup 1) (match_dup 2)))
|
(clobber (match_dup 4))])
|
(clobber (match_dup 4))])
|
(set (match_dup 0) (plus:SI (match_dup 5) (match_dup 3)))]
|
(set (match_dup 0) (plus:SI (match_dup 5) (match_dup 3)))]
|
"")
|
"")
|
|
|
(define_insn "*macc"
|
(define_insn "*macc"
|
[(set (match_operand:SI 0 "register_operand" "=l,d")
|
[(set (match_operand:SI 0 "register_operand" "=l,d")
|
(plus:SI (mult:SI (match_operand:SI 1 "register_operand" "d,d")
|
(plus:SI (mult:SI (match_operand:SI 1 "register_operand" "d,d")
|
(match_operand:SI 2 "register_operand" "d,d"))
|
(match_operand:SI 2 "register_operand" "d,d"))
|
(match_operand:SI 3 "register_operand" "0,l")))
|
(match_operand:SI 3 "register_operand" "0,l")))
|
(clobber (match_scratch:SI 4 "=X,3"))]
|
(clobber (match_scratch:SI 4 "=X,3"))]
|
"ISA_HAS_MACC"
|
"ISA_HAS_MACC"
|
{
|
{
|
if (which_alternative == 1)
|
if (which_alternative == 1)
|
return "macc\t%0,%1,%2";
|
return "macc\t%0,%1,%2";
|
else if (TARGET_MIPS5500)
|
else if (TARGET_MIPS5500)
|
return "madd\t%1,%2";
|
return "madd\t%1,%2";
|
else
|
else
|
/* The VR4130 assumes that there is a two-cycle latency between a macc
|
/* The VR4130 assumes that there is a two-cycle latency between a macc
|
that "writes" to $0 and an instruction that reads from it. We avoid
|
that "writes" to $0 and an instruction that reads from it. We avoid
|
this by assigning to $1 instead. */
|
this by assigning to $1 instead. */
|
return "%[macc\t%@,%1,%2%]";
|
return "%[macc\t%@,%1,%2%]";
|
}
|
}
|
[(set_attr "type" "imadd")
|
[(set_attr "type" "imadd")
|
(set_attr "mode" "SI")])
|
(set_attr "mode" "SI")])
|
|
|
(define_insn "*msac"
|
(define_insn "*msac"
|
[(set (match_operand:SI 0 "register_operand" "=l,d")
|
[(set (match_operand:SI 0 "register_operand" "=l,d")
|
(minus:SI (match_operand:SI 1 "register_operand" "0,l")
|
(minus:SI (match_operand:SI 1 "register_operand" "0,l")
|
(mult:SI (match_operand:SI 2 "register_operand" "d,d")
|
(mult:SI (match_operand:SI 2 "register_operand" "d,d")
|
(match_operand:SI 3 "register_operand" "d,d"))))
|
(match_operand:SI 3 "register_operand" "d,d"))))
|
(clobber (match_scratch:SI 4 "=X,1"))]
|
(clobber (match_scratch:SI 4 "=X,1"))]
|
"ISA_HAS_MSAC"
|
"ISA_HAS_MSAC"
|
{
|
{
|
if (which_alternative == 1)
|
if (which_alternative == 1)
|
return "msac\t%0,%2,%3";
|
return "msac\t%0,%2,%3";
|
else if (TARGET_MIPS5500)
|
else if (TARGET_MIPS5500)
|
return "msub\t%2,%3";
|
return "msub\t%2,%3";
|
else
|
else
|
return "msac\t$0,%2,%3";
|
return "msac\t$0,%2,%3";
|
}
|
}
|
[(set_attr "type" "imadd")
|
[(set_attr "type" "imadd")
|
(set_attr "mode" "SI")])
|
(set_attr "mode" "SI")])
|
|
|
;; An msac-like instruction implemented using negation and a macc.
|
;; An msac-like instruction implemented using negation and a macc.
|
(define_insn_and_split "*msac_using_macc"
|
(define_insn_and_split "*msac_using_macc"
|
[(set (match_operand:SI 0 "register_operand" "=l,d")
|
[(set (match_operand:SI 0 "register_operand" "=l,d")
|
(minus:SI (match_operand:SI 1 "register_operand" "0,l")
|
(minus:SI (match_operand:SI 1 "register_operand" "0,l")
|
(mult:SI (match_operand:SI 2 "register_operand" "d,d")
|
(mult:SI (match_operand:SI 2 "register_operand" "d,d")
|
(match_operand:SI 3 "register_operand" "d,d"))))
|
(match_operand:SI 3 "register_operand" "d,d"))))
|
(clobber (match_scratch:SI 4 "=X,1"))
|
(clobber (match_scratch:SI 4 "=X,1"))
|
(clobber (match_scratch:SI 5 "=d,d"))]
|
(clobber (match_scratch:SI 5 "=d,d"))]
|
"ISA_HAS_MACC && !ISA_HAS_MSAC"
|
"ISA_HAS_MACC && !ISA_HAS_MSAC"
|
"#"
|
"#"
|
"&& reload_completed"
|
"&& reload_completed"
|
[(set (match_dup 5)
|
[(set (match_dup 5)
|
(neg:SI (match_dup 3)))
|
(neg:SI (match_dup 3)))
|
(parallel
|
(parallel
|
[(set (match_dup 0)
|
[(set (match_dup 0)
|
(plus:SI (mult:SI (match_dup 2)
|
(plus:SI (mult:SI (match_dup 2)
|
(match_dup 5))
|
(match_dup 5))
|
(match_dup 1)))
|
(match_dup 1)))
|
(clobber (match_dup 4))])]
|
(clobber (match_dup 4))])]
|
""
|
""
|
[(set_attr "type" "imadd")
|
[(set_attr "type" "imadd")
|
(set_attr "length" "8")])
|
(set_attr "length" "8")])
|
|
|
;; Patterns generated by the define_peephole2 below.
|
;; Patterns generated by the define_peephole2 below.
|
|
|
(define_insn "*macc2"
|
(define_insn "*macc2"
|
[(set (match_operand:SI 0 "register_operand" "=l")
|
[(set (match_operand:SI 0 "register_operand" "=l")
|
(plus:SI (mult:SI (match_operand:SI 1 "register_operand" "d")
|
(plus:SI (mult:SI (match_operand:SI 1 "register_operand" "d")
|
(match_operand:SI 2 "register_operand" "d"))
|
(match_operand:SI 2 "register_operand" "d"))
|
(match_dup 0)))
|
(match_dup 0)))
|
(set (match_operand:SI 3 "register_operand" "=d")
|
(set (match_operand:SI 3 "register_operand" "=d")
|
(plus:SI (mult:SI (match_dup 1)
|
(plus:SI (mult:SI (match_dup 1)
|
(match_dup 2))
|
(match_dup 2))
|
(match_dup 0)))]
|
(match_dup 0)))]
|
"ISA_HAS_MACC && reload_completed"
|
"ISA_HAS_MACC && reload_completed"
|
"macc\t%3,%1,%2"
|
"macc\t%3,%1,%2"
|
[(set_attr "type" "imadd")
|
[(set_attr "type" "imadd")
|
(set_attr "mode" "SI")])
|
(set_attr "mode" "SI")])
|
|
|
(define_insn "*msac2"
|
(define_insn "*msac2"
|
[(set (match_operand:SI 0 "register_operand" "=l")
|
[(set (match_operand:SI 0 "register_operand" "=l")
|
(minus:SI (match_dup 0)
|
(minus:SI (match_dup 0)
|
(mult:SI (match_operand:SI 1 "register_operand" "d")
|
(mult:SI (match_operand:SI 1 "register_operand" "d")
|
(match_operand:SI 2 "register_operand" "d"))))
|
(match_operand:SI 2 "register_operand" "d"))))
|
(set (match_operand:SI 3 "register_operand" "=d")
|
(set (match_operand:SI 3 "register_operand" "=d")
|
(minus:SI (match_dup 0)
|
(minus:SI (match_dup 0)
|
(mult:SI (match_dup 1)
|
(mult:SI (match_dup 1)
|
(match_dup 2))))]
|
(match_dup 2))))]
|
"ISA_HAS_MSAC && reload_completed"
|
"ISA_HAS_MSAC && reload_completed"
|
"msac\t%3,%1,%2"
|
"msac\t%3,%1,%2"
|
[(set_attr "type" "imadd")
|
[(set_attr "type" "imadd")
|
(set_attr "mode" "SI")])
|
(set_attr "mode" "SI")])
|
|
|
;; Convert macc $0,, & mflo into macc ,,
|
;; Convert macc $0,, & mflo into macc ,,
|
;; Similarly msac.
|
;; Similarly msac.
|
;;
|
;;
|
;; Operand 0: LO
|
;; Operand 0: LO
|
;; Operand 1: macc/msac
|
;; Operand 1: macc/msac
|
;; Operand 2: GPR (destination)
|
;; Operand 2: GPR (destination)
|
(define_peephole2
|
(define_peephole2
|
[(parallel
|
[(parallel
|
[(set (match_operand:SI 0 "lo_operand")
|
[(set (match_operand:SI 0 "lo_operand")
|
(match_operand:SI 1 "macc_msac_operand"))
|
(match_operand:SI 1 "macc_msac_operand"))
|
(clobber (scratch:SI))])
|
(clobber (scratch:SI))])
|
(set (match_operand:SI 2 "d_operand")
|
(set (match_operand:SI 2 "d_operand")
|
(match_dup 0))]
|
(match_dup 0))]
|
""
|
""
|
[(parallel [(set (match_dup 0)
|
[(parallel [(set (match_dup 0)
|
(match_dup 1))
|
(match_dup 1))
|
(set (match_dup 2)
|
(set (match_dup 2)
|
(match_dup 1))])])
|
(match_dup 1))])])
|
|
|
;; When we have a three-address multiplication instruction, it should
|
;; When we have a three-address multiplication instruction, it should
|
;; be faster to do a separate multiply and add, rather than moving
|
;; be faster to do a separate multiply and add, rather than moving
|
;; something into LO in order to use a macc instruction.
|
;; something into LO in order to use a macc instruction.
|
;;
|
;;
|
;; This peephole needs a scratch register to cater for the case when one
|
;; This peephole needs a scratch register to cater for the case when one
|
;; of the multiplication operands is the same as the destination.
|
;; of the multiplication operands is the same as the destination.
|
;;
|
;;
|
;; Operand 0: GPR (scratch)
|
;; Operand 0: GPR (scratch)
|
;; Operand 1: LO
|
;; Operand 1: LO
|
;; Operand 2: GPR (addend)
|
;; Operand 2: GPR (addend)
|
;; Operand 3: GPR (destination)
|
;; Operand 3: GPR (destination)
|
;; Operand 4: macc/msac
|
;; Operand 4: macc/msac
|
;; Operand 5: new multiplication
|
;; Operand 5: new multiplication
|
;; Operand 6: new addition/subtraction
|
;; Operand 6: new addition/subtraction
|
(define_peephole2
|
(define_peephole2
|
[(match_scratch:SI 0 "d")
|
[(match_scratch:SI 0 "d")
|
(set (match_operand:SI 1 "lo_operand")
|
(set (match_operand:SI 1 "lo_operand")
|
(match_operand:SI 2 "d_operand"))
|
(match_operand:SI 2 "d_operand"))
|
(match_dup 0)
|
(match_dup 0)
|
(parallel
|
(parallel
|
[(set (match_operand:SI 3 "d_operand")
|
[(set (match_operand:SI 3 "d_operand")
|
(match_operand:SI 4 "macc_msac_operand"))
|
(match_operand:SI 4 "macc_msac_operand"))
|
(clobber (match_dup 1))])]
|
(clobber (match_dup 1))])]
|
"ISA_HAS_MUL3 && peep2_reg_dead_p (2, operands[1])"
|
"ISA_HAS_MUL3 && peep2_reg_dead_p (2, operands[1])"
|
[(parallel [(set (match_dup 0)
|
[(parallel [(set (match_dup 0)
|
(match_dup 5))
|
(match_dup 5))
|
(clobber (match_dup 1))])
|
(clobber (match_dup 1))])
|
(set (match_dup 3)
|
(set (match_dup 3)
|
(match_dup 6))]
|
(match_dup 6))]
|
{
|
{
|
operands[5] = XEXP (operands[4], GET_CODE (operands[4]) == PLUS ? 0 : 1);
|
operands[5] = XEXP (operands[4], GET_CODE (operands[4]) == PLUS ? 0 : 1);
|
operands[6] = gen_rtx_fmt_ee (GET_CODE (operands[4]), SImode,
|
operands[6] = gen_rtx_fmt_ee (GET_CODE (operands[4]), SImode,
|
operands[2], operands[0]);
|
operands[2], operands[0]);
|
})
|
})
|
|
|
;; Same as above, except LO is the initial target of the macc.
|
;; Same as above, except LO is the initial target of the macc.
|
;;
|
;;
|
;; Operand 0: GPR (scratch)
|
;; Operand 0: GPR (scratch)
|
;; Operand 1: LO
|
;; Operand 1: LO
|
;; Operand 2: GPR (addend)
|
;; Operand 2: GPR (addend)
|
;; Operand 3: macc/msac
|
;; Operand 3: macc/msac
|
;; Operand 4: GPR (destination)
|
;; Operand 4: GPR (destination)
|
;; Operand 5: new multiplication
|
;; Operand 5: new multiplication
|
;; Operand 6: new addition/subtraction
|
;; Operand 6: new addition/subtraction
|
(define_peephole2
|
(define_peephole2
|
[(match_scratch:SI 0 "d")
|
[(match_scratch:SI 0 "d")
|
(set (match_operand:SI 1 "lo_operand")
|
(set (match_operand:SI 1 "lo_operand")
|
(match_operand:SI 2 "d_operand"))
|
(match_operand:SI 2 "d_operand"))
|
(match_dup 0)
|
(match_dup 0)
|
(parallel
|
(parallel
|
[(set (match_dup 1)
|
[(set (match_dup 1)
|
(match_operand:SI 3 "macc_msac_operand"))
|
(match_operand:SI 3 "macc_msac_operand"))
|
(clobber (scratch:SI))])
|
(clobber (scratch:SI))])
|
(match_dup 0)
|
(match_dup 0)
|
(set (match_operand:SI 4 "d_operand")
|
(set (match_operand:SI 4 "d_operand")
|
(match_dup 1))]
|
(match_dup 1))]
|
"ISA_HAS_MUL3 && peep2_reg_dead_p (3, operands[1])"
|
"ISA_HAS_MUL3 && peep2_reg_dead_p (3, operands[1])"
|
[(parallel [(set (match_dup 0)
|
[(parallel [(set (match_dup 0)
|
(match_dup 5))
|
(match_dup 5))
|
(clobber (match_dup 1))])
|
(clobber (match_dup 1))])
|
(set (match_dup 4)
|
(set (match_dup 4)
|
(match_dup 6))]
|
(match_dup 6))]
|
{
|
{
|
operands[5] = XEXP (operands[3], GET_CODE (operands[3]) == PLUS ? 0 : 1);
|
operands[5] = XEXP (operands[3], GET_CODE (operands[3]) == PLUS ? 0 : 1);
|
operands[6] = gen_rtx_fmt_ee (GET_CODE (operands[3]), SImode,
|
operands[6] = gen_rtx_fmt_ee (GET_CODE (operands[3]), SImode,
|
operands[2], operands[0]);
|
operands[2], operands[0]);
|
})
|
})
|
|
|
;; See the comment above *mul_add_si for details.
|
;; See the comment above *mul_add_si for details.
|
(define_insn "*mul_sub_si"
|
(define_insn "*mul_sub_si"
|
[(set (match_operand:SI 0 "register_operand" "=l*?*?,d?")
|
[(set (match_operand:SI 0 "register_operand" "=l*?*?,d?")
|
(minus:SI (match_operand:SI 1 "register_operand" "0,d")
|
(minus:SI (match_operand:SI 1 "register_operand" "0,d")
|
(mult:SI (match_operand:SI 2 "register_operand" "d,d")
|
(mult:SI (match_operand:SI 2 "register_operand" "d,d")
|
(match_operand:SI 3 "register_operand" "d,d"))))
|
(match_operand:SI 3 "register_operand" "d,d"))))
|
(clobber (match_scratch:SI 4 "=X,l"))
|
(clobber (match_scratch:SI 4 "=X,l"))
|
(clobber (match_scratch:SI 5 "=X,&d"))]
|
(clobber (match_scratch:SI 5 "=X,&d"))]
|
"GENERATE_MADD_MSUB"
|
"GENERATE_MADD_MSUB"
|
"@
|
"@
|
msub\t%2,%3
|
msub\t%2,%3
|
#"
|
#"
|
[(set_attr "type" "imadd")
|
[(set_attr "type" "imadd")
|
(set_attr "mode" "SI")
|
(set_attr "mode" "SI")
|
(set_attr "length" "4,8")])
|
(set_attr "length" "4,8")])
|
|
|
;; Split *mul_sub_si if both the source and destination accumulator
|
;; Split *mul_sub_si if both the source and destination accumulator
|
;; values are GPRs.
|
;; values are GPRs.
|
(define_split
|
(define_split
|
[(set (match_operand:SI 0 "d_operand")
|
[(set (match_operand:SI 0 "d_operand")
|
(minus:SI (match_operand:SI 1 "d_operand")
|
(minus:SI (match_operand:SI 1 "d_operand")
|
(mult:SI (match_operand:SI 2 "d_operand")
|
(mult:SI (match_operand:SI 2 "d_operand")
|
(match_operand:SI 3 "d_operand"))))
|
(match_operand:SI 3 "d_operand"))))
|
(clobber (match_operand:SI 4 "lo_operand"))
|
(clobber (match_operand:SI 4 "lo_operand"))
|
(clobber (match_operand:SI 5 "d_operand"))]
|
(clobber (match_operand:SI 5 "d_operand"))]
|
"reload_completed"
|
"reload_completed"
|
[(parallel [(set (match_dup 5)
|
[(parallel [(set (match_dup 5)
|
(mult:SI (match_dup 2) (match_dup 3)))
|
(mult:SI (match_dup 2) (match_dup 3)))
|
(clobber (match_dup 4))])
|
(clobber (match_dup 4))])
|
(set (match_dup 0) (minus:SI (match_dup 1) (match_dup 5)))]
|
(set (match_dup 0) (minus:SI (match_dup 1) (match_dup 5)))]
|
"")
|
"")
|
|
|
(define_insn "*muls"
|
(define_insn "*muls"
|
[(set (match_operand:SI 0 "register_operand" "=l,d")
|
[(set (match_operand:SI 0 "register_operand" "=l,d")
|
(neg:SI (mult:SI (match_operand:SI 1 "register_operand" "d,d")
|
(neg:SI (mult:SI (match_operand:SI 1 "register_operand" "d,d")
|
(match_operand:SI 2 "register_operand" "d,d"))))
|
(match_operand:SI 2 "register_operand" "d,d"))))
|
(clobber (match_scratch:SI 3 "=X,l"))]
|
(clobber (match_scratch:SI 3 "=X,l"))]
|
"ISA_HAS_MULS"
|
"ISA_HAS_MULS"
|
"@
|
"@
|
muls\t$0,%1,%2
|
muls\t$0,%1,%2
|
muls\t%0,%1,%2"
|
muls\t%0,%1,%2"
|
[(set_attr "type" "imul,imul3")
|
[(set_attr "type" "imul,imul3")
|
(set_attr "mode" "SI")])
|
(set_attr "mode" "SI")])
|
|
|
(define_expand "mulsidi3"
|
(define_expand "mulsidi3"
|
[(set (match_operand:DI 0 "register_operand")
|
[(set (match_operand:DI 0 "register_operand")
|
(mult:DI (any_extend:DI (match_operand:SI 1 "register_operand"))
|
(mult:DI (any_extend:DI (match_operand:SI 1 "register_operand"))
|
(any_extend:DI (match_operand:SI 2 "register_operand"))))]
|
(any_extend:DI (match_operand:SI 2 "register_operand"))))]
|
"mips_mulsidi3_gen_fn () != NULL"
|
"mips_mulsidi3_gen_fn () != NULL"
|
{
|
{
|
mulsidi3_gen_fn fn = mips_mulsidi3_gen_fn ();
|
mulsidi3_gen_fn fn = mips_mulsidi3_gen_fn ();
|
emit_insn (fn (operands[0], operands[1], operands[2]));
|
emit_insn (fn (operands[0], operands[1], operands[2]));
|
DONE;
|
DONE;
|
})
|
})
|
|
|
(define_insn "mulsidi3_32bit"
|
(define_insn "mulsidi3_32bit"
|
[(set (match_operand:DI 0 "register_operand" "=x")
|
[(set (match_operand:DI 0 "register_operand" "=x")
|
(mult:DI (any_extend:DI (match_operand:SI 1 "register_operand" "d"))
|
(mult:DI (any_extend:DI (match_operand:SI 1 "register_operand" "d"))
|
(any_extend:DI (match_operand:SI 2 "register_operand" "d"))))]
|
(any_extend:DI (match_operand:SI 2 "register_operand" "d"))))]
|
"!TARGET_64BIT && !TARGET_FIX_R4000 && !ISA_HAS_DSPR2"
|
"!TARGET_64BIT && !TARGET_FIX_R4000 && !ISA_HAS_DSPR2"
|
"mult\t%1,%2"
|
"mult\t%1,%2"
|
[(set_attr "type" "imul")
|
[(set_attr "type" "imul")
|
(set_attr "mode" "SI")])
|
(set_attr "mode" "SI")])
|
|
|
(define_insn "mulsidi3_32bit_r4000"
|
(define_insn "mulsidi3_32bit_r4000"
|
[(set (match_operand:DI 0 "register_operand" "=d")
|
[(set (match_operand:DI 0 "register_operand" "=d")
|
(mult:DI (any_extend:DI (match_operand:SI 1 "register_operand" "d"))
|
(mult:DI (any_extend:DI (match_operand:SI 1 "register_operand" "d"))
|
(any_extend:DI (match_operand:SI 2 "register_operand" "d"))))
|
(any_extend:DI (match_operand:SI 2 "register_operand" "d"))))
|
(clobber (match_scratch:DI 3 "=x"))]
|
(clobber (match_scratch:DI 3 "=x"))]
|
"!TARGET_64BIT && TARGET_FIX_R4000"
|
"!TARGET_64BIT && TARGET_FIX_R4000"
|
"mult\t%1,%2\;mflo\t%L0\;mfhi\t%M0"
|
"mult\t%1,%2\;mflo\t%L0\;mfhi\t%M0"
|
[(set_attr "type" "imul")
|
[(set_attr "type" "imul")
|
(set_attr "mode" "SI")
|
(set_attr "mode" "SI")
|
(set_attr "length" "12")])
|
(set_attr "length" "12")])
|
|
|
(define_insn "mulsidi3_64bit"
|
(define_insn "mulsidi3_64bit"
|
[(set (match_operand:DI 0 "register_operand" "=d")
|
[(set (match_operand:DI 0 "register_operand" "=d")
|
(mult:DI (any_extend:DI (match_operand:SI 1 "register_operand" "d"))
|
(mult:DI (any_extend:DI (match_operand:SI 1 "register_operand" "d"))
|
(any_extend:DI (match_operand:SI 2 "register_operand" "d"))))
|
(any_extend:DI (match_operand:SI 2 "register_operand" "d"))))
|
(clobber (match_scratch:TI 3 "=x"))
|
(clobber (match_scratch:TI 3 "=x"))
|
(clobber (match_scratch:DI 4 "=d"))]
|
(clobber (match_scratch:DI 4 "=d"))]
|
"TARGET_64BIT && !TARGET_FIX_R4000 && !ISA_HAS_DMUL3"
|
"TARGET_64BIT && !TARGET_FIX_R4000 && !ISA_HAS_DMUL3"
|
"#"
|
"#"
|
[(set_attr "type" "imul")
|
[(set_attr "type" "imul")
|
(set_attr "mode" "SI")
|
(set_attr "mode" "SI")
|
(set (attr "length")
|
(set (attr "length")
|
(if_then_else (ne (symbol_ref "ISA_HAS_EXT_INS") (const_int 0))
|
(if_then_else (ne (symbol_ref "ISA_HAS_EXT_INS") (const_int 0))
|
(const_int 16)
|
(const_int 16)
|
(const_int 28)))])
|
(const_int 28)))])
|
|
|
(define_split
|
(define_split
|
[(set (match_operand:DI 0 "d_operand")
|
[(set (match_operand:DI 0 "d_operand")
|
(mult:DI (any_extend:DI (match_operand:SI 1 "d_operand"))
|
(mult:DI (any_extend:DI (match_operand:SI 1 "d_operand"))
|
(any_extend:DI (match_operand:SI 2 "d_operand"))))
|
(any_extend:DI (match_operand:SI 2 "d_operand"))))
|
(clobber (match_operand:TI 3 "hilo_operand"))
|
(clobber (match_operand:TI 3 "hilo_operand"))
|
(clobber (match_operand:DI 4 "d_operand"))]
|
(clobber (match_operand:DI 4 "d_operand"))]
|
"TARGET_64BIT && !TARGET_FIX_R4000 && ISA_HAS_EXT_INS && reload_completed"
|
"TARGET_64BIT && !TARGET_FIX_R4000 && ISA_HAS_EXT_INS && reload_completed"
|
[(set (match_dup 3)
|
[(set (match_dup 3)
|
(unspec:TI [(mult:DI (any_extend:DI (match_dup 1))
|
(unspec:TI [(mult:DI (any_extend:DI (match_dup 1))
|
(any_extend:DI (match_dup 2)))]
|
(any_extend:DI (match_dup 2)))]
|
UNSPEC_SET_HILO))
|
UNSPEC_SET_HILO))
|
|
|
;; OP0 <- LO, OP4 <- HI
|
;; OP0 <- LO, OP4 <- HI
|
(set (match_dup 0) (match_dup 5))
|
(set (match_dup 0) (match_dup 5))
|
(set (match_dup 4) (unspec:DI [(match_dup 3)] UNSPEC_MFHI))
|
(set (match_dup 4) (unspec:DI [(match_dup 3)] UNSPEC_MFHI))
|
|
|
(set (zero_extract:DI (match_dup 0) (const_int 32) (const_int 32))
|
(set (zero_extract:DI (match_dup 0) (const_int 32) (const_int 32))
|
(match_dup 4))]
|
(match_dup 4))]
|
{ operands[5] = gen_rtx_REG (DImode, LO_REGNUM); })
|
{ operands[5] = gen_rtx_REG (DImode, LO_REGNUM); })
|
|
|
(define_split
|
(define_split
|
[(set (match_operand:DI 0 "d_operand")
|
[(set (match_operand:DI 0 "d_operand")
|
(mult:DI (any_extend:DI (match_operand:SI 1 "d_operand"))
|
(mult:DI (any_extend:DI (match_operand:SI 1 "d_operand"))
|
(any_extend:DI (match_operand:SI 2 "d_operand"))))
|
(any_extend:DI (match_operand:SI 2 "d_operand"))))
|
(clobber (match_operand:TI 3 "hilo_operand"))
|
(clobber (match_operand:TI 3 "hilo_operand"))
|
(clobber (match_operand:DI 4 "d_operand"))]
|
(clobber (match_operand:DI 4 "d_operand"))]
|
"TARGET_64BIT && !TARGET_FIX_R4000 && !ISA_HAS_EXT_INS && reload_completed"
|
"TARGET_64BIT && !TARGET_FIX_R4000 && !ISA_HAS_EXT_INS && reload_completed"
|
[(set (match_dup 3)
|
[(set (match_dup 3)
|
(unspec:TI [(mult:DI (any_extend:DI (match_dup 1))
|
(unspec:TI [(mult:DI (any_extend:DI (match_dup 1))
|
(any_extend:DI (match_dup 2)))]
|
(any_extend:DI (match_dup 2)))]
|
UNSPEC_SET_HILO))
|
UNSPEC_SET_HILO))
|
|
|
;; OP0 <- LO, OP4 <- HI
|
;; OP0 <- LO, OP4 <- HI
|
(set (match_dup 0) (match_dup 5))
|
(set (match_dup 0) (match_dup 5))
|
(set (match_dup 4) (unspec:DI [(match_dup 3)] UNSPEC_MFHI))
|
(set (match_dup 4) (unspec:DI [(match_dup 3)] UNSPEC_MFHI))
|
|
|
;; Zero-extend OP0.
|
;; Zero-extend OP0.
|
(set (match_dup 0)
|
(set (match_dup 0)
|
(ashift:DI (match_dup 0)
|
(ashift:DI (match_dup 0)
|
(const_int 32)))
|
(const_int 32)))
|
(set (match_dup 0)
|
(set (match_dup 0)
|
(lshiftrt:DI (match_dup 0)
|
(lshiftrt:DI (match_dup 0)
|
(const_int 32)))
|
(const_int 32)))
|
|
|
;; Shift OP4 into place.
|
;; Shift OP4 into place.
|
(set (match_dup 4)
|
(set (match_dup 4)
|
(ashift:DI (match_dup 4)
|
(ashift:DI (match_dup 4)
|
(const_int 32)))
|
(const_int 32)))
|
|
|
;; OR the two halves together
|
;; OR the two halves together
|
(set (match_dup 0)
|
(set (match_dup 0)
|
(ior:DI (match_dup 0)
|
(ior:DI (match_dup 0)
|
(match_dup 4)))]
|
(match_dup 4)))]
|
{ operands[5] = gen_rtx_REG (DImode, LO_REGNUM); })
|
{ operands[5] = gen_rtx_REG (DImode, LO_REGNUM); })
|
|
|
(define_insn "mulsidi3_64bit_hilo"
|
(define_insn "mulsidi3_64bit_hilo"
|
[(set (match_operand:TI 0 "register_operand" "=x")
|
[(set (match_operand:TI 0 "register_operand" "=x")
|
(unspec:TI
|
(unspec:TI
|
[(mult:DI
|
[(mult:DI
|
(any_extend:DI (match_operand:SI 1 "register_operand" "d"))
|
(any_extend:DI (match_operand:SI 1 "register_operand" "d"))
|
(any_extend:DI (match_operand:SI 2 "register_operand" "d")))]
|
(any_extend:DI (match_operand:SI 2 "register_operand" "d")))]
|
UNSPEC_SET_HILO))]
|
UNSPEC_SET_HILO))]
|
"TARGET_64BIT && !TARGET_FIX_R4000"
|
"TARGET_64BIT && !TARGET_FIX_R4000"
|
"mult\t%1,%2"
|
"mult\t%1,%2"
|
[(set_attr "type" "imul")
|
[(set_attr "type" "imul")
|
(set_attr "mode" "SI")])
|
(set_attr "mode" "SI")])
|
|
|
;; See comment before the ISA_HAS_DMUL3 case in mips_mulsidi3_gen_fn.
|
;; See comment before the ISA_HAS_DMUL3 case in mips_mulsidi3_gen_fn.
|
(define_insn "mulsidi3_64bit_dmul"
|
(define_insn "mulsidi3_64bit_dmul"
|
[(set (match_operand:DI 0 "register_operand" "=d")
|
[(set (match_operand:DI 0 "register_operand" "=d")
|
(mult:DI (sign_extend:DI (match_operand:SI 1 "register_operand" "d"))
|
(mult:DI (sign_extend:DI (match_operand:SI 1 "register_operand" "d"))
|
(sign_extend:DI (match_operand:SI 2 "register_operand" "d"))))
|
(sign_extend:DI (match_operand:SI 2 "register_operand" "d"))))
|
(clobber (match_scratch:DI 3 "=l"))]
|
(clobber (match_scratch:DI 3 "=l"))]
|
"TARGET_64BIT && ISA_HAS_DMUL3"
|
"TARGET_64BIT && ISA_HAS_DMUL3"
|
"dmul\t%0,%1,%2"
|
"dmul\t%0,%1,%2"
|
[(set_attr "type" "imul3")
|
[(set_attr "type" "imul3")
|
(set_attr "mode" "DI")])
|
(set_attr "mode" "DI")])
|
|
|
;; Widening multiply with negation.
|
;; Widening multiply with negation.
|
(define_insn "*muls_di"
|
(define_insn "*muls_di"
|
[(set (match_operand:DI 0 "register_operand" "=x")
|
[(set (match_operand:DI 0 "register_operand" "=x")
|
(neg:DI
|
(neg:DI
|
(mult:DI
|
(mult:DI
|
(any_extend:DI (match_operand:SI 1 "register_operand" "d"))
|
(any_extend:DI (match_operand:SI 1 "register_operand" "d"))
|
(any_extend:DI (match_operand:SI 2 "register_operand" "d")))))]
|
(any_extend:DI (match_operand:SI 2 "register_operand" "d")))))]
|
"!TARGET_64BIT && ISA_HAS_MULS"
|
"!TARGET_64BIT && ISA_HAS_MULS"
|
"muls\t$0,%1,%2"
|
"muls\t$0,%1,%2"
|
[(set_attr "type" "imul")
|
[(set_attr "type" "imul")
|
(set_attr "mode" "SI")])
|
(set_attr "mode" "SI")])
|
|
|
(define_insn "msubsidi4"
|
(define_insn "msubsidi4"
|
[(set (match_operand:DI 0 "register_operand" "=ka")
|
[(set (match_operand:DI 0 "register_operand" "=ka")
|
(minus:DI
|
(minus:DI
|
(match_operand:DI 3 "register_operand" "0")
|
(match_operand:DI 3 "register_operand" "0")
|
(mult:DI
|
(mult:DI
|
(any_extend:DI (match_operand:SI 1 "register_operand" "d"))
|
(any_extend:DI (match_operand:SI 1 "register_operand" "d"))
|
(any_extend:DI (match_operand:SI 2 "register_operand" "d")))))]
|
(any_extend:DI (match_operand:SI 2 "register_operand" "d")))))]
|
"!TARGET_64BIT && (ISA_HAS_MSAC || GENERATE_MADD_MSUB || ISA_HAS_DSPR2)"
|
"!TARGET_64BIT && (ISA_HAS_MSAC || GENERATE_MADD_MSUB || ISA_HAS_DSPR2)"
|
{
|
{
|
if (ISA_HAS_DSPR2)
|
if (ISA_HAS_DSPR2)
|
return "msub\t%q0,%1,%2";
|
return "msub\t%q0,%1,%2";
|
else if (TARGET_MIPS5500 || GENERATE_MADD_MSUB)
|
else if (TARGET_MIPS5500 || GENERATE_MADD_MSUB)
|
return "msub\t%1,%2";
|
return "msub\t%1,%2";
|
else
|
else
|
return "msac\t$0,%1,%2";
|
return "msac\t$0,%1,%2";
|
}
|
}
|
[(set_attr "type" "imadd")
|
[(set_attr "type" "imadd")
|
(set_attr "mode" "SI")])
|
(set_attr "mode" "SI")])
|
|
|
;; _highpart patterns
|
;; _highpart patterns
|
|
|
(define_expand "mulsi3_highpart"
|
(define_expand "mulsi3_highpart"
|
[(set (match_operand:SI 0 "register_operand")
|
[(set (match_operand:SI 0 "register_operand")
|
(truncate:SI
|
(truncate:SI
|
(lshiftrt:DI
|
(lshiftrt:DI
|
(mult:DI (any_extend:DI (match_operand:SI 1 "register_operand"))
|
(mult:DI (any_extend:DI (match_operand:SI 1 "register_operand"))
|
(any_extend:DI (match_operand:SI 2 "register_operand")))
|
(any_extend:DI (match_operand:SI 2 "register_operand")))
|
(const_int 32))))]
|
(const_int 32))))]
|
""
|
""
|
{
|
{
|
if (ISA_HAS_MULHI)
|
if (ISA_HAS_MULHI)
|
emit_insn (gen_mulsi3_highpart_mulhi_internal (operands[0],
|
emit_insn (gen_mulsi3_highpart_mulhi_internal (operands[0],
|
operands[1],
|
operands[1],
|
operands[2]));
|
operands[2]));
|
else
|
else
|
emit_insn (gen_mulsi3_highpart_internal (operands[0], operands[1],
|
emit_insn (gen_mulsi3_highpart_internal (operands[0], operands[1],
|
operands[2]));
|
operands[2]));
|
DONE;
|
DONE;
|
})
|
})
|
|
|
(define_insn_and_split "mulsi3_highpart_internal"
|
(define_insn_and_split "mulsi3_highpart_internal"
|
[(set (match_operand:SI 0 "register_operand" "=d")
|
[(set (match_operand:SI 0 "register_operand" "=d")
|
(truncate:SI
|
(truncate:SI
|
(lshiftrt:DI
|
(lshiftrt:DI
|
(mult:DI (any_extend:DI (match_operand:SI 1 "register_operand" "d"))
|
(mult:DI (any_extend:DI (match_operand:SI 1 "register_operand" "d"))
|
(any_extend:DI (match_operand:SI 2 "register_operand" "d")))
|
(any_extend:DI (match_operand:SI 2 "register_operand" "d")))
|
(const_int 32))))
|
(const_int 32))))
|
(clobber (match_scratch:SI 3 "=l"))]
|
(clobber (match_scratch:SI 3 "=l"))]
|
"!ISA_HAS_MULHI"
|
"!ISA_HAS_MULHI"
|
{ return TARGET_FIX_R4000 ? "mult\t%1,%2\n\tmfhi\t%0" : "#"; }
|
{ return TARGET_FIX_R4000 ? "mult\t%1,%2\n\tmfhi\t%0" : "#"; }
|
"&& reload_completed && !TARGET_FIX_R4000"
|
"&& reload_completed && !TARGET_FIX_R4000"
|
[(const_int 0)]
|
[(const_int 0)]
|
{
|
{
|
rtx hilo;
|
rtx hilo;
|
|
|
if (TARGET_64BIT)
|
if (TARGET_64BIT)
|
{
|
{
|
hilo = gen_rtx_REG (TImode, MD_REG_FIRST);
|
hilo = gen_rtx_REG (TImode, MD_REG_FIRST);
|
emit_insn (gen_mulsidi3_64bit_hilo (hilo, operands[1], operands[2]));
|
emit_insn (gen_mulsidi3_64bit_hilo (hilo, operands[1], operands[2]));
|
emit_insn (gen_mfhisi_ti (operands[0], hilo));
|
emit_insn (gen_mfhisi_ti (operands[0], hilo));
|
}
|
}
|
else
|
else
|
{
|
{
|
hilo = gen_rtx_REG (DImode, MD_REG_FIRST);
|
hilo = gen_rtx_REG (DImode, MD_REG_FIRST);
|
emit_insn (gen_mulsidi3_32bit (hilo, operands[1], operands[2]));
|
emit_insn (gen_mulsidi3_32bit (hilo, operands[1], operands[2]));
|
emit_insn (gen_mfhisi_di (operands[0], hilo));
|
emit_insn (gen_mfhisi_di (operands[0], hilo));
|
}
|
}
|
DONE;
|
DONE;
|
}
|
}
|
[(set_attr "type" "imul")
|
[(set_attr "type" "imul")
|
(set_attr "mode" "SI")
|
(set_attr "mode" "SI")
|
(set_attr "length" "8")])
|
(set_attr "length" "8")])
|
|
|
(define_insn "mulsi3_highpart_mulhi_internal"
|
(define_insn "mulsi3_highpart_mulhi_internal"
|
[(set (match_operand:SI 0 "register_operand" "=d")
|
[(set (match_operand:SI 0 "register_operand" "=d")
|
(truncate:SI
|
(truncate:SI
|
(lshiftrt:DI
|
(lshiftrt:DI
|
(mult:DI
|
(mult:DI
|
(any_extend:DI (match_operand:SI 1 "register_operand" "d"))
|
(any_extend:DI (match_operand:SI 1 "register_operand" "d"))
|
(any_extend:DI (match_operand:SI 2 "register_operand" "d")))
|
(any_extend:DI (match_operand:SI 2 "register_operand" "d")))
|
(const_int 32))))
|
(const_int 32))))
|
(clobber (match_scratch:SI 3 "=l"))]
|
(clobber (match_scratch:SI 3 "=l"))]
|
"ISA_HAS_MULHI"
|
"ISA_HAS_MULHI"
|
"mulhi\t%0,%1,%2"
|
"mulhi\t%0,%1,%2"
|
[(set_attr "type" "imul3")
|
[(set_attr "type" "imul3")
|
(set_attr "mode" "SI")])
|
(set_attr "mode" "SI")])
|
|
|
(define_insn "*mulsi3_highpart_neg_mulhi_internal"
|
(define_insn "*mulsi3_highpart_neg_mulhi_internal"
|
[(set (match_operand:SI 0 "register_operand" "=d")
|
[(set (match_operand:SI 0 "register_operand" "=d")
|
(truncate:SI
|
(truncate:SI
|
(lshiftrt:DI
|
(lshiftrt:DI
|
(neg:DI
|
(neg:DI
|
(mult:DI
|
(mult:DI
|
(any_extend:DI (match_operand:SI 1 "register_operand" "d"))
|
(any_extend:DI (match_operand:SI 1 "register_operand" "d"))
|
(any_extend:DI (match_operand:SI 2 "register_operand" "d"))))
|
(any_extend:DI (match_operand:SI 2 "register_operand" "d"))))
|
(const_int 32))))
|
(const_int 32))))
|
(clobber (match_scratch:SI 3 "=l"))]
|
(clobber (match_scratch:SI 3 "=l"))]
|
"ISA_HAS_MULHI"
|
"ISA_HAS_MULHI"
|
"mulshi\t%0,%1,%2"
|
"mulshi\t%0,%1,%2"
|
[(set_attr "type" "imul3")
|
[(set_attr "type" "imul3")
|
(set_attr "mode" "SI")])
|
(set_attr "mode" "SI")])
|
|
|
;; Disable unsigned multiplication for -mfix-vr4120. This is for VR4120
|
;; Disable unsigned multiplication for -mfix-vr4120. This is for VR4120
|
;; errata MD(0), which says that dmultu does not always produce the
|
;; errata MD(0), which says that dmultu does not always produce the
|
;; correct result.
|
;; correct result.
|
(define_insn_and_split "muldi3_highpart"
|
(define_insn_and_split "muldi3_highpart"
|
[(set (match_operand:DI 0 "register_operand" "=d")
|
[(set (match_operand:DI 0 "register_operand" "=d")
|
(truncate:DI
|
(truncate:DI
|
(lshiftrt:TI
|
(lshiftrt:TI
|
(mult:TI (any_extend:TI (match_operand:DI 1 "register_operand" "d"))
|
(mult:TI (any_extend:TI (match_operand:DI 1 "register_operand" "d"))
|
(any_extend:TI (match_operand:DI 2 "register_operand" "d")))
|
(any_extend:TI (match_operand:DI 2 "register_operand" "d")))
|
(const_int 64))))
|
(const_int 64))))
|
(clobber (match_scratch:DI 3 "=l"))]
|
(clobber (match_scratch:DI 3 "=l"))]
|
"TARGET_64BIT && !( == ZERO_EXTEND && TARGET_FIX_VR4120)"
|
"TARGET_64BIT && !( == ZERO_EXTEND && TARGET_FIX_VR4120)"
|
{ return TARGET_FIX_R4000 ? "dmult\t%1,%2\n\tmfhi\t%0" : "#"; }
|
{ return TARGET_FIX_R4000 ? "dmult\t%1,%2\n\tmfhi\t%0" : "#"; }
|
"&& reload_completed && !TARGET_FIX_R4000"
|
"&& reload_completed && !TARGET_FIX_R4000"
|
[(const_int 0)]
|
[(const_int 0)]
|
{
|
{
|
rtx hilo;
|
rtx hilo;
|
|
|
hilo = gen_rtx_REG (TImode, MD_REG_FIRST);
|
hilo = gen_rtx_REG (TImode, MD_REG_FIRST);
|
emit_insn (gen_mulditi3_internal (hilo, operands[1], operands[2]));
|
emit_insn (gen_mulditi3_internal (hilo, operands[1], operands[2]));
|
emit_insn (gen_mfhidi_ti (operands[0], hilo));
|
emit_insn (gen_mfhidi_ti (operands[0], hilo));
|
DONE;
|
DONE;
|
}
|
}
|
[(set_attr "type" "imul")
|
[(set_attr "type" "imul")
|
(set_attr "mode" "DI")
|
(set_attr "mode" "DI")
|
(set_attr "length" "8")])
|
(set_attr "length" "8")])
|
|
|
(define_expand "mulditi3"
|
(define_expand "mulditi3"
|
[(set (match_operand:TI 0 "register_operand")
|
[(set (match_operand:TI 0 "register_operand")
|
(mult:TI (any_extend:TI (match_operand:DI 1 "register_operand"))
|
(mult:TI (any_extend:TI (match_operand:DI 1 "register_operand"))
|
(any_extend:TI (match_operand:DI 2 "register_operand"))))]
|
(any_extend:TI (match_operand:DI 2 "register_operand"))))]
|
"TARGET_64BIT && !( == ZERO_EXTEND && TARGET_FIX_VR4120)"
|
"TARGET_64BIT && !( == ZERO_EXTEND && TARGET_FIX_VR4120)"
|
{
|
{
|
if (TARGET_FIX_R4000)
|
if (TARGET_FIX_R4000)
|
emit_insn (gen_mulditi3_r4000 (operands[0], operands[1], operands[2]));
|
emit_insn (gen_mulditi3_r4000 (operands[0], operands[1], operands[2]));
|
else
|
else
|
emit_insn (gen_mulditi3_internal (operands[0], operands[1],
|
emit_insn (gen_mulditi3_internal (operands[0], operands[1],
|
operands[2]));
|
operands[2]));
|
DONE;
|
DONE;
|
})
|
})
|
|
|
(define_insn "mulditi3_internal"
|
(define_insn "mulditi3_internal"
|
[(set (match_operand:TI 0 "register_operand" "=x")
|
[(set (match_operand:TI 0 "register_operand" "=x")
|
(mult:TI (any_extend:TI (match_operand:DI 1 "register_operand" "d"))
|
(mult:TI (any_extend:TI (match_operand:DI 1 "register_operand" "d"))
|
(any_extend:TI (match_operand:DI 2 "register_operand" "d"))))]
|
(any_extend:TI (match_operand:DI 2 "register_operand" "d"))))]
|
"TARGET_64BIT
|
"TARGET_64BIT
|
&& !TARGET_FIX_R4000
|
&& !TARGET_FIX_R4000
|
&& !( == ZERO_EXTEND && TARGET_FIX_VR4120)"
|
&& !( == ZERO_EXTEND && TARGET_FIX_VR4120)"
|
"dmult\t%1,%2"
|
"dmult\t%1,%2"
|
[(set_attr "type" "imul")
|
[(set_attr "type" "imul")
|
(set_attr "mode" "DI")])
|
(set_attr "mode" "DI")])
|
|
|
(define_insn "mulditi3_r4000"
|
(define_insn "mulditi3_r4000"
|
[(set (match_operand:TI 0 "register_operand" "=d")
|
[(set (match_operand:TI 0 "register_operand" "=d")
|
(mult:TI (any_extend:TI (match_operand:DI 1 "register_operand" "d"))
|
(mult:TI (any_extend:TI (match_operand:DI 1 "register_operand" "d"))
|
(any_extend:TI (match_operand:DI 2 "register_operand" "d"))))
|
(any_extend:TI (match_operand:DI 2 "register_operand" "d"))))
|
(clobber (match_scratch:TI 3 "=x"))]
|
(clobber (match_scratch:TI 3 "=x"))]
|
"TARGET_64BIT
|
"TARGET_64BIT
|
&& TARGET_FIX_R4000
|
&& TARGET_FIX_R4000
|
&& !( == ZERO_EXTEND && TARGET_FIX_VR4120)"
|
&& !( == ZERO_EXTEND && TARGET_FIX_VR4120)"
|
"dmult\t%1,%2\;mflo\t%L0\;mfhi\t%M0"
|
"dmult\t%1,%2\;mflo\t%L0\;mfhi\t%M0"
|
[(set_attr "type" "imul")
|
[(set_attr "type" "imul")
|
(set_attr "mode" "DI")
|
(set_attr "mode" "DI")
|
(set_attr "length" "12")])
|
(set_attr "length" "12")])
|
|
|
;; The R4650 supports a 32-bit multiply/ 64-bit accumulate
|
;; The R4650 supports a 32-bit multiply/ 64-bit accumulate
|
;; instruction. The HI/LO registers are used as a 64-bit accumulator.
|
;; instruction. The HI/LO registers are used as a 64-bit accumulator.
|
|
|
(define_insn "madsi"
|
(define_insn "madsi"
|
[(set (match_operand:SI 0 "register_operand" "+l")
|
[(set (match_operand:SI 0 "register_operand" "+l")
|
(plus:SI (mult:SI (match_operand:SI 1 "register_operand" "d")
|
(plus:SI (mult:SI (match_operand:SI 1 "register_operand" "d")
|
(match_operand:SI 2 "register_operand" "d"))
|
(match_operand:SI 2 "register_operand" "d"))
|
(match_dup 0)))]
|
(match_dup 0)))]
|
"TARGET_MAD"
|
"TARGET_MAD"
|
"mad\t%1,%2"
|
"mad\t%1,%2"
|
[(set_attr "type" "imadd")
|
[(set_attr "type" "imadd")
|
(set_attr "mode" "SI")])
|
(set_attr "mode" "SI")])
|
|
|
(define_insn "maddsidi4"
|
(define_insn "maddsidi4"
|
[(set (match_operand:DI 0 "register_operand" "=ka")
|
[(set (match_operand:DI 0 "register_operand" "=ka")
|
(plus:DI
|
(plus:DI
|
(mult:DI (any_extend:DI (match_operand:SI 1 "register_operand" "d"))
|
(mult:DI (any_extend:DI (match_operand:SI 1 "register_operand" "d"))
|
(any_extend:DI (match_operand:SI 2 "register_operand" "d")))
|
(any_extend:DI (match_operand:SI 2 "register_operand" "d")))
|
(match_operand:DI 3 "register_operand" "0")))]
|
(match_operand:DI 3 "register_operand" "0")))]
|
"(TARGET_MAD || ISA_HAS_MACC || GENERATE_MADD_MSUB || ISA_HAS_DSPR2)
|
"(TARGET_MAD || ISA_HAS_MACC || GENERATE_MADD_MSUB || ISA_HAS_DSPR2)
|
&& !TARGET_64BIT"
|
&& !TARGET_64BIT"
|
{
|
{
|
if (TARGET_MAD)
|
if (TARGET_MAD)
|
return "mad\t%1,%2";
|
return "mad\t%1,%2";
|
else if (ISA_HAS_DSPR2)
|
else if (ISA_HAS_DSPR2)
|
return "madd\t%q0,%1,%2";
|
return "madd\t%q0,%1,%2";
|
else if (GENERATE_MADD_MSUB || TARGET_MIPS5500)
|
else if (GENERATE_MADD_MSUB || TARGET_MIPS5500)
|
return "madd\t%1,%2";
|
return "madd\t%1,%2";
|
else
|
else
|
/* See comment in *macc. */
|
/* See comment in *macc. */
|
return "%[macc\t%@,%1,%2%]";
|
return "%[macc\t%@,%1,%2%]";
|
}
|
}
|
[(set_attr "type" "imadd")
|
[(set_attr "type" "imadd")
|
(set_attr "mode" "SI")])
|
(set_attr "mode" "SI")])
|
|
|
;; Floating point multiply accumulate instructions.
|
;; Floating point multiply accumulate instructions.
|
|
|
(define_insn "*madd4"
|
(define_insn "*madd4"
|
[(set (match_operand:ANYF 0 "register_operand" "=f")
|
[(set (match_operand:ANYF 0 "register_operand" "=f")
|
(plus:ANYF (mult:ANYF (match_operand:ANYF 1 "register_operand" "f")
|
(plus:ANYF (mult:ANYF (match_operand:ANYF 1 "register_operand" "f")
|
(match_operand:ANYF 2 "register_operand" "f"))
|
(match_operand:ANYF 2 "register_operand" "f"))
|
(match_operand:ANYF 3 "register_operand" "f")))]
|
(match_operand:ANYF 3 "register_operand" "f")))]
|
"ISA_HAS_FP_MADD4_MSUB4 && TARGET_FUSED_MADD"
|
"ISA_HAS_FP_MADD4_MSUB4 && TARGET_FUSED_MADD"
|
"madd.\t%0,%3,%1,%2"
|
"madd.\t%0,%3,%1,%2"
|
[(set_attr "type" "fmadd")
|
[(set_attr "type" "fmadd")
|
(set_attr "mode" "")])
|
(set_attr "mode" "")])
|
|
|
(define_insn "*madd3"
|
(define_insn "*madd3"
|
[(set (match_operand:ANYF 0 "register_operand" "=f")
|
[(set (match_operand:ANYF 0 "register_operand" "=f")
|
(plus:ANYF (mult:ANYF (match_operand:ANYF 1 "register_operand" "f")
|
(plus:ANYF (mult:ANYF (match_operand:ANYF 1 "register_operand" "f")
|
(match_operand:ANYF 2 "register_operand" "f"))
|
(match_operand:ANYF 2 "register_operand" "f"))
|
(match_operand:ANYF 3 "register_operand" "0")))]
|
(match_operand:ANYF 3 "register_operand" "0")))]
|
"ISA_HAS_FP_MADD3_MSUB3 && TARGET_FUSED_MADD"
|
"ISA_HAS_FP_MADD3_MSUB3 && TARGET_FUSED_MADD"
|
"madd.\t%0,%1,%2"
|
"madd.\t%0,%1,%2"
|
[(set_attr "type" "fmadd")
|
[(set_attr "type" "fmadd")
|
(set_attr "mode" "")])
|
(set_attr "mode" "")])
|
|
|
(define_insn "*msub4"
|
(define_insn "*msub4"
|
[(set (match_operand:ANYF 0 "register_operand" "=f")
|
[(set (match_operand:ANYF 0 "register_operand" "=f")
|
(minus:ANYF (mult:ANYF (match_operand:ANYF 1 "register_operand" "f")
|
(minus:ANYF (mult:ANYF (match_operand:ANYF 1 "register_operand" "f")
|
(match_operand:ANYF 2 "register_operand" "f"))
|
(match_operand:ANYF 2 "register_operand" "f"))
|
(match_operand:ANYF 3 "register_operand" "f")))]
|
(match_operand:ANYF 3 "register_operand" "f")))]
|
"ISA_HAS_FP_MADD4_MSUB4 && TARGET_FUSED_MADD"
|
"ISA_HAS_FP_MADD4_MSUB4 && TARGET_FUSED_MADD"
|
"msub.\t%0,%3,%1,%2"
|
"msub.\t%0,%3,%1,%2"
|
[(set_attr "type" "fmadd")
|
[(set_attr "type" "fmadd")
|
(set_attr "mode" "")])
|
(set_attr "mode" "")])
|
|
|
(define_insn "*msub3"
|
(define_insn "*msub3"
|
[(set (match_operand:ANYF 0 "register_operand" "=f")
|
[(set (match_operand:ANYF 0 "register_operand" "=f")
|
(minus:ANYF (mult:ANYF (match_operand:ANYF 1 "register_operand" "f")
|
(minus:ANYF (mult:ANYF (match_operand:ANYF 1 "register_operand" "f")
|
(match_operand:ANYF 2 "register_operand" "f"))
|
(match_operand:ANYF 2 "register_operand" "f"))
|
(match_operand:ANYF 3 "register_operand" "0")))]
|
(match_operand:ANYF 3 "register_operand" "0")))]
|
"ISA_HAS_FP_MADD3_MSUB3 && TARGET_FUSED_MADD"
|
"ISA_HAS_FP_MADD3_MSUB3 && TARGET_FUSED_MADD"
|
"msub.\t%0,%1,%2"
|
"msub.\t%0,%1,%2"
|
[(set_attr "type" "fmadd")
|
[(set_attr "type" "fmadd")
|
(set_attr "mode" "")])
|
(set_attr "mode" "")])
|
|
|
(define_insn "*nmadd4"
|
(define_insn "*nmadd4"
|
[(set (match_operand:ANYF 0 "register_operand" "=f")
|
[(set (match_operand:ANYF 0 "register_operand" "=f")
|
(neg:ANYF (plus:ANYF
|
(neg:ANYF (plus:ANYF
|
(mult:ANYF (match_operand:ANYF 1 "register_operand" "f")
|
(mult:ANYF (match_operand:ANYF 1 "register_operand" "f")
|
(match_operand:ANYF 2 "register_operand" "f"))
|
(match_operand:ANYF 2 "register_operand" "f"))
|
(match_operand:ANYF 3 "register_operand" "f"))))]
|
(match_operand:ANYF 3 "register_operand" "f"))))]
|
"ISA_HAS_NMADD4_NMSUB4 (mode)
|
"ISA_HAS_NMADD4_NMSUB4 (mode)
|
&& TARGET_FUSED_MADD
|
&& TARGET_FUSED_MADD
|
&& HONOR_SIGNED_ZEROS (mode)
|
&& HONOR_SIGNED_ZEROS (mode)
|
&& !HONOR_NANS (mode)"
|
&& !HONOR_NANS (mode)"
|
"nmadd.\t%0,%3,%1,%2"
|
"nmadd.\t%0,%3,%1,%2"
|
[(set_attr "type" "fmadd")
|
[(set_attr "type" "fmadd")
|
(set_attr "mode" "")])
|
(set_attr "mode" "")])
|
|
|
(define_insn "*nmadd3"
|
(define_insn "*nmadd3"
|
[(set (match_operand:ANYF 0 "register_operand" "=f")
|
[(set (match_operand:ANYF 0 "register_operand" "=f")
|
(neg:ANYF (plus:ANYF
|
(neg:ANYF (plus:ANYF
|
(mult:ANYF (match_operand:ANYF 1 "register_operand" "f")
|
(mult:ANYF (match_operand:ANYF 1 "register_operand" "f")
|
(match_operand:ANYF 2 "register_operand" "f"))
|
(match_operand:ANYF 2 "register_operand" "f"))
|
(match_operand:ANYF 3 "register_operand" "0"))))]
|
(match_operand:ANYF 3 "register_operand" "0"))))]
|
"ISA_HAS_NMADD3_NMSUB3 (mode)
|
"ISA_HAS_NMADD3_NMSUB3 (mode)
|
&& TARGET_FUSED_MADD
|
&& TARGET_FUSED_MADD
|
&& HONOR_SIGNED_ZEROS (mode)
|
&& HONOR_SIGNED_ZEROS (mode)
|
&& !HONOR_NANS (mode)"
|
&& !HONOR_NANS (mode)"
|
"nmadd.\t%0,%1,%2"
|
"nmadd.\t%0,%1,%2"
|
[(set_attr "type" "fmadd")
|
[(set_attr "type" "fmadd")
|
(set_attr "mode" "")])
|
(set_attr "mode" "")])
|
|
|
(define_insn "*nmadd4_fastmath"
|
(define_insn "*nmadd4_fastmath"
|
[(set (match_operand:ANYF 0 "register_operand" "=f")
|
[(set (match_operand:ANYF 0 "register_operand" "=f")
|
(minus:ANYF
|
(minus:ANYF
|
(mult:ANYF (neg:ANYF (match_operand:ANYF 1 "register_operand" "f"))
|
(mult:ANYF (neg:ANYF (match_operand:ANYF 1 "register_operand" "f"))
|
(match_operand:ANYF 2 "register_operand" "f"))
|
(match_operand:ANYF 2 "register_operand" "f"))
|
(match_operand:ANYF 3 "register_operand" "f")))]
|
(match_operand:ANYF 3 "register_operand" "f")))]
|
"ISA_HAS_NMADD4_NMSUB4 (mode)
|
"ISA_HAS_NMADD4_NMSUB4 (mode)
|
&& TARGET_FUSED_MADD
|
&& TARGET_FUSED_MADD
|
&& !HONOR_SIGNED_ZEROS (mode)
|
&& !HONOR_SIGNED_ZEROS (mode)
|
&& !HONOR_NANS (mode)"
|
&& !HONOR_NANS (mode)"
|
"nmadd.\t%0,%3,%1,%2"
|
"nmadd.\t%0,%3,%1,%2"
|
[(set_attr "type" "fmadd")
|
[(set_attr "type" "fmadd")
|
(set_attr "mode" "")])
|
(set_attr "mode" "")])
|
|
|
(define_insn "*nmadd3_fastmath"
|
(define_insn "*nmadd3_fastmath"
|
[(set (match_operand:ANYF 0 "register_operand" "=f")
|
[(set (match_operand:ANYF 0 "register_operand" "=f")
|
(minus:ANYF
|
(minus:ANYF
|
(mult:ANYF (neg:ANYF (match_operand:ANYF 1 "register_operand" "f"))
|
(mult:ANYF (neg:ANYF (match_operand:ANYF 1 "register_operand" "f"))
|
(match_operand:ANYF 2 "register_operand" "f"))
|
(match_operand:ANYF 2 "register_operand" "f"))
|
(match_operand:ANYF 3 "register_operand" "0")))]
|
(match_operand:ANYF 3 "register_operand" "0")))]
|
"ISA_HAS_NMADD3_NMSUB3 (mode)
|
"ISA_HAS_NMADD3_NMSUB3 (mode)
|
&& TARGET_FUSED_MADD
|
&& TARGET_FUSED_MADD
|
&& !HONOR_SIGNED_ZEROS (mode)
|
&& !HONOR_SIGNED_ZEROS (mode)
|
&& !HONOR_NANS (mode)"
|
&& !HONOR_NANS (mode)"
|
"nmadd.\t%0,%1,%2"
|
"nmadd.\t%0,%1,%2"
|
[(set_attr "type" "fmadd")
|
[(set_attr "type" "fmadd")
|
(set_attr "mode" "")])
|
(set_attr "mode" "")])
|
|
|
(define_insn "*nmsub4"
|
(define_insn "*nmsub4"
|
[(set (match_operand:ANYF 0 "register_operand" "=f")
|
[(set (match_operand:ANYF 0 "register_operand" "=f")
|
(neg:ANYF (minus:ANYF
|
(neg:ANYF (minus:ANYF
|
(mult:ANYF (match_operand:ANYF 2 "register_operand" "f")
|
(mult:ANYF (match_operand:ANYF 2 "register_operand" "f")
|
(match_operand:ANYF 3 "register_operand" "f"))
|
(match_operand:ANYF 3 "register_operand" "f"))
|
(match_operand:ANYF 1 "register_operand" "f"))))]
|
(match_operand:ANYF 1 "register_operand" "f"))))]
|
"ISA_HAS_NMADD4_NMSUB4 (mode)
|
"ISA_HAS_NMADD4_NMSUB4 (mode)
|
&& TARGET_FUSED_MADD
|
&& TARGET_FUSED_MADD
|
&& HONOR_SIGNED_ZEROS (mode)
|
&& HONOR_SIGNED_ZEROS (mode)
|
&& !HONOR_NANS (mode)"
|
&& !HONOR_NANS (mode)"
|
"nmsub.\t%0,%1,%2,%3"
|
"nmsub.\t%0,%1,%2,%3"
|
[(set_attr "type" "fmadd")
|
[(set_attr "type" "fmadd")
|
(set_attr "mode" "")])
|
(set_attr "mode" "")])
|
|
|
(define_insn "*nmsub3"
|
(define_insn "*nmsub3"
|
[(set (match_operand:ANYF 0 "register_operand" "=f")
|
[(set (match_operand:ANYF 0 "register_operand" "=f")
|
(neg:ANYF (minus:ANYF
|
(neg:ANYF (minus:ANYF
|
(mult:ANYF (match_operand:ANYF 2 "register_operand" "f")
|
(mult:ANYF (match_operand:ANYF 2 "register_operand" "f")
|
(match_operand:ANYF 3 "register_operand" "f"))
|
(match_operand:ANYF 3 "register_operand" "f"))
|
(match_operand:ANYF 1 "register_operand" "0"))))]
|
(match_operand:ANYF 1 "register_operand" "0"))))]
|
"ISA_HAS_NMADD3_NMSUB3 (mode)
|
"ISA_HAS_NMADD3_NMSUB3 (mode)
|
&& TARGET_FUSED_MADD
|
&& TARGET_FUSED_MADD
|
&& HONOR_SIGNED_ZEROS (mode)
|
&& HONOR_SIGNED_ZEROS (mode)
|
&& !HONOR_NANS (mode)"
|
&& !HONOR_NANS (mode)"
|
"nmsub.\t%0,%1,%2"
|
"nmsub.\t%0,%1,%2"
|
[(set_attr "type" "fmadd")
|
[(set_attr "type" "fmadd")
|
(set_attr "mode" "")])
|
(set_attr "mode" "")])
|
|
|
(define_insn "*nmsub4_fastmath"
|
(define_insn "*nmsub4_fastmath"
|
[(set (match_operand:ANYF 0 "register_operand" "=f")
|
[(set (match_operand:ANYF 0 "register_operand" "=f")
|
(minus:ANYF
|
(minus:ANYF
|
(match_operand:ANYF 1 "register_operand" "f")
|
(match_operand:ANYF 1 "register_operand" "f")
|
(mult:ANYF (match_operand:ANYF 2 "register_operand" "f")
|
(mult:ANYF (match_operand:ANYF 2 "register_operand" "f")
|
(match_operand:ANYF 3 "register_operand" "f"))))]
|
(match_operand:ANYF 3 "register_operand" "f"))))]
|
"ISA_HAS_NMADD4_NMSUB4 (mode)
|
"ISA_HAS_NMADD4_NMSUB4 (mode)
|
&& TARGET_FUSED_MADD
|
&& TARGET_FUSED_MADD
|
&& !HONOR_SIGNED_ZEROS (mode)
|
&& !HONOR_SIGNED_ZEROS (mode)
|
&& !HONOR_NANS (mode)"
|
&& !HONOR_NANS (mode)"
|
"nmsub.\t%0,%1,%2,%3"
|
"nmsub.\t%0,%1,%2,%3"
|
[(set_attr "type" "fmadd")
|
[(set_attr "type" "fmadd")
|
(set_attr "mode" "")])
|
(set_attr "mode" "")])
|
|
|
(define_insn "*nmsub3_fastmath"
|
(define_insn "*nmsub3_fastmath"
|
[(set (match_operand:ANYF 0 "register_operand" "=f")
|
[(set (match_operand:ANYF 0 "register_operand" "=f")
|
(minus:ANYF
|
(minus:ANYF
|
(match_operand:ANYF 1 "register_operand" "f")
|
(match_operand:ANYF 1 "register_operand" "f")
|
(mult:ANYF (match_operand:ANYF 2 "register_operand" "f")
|
(mult:ANYF (match_operand:ANYF 2 "register_operand" "f")
|
(match_operand:ANYF 3 "register_operand" "0"))))]
|
(match_operand:ANYF 3 "register_operand" "0"))))]
|
"ISA_HAS_NMADD3_NMSUB3 (mode)
|
"ISA_HAS_NMADD3_NMSUB3 (mode)
|
&& TARGET_FUSED_MADD
|
&& TARGET_FUSED_MADD
|
&& !HONOR_SIGNED_ZEROS (mode)
|
&& !HONOR_SIGNED_ZEROS (mode)
|
&& !HONOR_NANS (mode)"
|
&& !HONOR_NANS (mode)"
|
"nmsub.\t%0,%1,%2"
|
"nmsub.\t%0,%1,%2"
|
[(set_attr "type" "fmadd")
|
[(set_attr "type" "fmadd")
|
(set_attr "mode" "")])
|
(set_attr "mode" "")])
|
|
|
;;
|
;;
|
;; ....................
|
;; ....................
|
;;
|
;;
|
;; DIVISION and REMAINDER
|
;; DIVISION and REMAINDER
|
;;
|
;;
|
;; ....................
|
;; ....................
|
;;
|
;;
|
|
|
(define_expand "div3"
|
(define_expand "div3"
|
[(set (match_operand:ANYF 0 "register_operand")
|
[(set (match_operand:ANYF 0 "register_operand")
|
(div:ANYF (match_operand:ANYF 1 "reg_or_1_operand")
|
(div:ANYF (match_operand:ANYF 1 "reg_or_1_operand")
|
(match_operand:ANYF 2 "register_operand")))]
|
(match_operand:ANYF 2 "register_operand")))]
|
""
|
""
|
{
|
{
|
if (const_1_operand (operands[1], mode))
|
if (const_1_operand (operands[1], mode))
|
if (!( && flag_unsafe_math_optimizations))
|
if (!( && flag_unsafe_math_optimizations))
|
operands[1] = force_reg (mode, operands[1]);
|
operands[1] = force_reg (mode, operands[1]);
|
})
|
})
|
|
|
;; These patterns work around the early SB-1 rev2 core "F1" erratum:
|
;; These patterns work around the early SB-1 rev2 core "F1" erratum:
|
;;
|
;;
|
;; If an mfc1 or dmfc1 happens to access the floating point register
|
;; If an mfc1 or dmfc1 happens to access the floating point register
|
;; file at the same time a long latency operation (div, sqrt, recip,
|
;; file at the same time a long latency operation (div, sqrt, recip,
|
;; sqrt) iterates an intermediate result back through the floating
|
;; sqrt) iterates an intermediate result back through the floating
|
;; point register file bypass, then instead returning the correct
|
;; point register file bypass, then instead returning the correct
|
;; register value the mfc1 or dmfc1 operation returns the intermediate
|
;; register value the mfc1 or dmfc1 operation returns the intermediate
|
;; result of the long latency operation.
|
;; result of the long latency operation.
|
;;
|
;;
|
;; The workaround is to insert an unconditional 'mov' from/to the
|
;; The workaround is to insert an unconditional 'mov' from/to the
|
;; long latency op destination register.
|
;; long latency op destination register.
|
|
|
(define_insn "*div3"
|
(define_insn "*div3"
|
[(set (match_operand:ANYF 0 "register_operand" "=f")
|
[(set (match_operand:ANYF 0 "register_operand" "=f")
|
(div:ANYF (match_operand:ANYF 1 "register_operand" "f")
|
(div:ANYF (match_operand:ANYF 1 "register_operand" "f")
|
(match_operand:ANYF 2 "register_operand" "f")))]
|
(match_operand:ANYF 2 "register_operand" "f")))]
|
""
|
""
|
{
|
{
|
if (TARGET_FIX_SB1)
|
if (TARGET_FIX_SB1)
|
return "div.\t%0,%1,%2\;mov.\t%0,%0";
|
return "div.\t%0,%1,%2\;mov.\t%0,%0";
|
else
|
else
|
return "div.\t%0,%1,%2";
|
return "div.\t%0,%1,%2";
|
}
|
}
|
[(set_attr "type" "fdiv")
|
[(set_attr "type" "fdiv")
|
(set_attr "mode" "")
|
(set_attr "mode" "")
|
(set (attr "length")
|
(set (attr "length")
|
(if_then_else (ne (symbol_ref "TARGET_FIX_SB1") (const_int 0))
|
(if_then_else (ne (symbol_ref "TARGET_FIX_SB1") (const_int 0))
|
(const_int 8)
|
(const_int 8)
|
(const_int 4)))])
|
(const_int 4)))])
|
|
|
(define_insn "*recip3"
|
(define_insn "*recip3"
|
[(set (match_operand:ANYF 0 "register_operand" "=f")
|
[(set (match_operand:ANYF 0 "register_operand" "=f")
|
(div:ANYF (match_operand:ANYF 1 "const_1_operand" "")
|
(div:ANYF (match_operand:ANYF 1 "const_1_operand" "")
|
(match_operand:ANYF 2 "register_operand" "f")))]
|
(match_operand:ANYF 2 "register_operand" "f")))]
|
" && flag_unsafe_math_optimizations"
|
" && flag_unsafe_math_optimizations"
|
{
|
{
|
if (TARGET_FIX_SB1)
|
if (TARGET_FIX_SB1)
|
return "recip.\t%0,%2\;mov.\t%0,%0";
|
return "recip.\t%0,%2\;mov.\t%0,%0";
|
else
|
else
|
return "recip.\t%0,%2";
|
return "recip.\t%0,%2";
|
}
|
}
|
[(set_attr "type" "frdiv")
|
[(set_attr "type" "frdiv")
|
(set_attr "mode" "")
|
(set_attr "mode" "")
|
(set (attr "length")
|
(set (attr "length")
|
(if_then_else (ne (symbol_ref "TARGET_FIX_SB1") (const_int 0))
|
(if_then_else (ne (symbol_ref "TARGET_FIX_SB1") (const_int 0))
|
(const_int 8)
|
(const_int 8)
|
(const_int 4)))])
|
(const_int 4)))])
|
|
|
;; VR4120 errata MD(A1): signed division instructions do not work correctly
|
;; VR4120 errata MD(A1): signed division instructions do not work correctly
|
;; with negative operands. We use special libgcc functions instead.
|
;; with negative operands. We use special libgcc functions instead.
|
(define_insn_and_split "divmod4"
|
(define_insn_and_split "divmod4"
|
[(set (match_operand:GPR 0 "register_operand" "=l")
|
[(set (match_operand:GPR 0 "register_operand" "=l")
|
(div:GPR (match_operand:GPR 1 "register_operand" "d")
|
(div:GPR (match_operand:GPR 1 "register_operand" "d")
|
(match_operand:GPR 2 "register_operand" "d")))
|
(match_operand:GPR 2 "register_operand" "d")))
|
(set (match_operand:GPR 3 "register_operand" "=d")
|
(set (match_operand:GPR 3 "register_operand" "=d")
|
(mod:GPR (match_dup 1)
|
(mod:GPR (match_dup 1)
|
(match_dup 2)))]
|
(match_dup 2)))]
|
"!TARGET_FIX_VR4120"
|
"!TARGET_FIX_VR4120"
|
"#"
|
"#"
|
"&& reload_completed"
|
"&& reload_completed"
|
[(const_int 0)]
|
[(const_int 0)]
|
{
|
{
|
rtx hilo;
|
rtx hilo;
|
|
|
if (TARGET_64BIT)
|
if (TARGET_64BIT)
|
{
|
{
|
hilo = gen_rtx_REG (TImode, MD_REG_FIRST);
|
hilo = gen_rtx_REG (TImode, MD_REG_FIRST);
|
emit_insn (gen_divmod4_hilo_ti (hilo, operands[1], operands[2]));
|
emit_insn (gen_divmod4_hilo_ti (hilo, operands[1], operands[2]));
|
emit_insn (gen_mfhi_ti (operands[3], hilo));
|
emit_insn (gen_mfhi_ti (operands[3], hilo));
|
}
|
}
|
else
|
else
|
{
|
{
|
hilo = gen_rtx_REG (DImode, MD_REG_FIRST);
|
hilo = gen_rtx_REG (DImode, MD_REG_FIRST);
|
emit_insn (gen_divmod4_hilo_di (hilo, operands[1], operands[2]));
|
emit_insn (gen_divmod4_hilo_di (hilo, operands[1], operands[2]));
|
emit_insn (gen_mfhi_di (operands[3], hilo));
|
emit_insn (gen_mfhi_di (operands[3], hilo));
|
}
|
}
|
DONE;
|
DONE;
|
}
|
}
|
[(set_attr "type" "idiv")
|
[(set_attr "type" "idiv")
|
(set_attr "mode" "")
|
(set_attr "mode" "")
|
(set_attr "length" "8")])
|
(set_attr "length" "8")])
|
|
|
(define_insn_and_split "udivmod4"
|
(define_insn_and_split "udivmod4"
|
[(set (match_operand:GPR 0 "register_operand" "=l")
|
[(set (match_operand:GPR 0 "register_operand" "=l")
|
(udiv:GPR (match_operand:GPR 1 "register_operand" "d")
|
(udiv:GPR (match_operand:GPR 1 "register_operand" "d")
|
(match_operand:GPR 2 "register_operand" "d")))
|
(match_operand:GPR 2 "register_operand" "d")))
|
(set (match_operand:GPR 3 "register_operand" "=d")
|
(set (match_operand:GPR 3 "register_operand" "=d")
|
(umod:GPR (match_dup 1)
|
(umod:GPR (match_dup 1)
|
(match_dup 2)))]
|
(match_dup 2)))]
|
""
|
""
|
"#"
|
"#"
|
"reload_completed"
|
"reload_completed"
|
[(const_int 0)]
|
[(const_int 0)]
|
{
|
{
|
rtx hilo;
|
rtx hilo;
|
|
|
if (TARGET_64BIT)
|
if (TARGET_64BIT)
|
{
|
{
|
hilo = gen_rtx_REG (TImode, MD_REG_FIRST);
|
hilo = gen_rtx_REG (TImode, MD_REG_FIRST);
|
emit_insn (gen_udivmod4_hilo_ti (hilo, operands[1], operands[2]));
|
emit_insn (gen_udivmod4_hilo_ti (hilo, operands[1], operands[2]));
|
emit_insn (gen_mfhi_ti (operands[3], hilo));
|
emit_insn (gen_mfhi_ti (operands[3], hilo));
|
}
|
}
|
else
|
else
|
{
|
{
|
hilo = gen_rtx_REG (DImode, MD_REG_FIRST);
|
hilo = gen_rtx_REG (DImode, MD_REG_FIRST);
|
emit_insn (gen_udivmod4_hilo_di (hilo, operands[1], operands[2]));
|
emit_insn (gen_udivmod4_hilo_di (hilo, operands[1], operands[2]));
|
emit_insn (gen_mfhi_di (operands[3], hilo));
|
emit_insn (gen_mfhi_di (operands[3], hilo));
|
}
|
}
|
DONE;
|
DONE;
|
}
|
}
|
[(set_attr "type" "idiv")
|
[(set_attr "type" "idiv")
|
(set_attr "mode" "")
|
(set_attr "mode" "")
|
(set_attr "length" "8")])
|
(set_attr "length" "8")])
|
|
|
(define_insn "divmod4_hilo_"
|
(define_insn "divmod4_hilo_"
|
[(set (match_operand:HILO 0 "register_operand" "=x")
|
[(set (match_operand:HILO 0 "register_operand" "=x")
|
(unspec:HILO
|
(unspec:HILO
|
[(any_div:GPR (match_operand:GPR 1 "register_operand" "d")
|
[(any_div:GPR (match_operand:GPR 1 "register_operand" "d")
|
(match_operand:GPR 2 "register_operand" "d"))]
|
(match_operand:GPR 2 "register_operand" "d"))]
|
UNSPEC_SET_HILO))]
|
UNSPEC_SET_HILO))]
|
""
|
""
|
{ return mips_output_division ("div\t%.,%1,%2", operands); }
|
{ return mips_output_division ("div\t%.,%1,%2", operands); }
|
[(set_attr "type" "idiv")
|
[(set_attr "type" "idiv")
|
(set_attr "mode" "")])
|
(set_attr "mode" "")])
|
|
|
;;
|
;;
|
;; ....................
|
;; ....................
|
;;
|
;;
|
;; SQUARE ROOT
|
;; SQUARE ROOT
|
;;
|
;;
|
;; ....................
|
;; ....................
|
|
|
;; These patterns work around the early SB-1 rev2 core "F1" erratum (see
|
;; These patterns work around the early SB-1 rev2 core "F1" erratum (see
|
;; "*div[sd]f3" comment for details).
|
;; "*div[sd]f3" comment for details).
|
|
|
(define_insn "sqrt2"
|
(define_insn "sqrt2"
|
[(set (match_operand:ANYF 0 "register_operand" "=f")
|
[(set (match_operand:ANYF 0 "register_operand" "=f")
|
(sqrt:ANYF (match_operand:ANYF 1 "register_operand" "f")))]
|
(sqrt:ANYF (match_operand:ANYF 1 "register_operand" "f")))]
|
""
|
""
|
{
|
{
|
if (TARGET_FIX_SB1)
|
if (TARGET_FIX_SB1)
|
return "sqrt.\t%0,%1\;mov.\t%0,%0";
|
return "sqrt.\t%0,%1\;mov.\t%0,%0";
|
else
|
else
|
return "sqrt.\t%0,%1";
|
return "sqrt.\t%0,%1";
|
}
|
}
|
[(set_attr "type" "fsqrt")
|
[(set_attr "type" "fsqrt")
|
(set_attr "mode" "")
|
(set_attr "mode" "")
|
(set (attr "length")
|
(set (attr "length")
|
(if_then_else (ne (symbol_ref "TARGET_FIX_SB1") (const_int 0))
|
(if_then_else (ne (symbol_ref "TARGET_FIX_SB1") (const_int 0))
|
(const_int 8)
|
(const_int 8)
|
(const_int 4)))])
|
(const_int 4)))])
|
|
|
(define_insn "*rsqrta"
|
(define_insn "*rsqrta"
|
[(set (match_operand:ANYF 0 "register_operand" "=f")
|
[(set (match_operand:ANYF 0 "register_operand" "=f")
|
(div:ANYF (match_operand:ANYF 1 "const_1_operand" "")
|
(div:ANYF (match_operand:ANYF 1 "const_1_operand" "")
|
(sqrt:ANYF (match_operand:ANYF 2 "register_operand" "f"))))]
|
(sqrt:ANYF (match_operand:ANYF 2 "register_operand" "f"))))]
|
" && flag_unsafe_math_optimizations"
|
" && flag_unsafe_math_optimizations"
|
{
|
{
|
if (TARGET_FIX_SB1)
|
if (TARGET_FIX_SB1)
|
return "rsqrt.\t%0,%2\;mov.\t%0,%0";
|
return "rsqrt.\t%0,%2\;mov.\t%0,%0";
|
else
|
else
|
return "rsqrt.\t%0,%2";
|
return "rsqrt.\t%0,%2";
|
}
|
}
|
[(set_attr "type" "frsqrt")
|
[(set_attr "type" "frsqrt")
|
(set_attr "mode" "")
|
(set_attr "mode" "")
|
(set (attr "length")
|
(set (attr "length")
|
(if_then_else (ne (symbol_ref "TARGET_FIX_SB1") (const_int 0))
|
(if_then_else (ne (symbol_ref "TARGET_FIX_SB1") (const_int 0))
|
(const_int 8)
|
(const_int 8)
|
(const_int 4)))])
|
(const_int 4)))])
|
|
|
(define_insn "*rsqrtb"
|
(define_insn "*rsqrtb"
|
[(set (match_operand:ANYF 0 "register_operand" "=f")
|
[(set (match_operand:ANYF 0 "register_operand" "=f")
|
(sqrt:ANYF (div:ANYF (match_operand:ANYF 1 "const_1_operand" "")
|
(sqrt:ANYF (div:ANYF (match_operand:ANYF 1 "const_1_operand" "")
|
(match_operand:ANYF 2 "register_operand" "f"))))]
|
(match_operand:ANYF 2 "register_operand" "f"))))]
|
" && flag_unsafe_math_optimizations"
|
" && flag_unsafe_math_optimizations"
|
{
|
{
|
if (TARGET_FIX_SB1)
|
if (TARGET_FIX_SB1)
|
return "rsqrt.\t%0,%2\;mov.\t%0,%0";
|
return "rsqrt.\t%0,%2\;mov.\t%0,%0";
|
else
|
else
|
return "rsqrt.\t%0,%2";
|
return "rsqrt.\t%0,%2";
|
}
|
}
|
[(set_attr "type" "frsqrt")
|
[(set_attr "type" "frsqrt")
|
(set_attr "mode" "")
|
(set_attr "mode" "")
|
(set (attr "length")
|
(set (attr "length")
|
(if_then_else (ne (symbol_ref "TARGET_FIX_SB1") (const_int 0))
|
(if_then_else (ne (symbol_ref "TARGET_FIX_SB1") (const_int 0))
|
(const_int 8)
|
(const_int 8)
|
(const_int 4)))])
|
(const_int 4)))])
|
|
|
;;
|
;;
|
;; ....................
|
;; ....................
|
;;
|
;;
|
;; ABSOLUTE VALUE
|
;; ABSOLUTE VALUE
|
;;
|
;;
|
;; ....................
|
;; ....................
|
|
|
;; Do not use the integer abs macro instruction, since that signals an
|
;; Do not use the integer abs macro instruction, since that signals an
|
;; exception on -2147483648 (sigh).
|
;; exception on -2147483648 (sigh).
|
|
|
;; abs.fmt is an arithmetic instruction and treats all NaN inputs as
|
;; abs.fmt is an arithmetic instruction and treats all NaN inputs as
|
;; invalid; it does not clear their sign bits. We therefore can't use
|
;; invalid; it does not clear their sign bits. We therefore can't use
|
;; abs.fmt if the signs of NaNs matter.
|
;; abs.fmt if the signs of NaNs matter.
|
|
|
(define_insn "abs2"
|
(define_insn "abs2"
|
[(set (match_operand:ANYF 0 "register_operand" "=f")
|
[(set (match_operand:ANYF 0 "register_operand" "=f")
|
(abs:ANYF (match_operand:ANYF 1 "register_operand" "f")))]
|
(abs:ANYF (match_operand:ANYF 1 "register_operand" "f")))]
|
"!HONOR_NANS (mode)"
|
"!HONOR_NANS (mode)"
|
"abs.\t%0,%1"
|
"abs.\t%0,%1"
|
[(set_attr "type" "fabs")
|
[(set_attr "type" "fabs")
|
(set_attr "mode" "")])
|
(set_attr "mode" "")])
|
|
|
;;
|
;;
|
;; ...................
|
;; ...................
|
;;
|
;;
|
;; Count leading zeroes.
|
;; Count leading zeroes.
|
;;
|
;;
|
;; ...................
|
;; ...................
|
;;
|
;;
|
|
|
(define_insn "clz2"
|
(define_insn "clz2"
|
[(set (match_operand:GPR 0 "register_operand" "=d")
|
[(set (match_operand:GPR 0 "register_operand" "=d")
|
(clz:GPR (match_operand:GPR 1 "register_operand" "d")))]
|
(clz:GPR (match_operand:GPR 1 "register_operand" "d")))]
|
"ISA_HAS_CLZ_CLO"
|
"ISA_HAS_CLZ_CLO"
|
"clz\t%0,%1"
|
"clz\t%0,%1"
|
[(set_attr "type" "clz")
|
[(set_attr "type" "clz")
|
(set_attr "mode" "")])
|
(set_attr "mode" "")])
|
|
|
;;
|
;;
|
;; ...................
|
;; ...................
|
;;
|
;;
|
;; Count number of set bits.
|
;; Count number of set bits.
|
;;
|
;;
|
;; ...................
|
;; ...................
|
;;
|
;;
|
|
|
(define_insn "popcount2"
|
(define_insn "popcount2"
|
[(set (match_operand:GPR 0 "register_operand" "=d")
|
[(set (match_operand:GPR 0 "register_operand" "=d")
|
(popcount:GPR (match_operand:GPR 1 "register_operand" "d")))]
|
(popcount:GPR (match_operand:GPR 1 "register_operand" "d")))]
|
"ISA_HAS_POP"
|
"ISA_HAS_POP"
|
"pop\t%0,%1"
|
"pop\t%0,%1"
|
[(set_attr "type" "pop")
|
[(set_attr "type" "pop")
|
(set_attr "mode" "")])
|
(set_attr "mode" "")])
|
|
|
;;
|
;;
|
;; ....................
|
;; ....................
|
;;
|
;;
|
;; NEGATION and ONE'S COMPLEMENT
|
;; NEGATION and ONE'S COMPLEMENT
|
;;
|
;;
|
;; ....................
|
;; ....................
|
|
|
(define_insn "negsi2"
|
(define_insn "negsi2"
|
[(set (match_operand:SI 0 "register_operand" "=d")
|
[(set (match_operand:SI 0 "register_operand" "=d")
|
(neg:SI (match_operand:SI 1 "register_operand" "d")))]
|
(neg:SI (match_operand:SI 1 "register_operand" "d")))]
|
""
|
""
|
{
|
{
|
if (TARGET_MIPS16)
|
if (TARGET_MIPS16)
|
return "neg\t%0,%1";
|
return "neg\t%0,%1";
|
else
|
else
|
return "subu\t%0,%.,%1";
|
return "subu\t%0,%.,%1";
|
}
|
}
|
[(set_attr "type" "arith")
|
[(set_attr "type" "arith")
|
(set_attr "mode" "SI")])
|
(set_attr "mode" "SI")])
|
|
|
(define_insn "negdi2"
|
(define_insn "negdi2"
|
[(set (match_operand:DI 0 "register_operand" "=d")
|
[(set (match_operand:DI 0 "register_operand" "=d")
|
(neg:DI (match_operand:DI 1 "register_operand" "d")))]
|
(neg:DI (match_operand:DI 1 "register_operand" "d")))]
|
"TARGET_64BIT && !TARGET_MIPS16"
|
"TARGET_64BIT && !TARGET_MIPS16"
|
"dsubu\t%0,%.,%1"
|
"dsubu\t%0,%.,%1"
|
[(set_attr "type" "arith")
|
[(set_attr "type" "arith")
|
(set_attr "mode" "DI")])
|
(set_attr "mode" "DI")])
|
|
|
;; neg.fmt is an arithmetic instruction and treats all NaN inputs as
|
;; neg.fmt is an arithmetic instruction and treats all NaN inputs as
|
;; invalid; it does not flip their sign bit. We therefore can't use
|
;; invalid; it does not flip their sign bit. We therefore can't use
|
;; neg.fmt if the signs of NaNs matter.
|
;; neg.fmt if the signs of NaNs matter.
|
|
|
(define_insn "neg2"
|
(define_insn "neg2"
|
[(set (match_operand:ANYF 0 "register_operand" "=f")
|
[(set (match_operand:ANYF 0 "register_operand" "=f")
|
(neg:ANYF (match_operand:ANYF 1 "register_operand" "f")))]
|
(neg:ANYF (match_operand:ANYF 1 "register_operand" "f")))]
|
"!HONOR_NANS (mode)"
|
"!HONOR_NANS (mode)"
|
"neg.\t%0,%1"
|
"neg.\t%0,%1"
|
[(set_attr "type" "fneg")
|
[(set_attr "type" "fneg")
|
(set_attr "mode" "")])
|
(set_attr "mode" "")])
|
|
|
(define_insn "one_cmpl2"
|
(define_insn "one_cmpl2"
|
[(set (match_operand:GPR 0 "register_operand" "=d")
|
[(set (match_operand:GPR 0 "register_operand" "=d")
|
(not:GPR (match_operand:GPR 1 "register_operand" "d")))]
|
(not:GPR (match_operand:GPR 1 "register_operand" "d")))]
|
""
|
""
|
{
|
{
|
if (TARGET_MIPS16)
|
if (TARGET_MIPS16)
|
return "not\t%0,%1";
|
return "not\t%0,%1";
|
else
|
else
|
return "nor\t%0,%.,%1";
|
return "nor\t%0,%.,%1";
|
}
|
}
|
[(set_attr "type" "logical")
|
[(set_attr "type" "logical")
|
(set_attr "mode" "")])
|
(set_attr "mode" "")])
|
|
|
;;
|
;;
|
;; ....................
|
;; ....................
|
;;
|
;;
|
;; LOGICAL
|
;; LOGICAL
|
;;
|
;;
|
;; ....................
|
;; ....................
|
;;
|
;;
|
|
|
;; Many of these instructions use trivial define_expands, because we
|
;; Many of these instructions use trivial define_expands, because we
|
;; want to use a different set of constraints when TARGET_MIPS16.
|
;; want to use a different set of constraints when TARGET_MIPS16.
|
|
|
(define_expand "and3"
|
(define_expand "and3"
|
[(set (match_operand:GPR 0 "register_operand")
|
[(set (match_operand:GPR 0 "register_operand")
|
(and:GPR (match_operand:GPR 1 "register_operand")
|
(and:GPR (match_operand:GPR 1 "register_operand")
|
(match_operand:GPR 2 "and_reg_operand")))])
|
(match_operand:GPR 2 "and_reg_operand")))])
|
|
|
;; The middle-end is not allowed to convert ANDing with 0xffff_ffff into a
|
;; The middle-end is not allowed to convert ANDing with 0xffff_ffff into a
|
;; zero_extendsidi2 because of TRULY_NOOP_TRUNCATION, so handle these here.
|
;; zero_extendsidi2 because of TRULY_NOOP_TRUNCATION, so handle these here.
|
;; Note that this variant does not trigger for SI mode because we require
|
;; Note that this variant does not trigger for SI mode because we require
|
;; a 64-bit HOST_WIDE_INT and 0xffff_ffff wouldn't be a canonical
|
;; a 64-bit HOST_WIDE_INT and 0xffff_ffff wouldn't be a canonical
|
;; sign-extended SImode value.
|
;; sign-extended SImode value.
|
;;
|
;;
|
;; These are possible combinations for operand 1 and 2. The table
|
;; These are possible combinations for operand 1 and 2. The table
|
;; includes both MIPS and MIPS16 cases. (r=register, mem=memory,
|
;; includes both MIPS and MIPS16 cases. (r=register, mem=memory,
|
;; 16=MIPS16, x=match, S=split):
|
;; 16=MIPS16, x=match, S=split):
|
;;
|
;;
|
;; \ op1 r/EXT r/!EXT mem r/16 mem/16
|
;; \ op1 r/EXT r/!EXT mem r/16 mem/16
|
;; op2
|
;; op2
|
;;
|
;;
|
;; andi x x
|
;; andi x x
|
;; 0xff x x x x
|
;; 0xff x x x x
|
;; 0xffff x x x x
|
;; 0xffff x x x x
|
;; 0xffff_ffff x S x S x
|
;; 0xffff_ffff x S x S x
|
;; low-bitmask x
|
;; low-bitmask x
|
;; register x x
|
;; register x x
|
;; register =op1 x
|
;; register =op1 x
|
|
|
(define_insn "*and3"
|
(define_insn "*and3"
|
[(set (match_operand:GPR 0 "register_operand" "=d,d,d,d,d,d,d")
|
[(set (match_operand:GPR 0 "register_operand" "=d,d,d,d,d,d,d")
|
(and:GPR (match_operand:GPR 1 "nonimmediate_operand" "o,o,W,d,d,d,d")
|
(and:GPR (match_operand:GPR 1 "nonimmediate_operand" "o,o,W,d,d,d,d")
|
(match_operand:GPR 2 "and_operand" "Yb,Yh,Yw,K,Yx,Yw,d")))]
|
(match_operand:GPR 2 "and_operand" "Yb,Yh,Yw,K,Yx,Yw,d")))]
|
"!TARGET_MIPS16 && and_operands_ok (mode, operands[1], operands[2])"
|
"!TARGET_MIPS16 && and_operands_ok (mode, operands[1], operands[2])"
|
{
|
{
|
int len;
|
int len;
|
|
|
switch (which_alternative)
|
switch (which_alternative)
|
{
|
{
|
case 0:
|
case 0:
|
operands[1] = gen_lowpart (QImode, operands[1]);
|
operands[1] = gen_lowpart (QImode, operands[1]);
|
return "lbu\t%0,%1";
|
return "lbu\t%0,%1";
|
case 1:
|
case 1:
|
operands[1] = gen_lowpart (HImode, operands[1]);
|
operands[1] = gen_lowpart (HImode, operands[1]);
|
return "lhu\t%0,%1";
|
return "lhu\t%0,%1";
|
case 2:
|
case 2:
|
operands[1] = gen_lowpart (SImode, operands[1]);
|
operands[1] = gen_lowpart (SImode, operands[1]);
|
return "lwu\t%0,%1";
|
return "lwu\t%0,%1";
|
case 3:
|
case 3:
|
return "andi\t%0,%1,%x2";
|
return "andi\t%0,%1,%x2";
|
case 4:
|
case 4:
|
len = low_bitmask_len (mode, INTVAL (operands[2]));
|
len = low_bitmask_len (mode, INTVAL (operands[2]));
|
operands[2] = GEN_INT (len);
|
operands[2] = GEN_INT (len);
|
return "ext\t%0,%1,0,%2";
|
return "ext\t%0,%1,0,%2";
|
case 5:
|
case 5:
|
return "#";
|
return "#";
|
case 6:
|
case 6:
|
return "and\t%0,%1,%2";
|
return "and\t%0,%1,%2";
|
default:
|
default:
|
gcc_unreachable ();
|
gcc_unreachable ();
|
}
|
}
|
}
|
}
|
[(set_attr "move_type" "load,load,load,andi,ext_ins,shift_shift,logical")
|
[(set_attr "move_type" "load,load,load,andi,ext_ins,shift_shift,logical")
|
(set_attr "mode" "")])
|
(set_attr "mode" "")])
|
|
|
(define_insn "*and3_mips16"
|
(define_insn "*and3_mips16"
|
[(set (match_operand:GPR 0 "register_operand" "=d,d,d,d,d")
|
[(set (match_operand:GPR 0 "register_operand" "=d,d,d,d,d")
|
(and:GPR (match_operand:GPR 1 "nonimmediate_operand" "%o,o,W,d,0")
|
(and:GPR (match_operand:GPR 1 "nonimmediate_operand" "%o,o,W,d,0")
|
(match_operand:GPR 2 "and_operand" "Yb,Yh,Yw,Yw,d")))]
|
(match_operand:GPR 2 "and_operand" "Yb,Yh,Yw,Yw,d")))]
|
"TARGET_MIPS16 && and_operands_ok (mode, operands[1], operands[2])"
|
"TARGET_MIPS16 && and_operands_ok (mode, operands[1], operands[2])"
|
{
|
{
|
switch (which_alternative)
|
switch (which_alternative)
|
{
|
{
|
case 0:
|
case 0:
|
operands[1] = gen_lowpart (QImode, operands[1]);
|
operands[1] = gen_lowpart (QImode, operands[1]);
|
return "lbu\t%0,%1";
|
return "lbu\t%0,%1";
|
case 1:
|
case 1:
|
operands[1] = gen_lowpart (HImode, operands[1]);
|
operands[1] = gen_lowpart (HImode, operands[1]);
|
return "lhu\t%0,%1";
|
return "lhu\t%0,%1";
|
case 2:
|
case 2:
|
operands[1] = gen_lowpart (SImode, operands[1]);
|
operands[1] = gen_lowpart (SImode, operands[1]);
|
return "lwu\t%0,%1";
|
return "lwu\t%0,%1";
|
case 3:
|
case 3:
|
return "#";
|
return "#";
|
case 4:
|
case 4:
|
return "and\t%0,%2";
|
return "and\t%0,%2";
|
default:
|
default:
|
gcc_unreachable ();
|
gcc_unreachable ();
|
}
|
}
|
}
|
}
|
[(set_attr "move_type" "load,load,load,shift_shift,logical")
|
[(set_attr "move_type" "load,load,load,shift_shift,logical")
|
(set_attr "mode" "")])
|
(set_attr "mode" "")])
|
|
|
(define_expand "ior3"
|
(define_expand "ior3"
|
[(set (match_operand:GPR 0 "register_operand")
|
[(set (match_operand:GPR 0 "register_operand")
|
(ior:GPR (match_operand:GPR 1 "register_operand")
|
(ior:GPR (match_operand:GPR 1 "register_operand")
|
(match_operand:GPR 2 "uns_arith_operand")))]
|
(match_operand:GPR 2 "uns_arith_operand")))]
|
""
|
""
|
{
|
{
|
if (TARGET_MIPS16)
|
if (TARGET_MIPS16)
|
operands[2] = force_reg (mode, operands[2]);
|
operands[2] = force_reg (mode, operands[2]);
|
})
|
})
|
|
|
(define_insn "*ior3"
|
(define_insn "*ior3"
|
[(set (match_operand:GPR 0 "register_operand" "=d,d")
|
[(set (match_operand:GPR 0 "register_operand" "=d,d")
|
(ior:GPR (match_operand:GPR 1 "register_operand" "%d,d")
|
(ior:GPR (match_operand:GPR 1 "register_operand" "%d,d")
|
(match_operand:GPR 2 "uns_arith_operand" "d,K")))]
|
(match_operand:GPR 2 "uns_arith_operand" "d,K")))]
|
"!TARGET_MIPS16"
|
"!TARGET_MIPS16"
|
"@
|
"@
|
or\t%0,%1,%2
|
or\t%0,%1,%2
|
ori\t%0,%1,%x2"
|
ori\t%0,%1,%x2"
|
[(set_attr "type" "logical")
|
[(set_attr "type" "logical")
|
(set_attr "mode" "")])
|
(set_attr "mode" "")])
|
|
|
(define_insn "*ior3_mips16"
|
(define_insn "*ior3_mips16"
|
[(set (match_operand:GPR 0 "register_operand" "=d")
|
[(set (match_operand:GPR 0 "register_operand" "=d")
|
(ior:GPR (match_operand:GPR 1 "register_operand" "%0")
|
(ior:GPR (match_operand:GPR 1 "register_operand" "%0")
|
(match_operand:GPR 2 "register_operand" "d")))]
|
(match_operand:GPR 2 "register_operand" "d")))]
|
"TARGET_MIPS16"
|
"TARGET_MIPS16"
|
"or\t%0,%2"
|
"or\t%0,%2"
|
[(set_attr "type" "logical")
|
[(set_attr "type" "logical")
|
(set_attr "mode" "")])
|
(set_attr "mode" "")])
|
|
|
(define_expand "xor3"
|
(define_expand "xor3"
|
[(set (match_operand:GPR 0 "register_operand")
|
[(set (match_operand:GPR 0 "register_operand")
|
(xor:GPR (match_operand:GPR 1 "register_operand")
|
(xor:GPR (match_operand:GPR 1 "register_operand")
|
(match_operand:GPR 2 "uns_arith_operand")))]
|
(match_operand:GPR 2 "uns_arith_operand")))]
|
""
|
""
|
"")
|
"")
|
|
|
(define_insn ""
|
(define_insn ""
|
[(set (match_operand:GPR 0 "register_operand" "=d,d")
|
[(set (match_operand:GPR 0 "register_operand" "=d,d")
|
(xor:GPR (match_operand:GPR 1 "register_operand" "%d,d")
|
(xor:GPR (match_operand:GPR 1 "register_operand" "%d,d")
|
(match_operand:GPR 2 "uns_arith_operand" "d,K")))]
|
(match_operand:GPR 2 "uns_arith_operand" "d,K")))]
|
"!TARGET_MIPS16"
|
"!TARGET_MIPS16"
|
"@
|
"@
|
xor\t%0,%1,%2
|
xor\t%0,%1,%2
|
xori\t%0,%1,%x2"
|
xori\t%0,%1,%x2"
|
[(set_attr "type" "logical")
|
[(set_attr "type" "logical")
|
(set_attr "mode" "")])
|
(set_attr "mode" "")])
|
|
|
(define_insn ""
|
(define_insn ""
|
[(set (match_operand:GPR 0 "register_operand" "=d,t,t")
|
[(set (match_operand:GPR 0 "register_operand" "=d,t,t")
|
(xor:GPR (match_operand:GPR 1 "register_operand" "%0,d,d")
|
(xor:GPR (match_operand:GPR 1 "register_operand" "%0,d,d")
|
(match_operand:GPR 2 "uns_arith_operand" "d,K,d")))]
|
(match_operand:GPR 2 "uns_arith_operand" "d,K,d")))]
|
"TARGET_MIPS16"
|
"TARGET_MIPS16"
|
"@
|
"@
|
xor\t%0,%2
|
xor\t%0,%2
|
cmpi\t%1,%2
|
cmpi\t%1,%2
|
cmp\t%1,%2"
|
cmp\t%1,%2"
|
[(set_attr "type" "logical,arith,arith")
|
[(set_attr "type" "logical,arith,arith")
|
(set_attr "mode" "")
|
(set_attr "mode" "")
|
(set_attr_alternative "length"
|
(set_attr_alternative "length"
|
[(const_int 4)
|
[(const_int 4)
|
(if_then_else (match_operand:VOID 2 "m16_uimm8_1")
|
(if_then_else (match_operand:VOID 2 "m16_uimm8_1")
|
(const_int 4)
|
(const_int 4)
|
(const_int 8))
|
(const_int 8))
|
(const_int 4)])])
|
(const_int 4)])])
|
|
|
(define_insn "*nor3"
|
(define_insn "*nor3"
|
[(set (match_operand:GPR 0 "register_operand" "=d")
|
[(set (match_operand:GPR 0 "register_operand" "=d")
|
(and:GPR (not:GPR (match_operand:GPR 1 "register_operand" "d"))
|
(and:GPR (not:GPR (match_operand:GPR 1 "register_operand" "d"))
|
(not:GPR (match_operand:GPR 2 "register_operand" "d"))))]
|
(not:GPR (match_operand:GPR 2 "register_operand" "d"))))]
|
"!TARGET_MIPS16"
|
"!TARGET_MIPS16"
|
"nor\t%0,%1,%2"
|
"nor\t%0,%1,%2"
|
[(set_attr "type" "logical")
|
[(set_attr "type" "logical")
|
(set_attr "mode" "")])
|
(set_attr "mode" "")])
|
|
|
;;
|
;;
|
;; ....................
|
;; ....................
|
;;
|
;;
|
;; TRUNCATION
|
;; TRUNCATION
|
;;
|
;;
|
;; ....................
|
;; ....................
|
|
|
|
|
|
|
(define_insn "truncdfsf2"
|
(define_insn "truncdfsf2"
|
[(set (match_operand:SF 0 "register_operand" "=f")
|
[(set (match_operand:SF 0 "register_operand" "=f")
|
(float_truncate:SF (match_operand:DF 1 "register_operand" "f")))]
|
(float_truncate:SF (match_operand:DF 1 "register_operand" "f")))]
|
"TARGET_HARD_FLOAT && TARGET_DOUBLE_FLOAT"
|
"TARGET_HARD_FLOAT && TARGET_DOUBLE_FLOAT"
|
"cvt.s.d\t%0,%1"
|
"cvt.s.d\t%0,%1"
|
[(set_attr "type" "fcvt")
|
[(set_attr "type" "fcvt")
|
(set_attr "cnv_mode" "D2S")
|
(set_attr "cnv_mode" "D2S")
|
(set_attr "mode" "SF")])
|
(set_attr "mode" "SF")])
|
|
|
;; Integer truncation patterns. Truncating SImode values to smaller
|
;; Integer truncation patterns. Truncating SImode values to smaller
|
;; modes is a no-op, as it is for most other GCC ports. Truncating
|
;; modes is a no-op, as it is for most other GCC ports. Truncating
|
;; DImode values to SImode is not a no-op for TARGET_64BIT since we
|
;; DImode values to SImode is not a no-op for TARGET_64BIT since we
|
;; need to make sure that the lower 32 bits are properly sign-extended
|
;; need to make sure that the lower 32 bits are properly sign-extended
|
;; (see TRULY_NOOP_TRUNCATION). Truncating DImode values into modes
|
;; (see TRULY_NOOP_TRUNCATION). Truncating DImode values into modes
|
;; smaller than SImode is equivalent to two separate truncations:
|
;; smaller than SImode is equivalent to two separate truncations:
|
;;
|
;;
|
;; A B
|
;; A B
|
;; DI ---> HI == DI ---> SI ---> HI
|
;; DI ---> HI == DI ---> SI ---> HI
|
;; DI ---> QI == DI ---> SI ---> QI
|
;; DI ---> QI == DI ---> SI ---> QI
|
;;
|
;;
|
;; Step A needs a real instruction but step B does not.
|
;; Step A needs a real instruction but step B does not.
|
|
|
(define_insn "truncdi2"
|
(define_insn "truncdi2"
|
[(set (match_operand:SUBDI 0 "nonimmediate_operand" "=d,m")
|
[(set (match_operand:SUBDI 0 "nonimmediate_operand" "=d,m")
|
(truncate:SUBDI (match_operand:DI 1 "register_operand" "d,d")))]
|
(truncate:SUBDI (match_operand:DI 1 "register_operand" "d,d")))]
|
"TARGET_64BIT"
|
"TARGET_64BIT"
|
"@
|
"@
|
sll\t%0,%1,0
|
sll\t%0,%1,0
|
\t%1,%0"
|
\t%1,%0"
|
[(set_attr "move_type" "sll0,store")
|
[(set_attr "move_type" "sll0,store")
|
(set_attr "mode" "SI")])
|
(set_attr "mode" "SI")])
|
|
|
;; Combiner patterns to optimize shift/truncate combinations.
|
;; Combiner patterns to optimize shift/truncate combinations.
|
|
|
(define_insn "*ashr_trunc"
|
(define_insn "*ashr_trunc"
|
[(set (match_operand:SUBDI 0 "register_operand" "=d")
|
[(set (match_operand:SUBDI 0 "register_operand" "=d")
|
(truncate:SUBDI
|
(truncate:SUBDI
|
(ashiftrt:DI (match_operand:DI 1 "register_operand" "d")
|
(ashiftrt:DI (match_operand:DI 1 "register_operand" "d")
|
(match_operand:DI 2 "const_arith_operand" ""))))]
|
(match_operand:DI 2 "const_arith_operand" ""))))]
|
"TARGET_64BIT && !TARGET_MIPS16 && IN_RANGE (INTVAL (operands[2]), 32, 63)"
|
"TARGET_64BIT && !TARGET_MIPS16 && IN_RANGE (INTVAL (operands[2]), 32, 63)"
|
"dsra\t%0,%1,%2"
|
"dsra\t%0,%1,%2"
|
[(set_attr "type" "shift")
|
[(set_attr "type" "shift")
|
(set_attr "mode" "")])
|
(set_attr "mode" "")])
|
|
|
(define_insn "*lshr32_trunc"
|
(define_insn "*lshr32_trunc"
|
[(set (match_operand:SUBDI 0 "register_operand" "=d")
|
[(set (match_operand:SUBDI 0 "register_operand" "=d")
|
(truncate:SUBDI
|
(truncate:SUBDI
|
(lshiftrt:DI (match_operand:DI 1 "register_operand" "d")
|
(lshiftrt:DI (match_operand:DI 1 "register_operand" "d")
|
(const_int 32))))]
|
(const_int 32))))]
|
"TARGET_64BIT && !TARGET_MIPS16"
|
"TARGET_64BIT && !TARGET_MIPS16"
|
"dsra\t%0,%1,32"
|
"dsra\t%0,%1,32"
|
[(set_attr "type" "shift")
|
[(set_attr "type" "shift")
|
(set_attr "mode" "")])
|
(set_attr "mode" "")])
|
|
|
;; Logical shift by more than 32 results in proper SI values so truncation is
|
;; Logical shift by more than 32 results in proper SI values so truncation is
|
;; removed by the middle end. Note that a logical shift by 32 is handled by
|
;; removed by the middle end. Note that a logical shift by 32 is handled by
|
;; the previous pattern.
|
;; the previous pattern.
|
(define_insn "*_trunc_exts"
|
(define_insn "*_trunc_exts"
|
[(set (match_operand:SUBDI 0 "register_operand" "=d")
|
[(set (match_operand:SUBDI 0 "register_operand" "=d")
|
(truncate:SUBDI
|
(truncate:SUBDI
|
(any_shiftrt:DI (match_operand:DI 1 "register_operand" "d")
|
(any_shiftrt:DI (match_operand:DI 1 "register_operand" "d")
|
(match_operand:DI 2 "const_arith_operand" ""))))]
|
(match_operand:DI 2 "const_arith_operand" ""))))]
|
"ISA_HAS_EXTS && TARGET_64BIT && UINTVAL (operands[2]) < 32"
|
"ISA_HAS_EXTS && TARGET_64BIT && UINTVAL (operands[2]) < 32"
|
"exts\t%0,%1,%2,31"
|
"exts\t%0,%1,%2,31"
|
[(set_attr "type" "arith")
|
[(set_attr "type" "arith")
|
(set_attr "mode" "")])
|
(set_attr "mode" "")])
|
|
|
;;
|
;;
|
;; ....................
|
;; ....................
|
;;
|
;;
|
;; ZERO EXTENSION
|
;; ZERO EXTENSION
|
;;
|
;;
|
;; ....................
|
;; ....................
|
|
|
;; Extension insns.
|
;; Extension insns.
|
|
|
(define_expand "zero_extendsidi2"
|
(define_expand "zero_extendsidi2"
|
[(set (match_operand:DI 0 "register_operand")
|
[(set (match_operand:DI 0 "register_operand")
|
(zero_extend:DI (match_operand:SI 1 "nonimmediate_operand")))]
|
(zero_extend:DI (match_operand:SI 1 "nonimmediate_operand")))]
|
"TARGET_64BIT")
|
"TARGET_64BIT")
|
|
|
(define_insn_and_split "*zero_extendsidi2"
|
(define_insn_and_split "*zero_extendsidi2"
|
[(set (match_operand:DI 0 "register_operand" "=d,d")
|
[(set (match_operand:DI 0 "register_operand" "=d,d")
|
(zero_extend:DI (match_operand:SI 1 "nonimmediate_operand" "d,W")))]
|
(zero_extend:DI (match_operand:SI 1 "nonimmediate_operand" "d,W")))]
|
"TARGET_64BIT && !ISA_HAS_EXT_INS"
|
"TARGET_64BIT && !ISA_HAS_EXT_INS"
|
"@
|
"@
|
#
|
#
|
lwu\t%0,%1"
|
lwu\t%0,%1"
|
"&& reload_completed && REG_P (operands[1])"
|
"&& reload_completed && REG_P (operands[1])"
|
[(set (match_dup 0)
|
[(set (match_dup 0)
|
(ashift:DI (match_dup 1) (const_int 32)))
|
(ashift:DI (match_dup 1) (const_int 32)))
|
(set (match_dup 0)
|
(set (match_dup 0)
|
(lshiftrt:DI (match_dup 0) (const_int 32)))]
|
(lshiftrt:DI (match_dup 0) (const_int 32)))]
|
{ operands[1] = gen_lowpart (DImode, operands[1]); }
|
{ operands[1] = gen_lowpart (DImode, operands[1]); }
|
[(set_attr "move_type" "shift_shift,load")
|
[(set_attr "move_type" "shift_shift,load")
|
(set_attr "mode" "DI")])
|
(set_attr "mode" "DI")])
|
|
|
(define_insn "*zero_extendsidi2_dext"
|
(define_insn "*zero_extendsidi2_dext"
|
[(set (match_operand:DI 0 "register_operand" "=d,d")
|
[(set (match_operand:DI 0 "register_operand" "=d,d")
|
(zero_extend:DI (match_operand:SI 1 "nonimmediate_operand" "d,W")))]
|
(zero_extend:DI (match_operand:SI 1 "nonimmediate_operand" "d,W")))]
|
"TARGET_64BIT && ISA_HAS_EXT_INS"
|
"TARGET_64BIT && ISA_HAS_EXT_INS"
|
"@
|
"@
|
dext\t%0,%1,0,32
|
dext\t%0,%1,0,32
|
lwu\t%0,%1"
|
lwu\t%0,%1"
|
[(set_attr "move_type" "arith,load")
|
[(set_attr "move_type" "arith,load")
|
(set_attr "mode" "DI")])
|
(set_attr "mode" "DI")])
|
|
|
;; See the comment before the *and3 pattern why this is generated by
|
;; See the comment before the *and3 pattern why this is generated by
|
;; combine.
|
;; combine.
|
|
|
(define_split
|
(define_split
|
[(set (match_operand:DI 0 "register_operand")
|
[(set (match_operand:DI 0 "register_operand")
|
(and:DI (match_operand:DI 1 "register_operand")
|
(and:DI (match_operand:DI 1 "register_operand")
|
(const_int 4294967295)))]
|
(const_int 4294967295)))]
|
"TARGET_64BIT && !ISA_HAS_EXT_INS && reload_completed"
|
"TARGET_64BIT && !ISA_HAS_EXT_INS && reload_completed"
|
[(set (match_dup 0)
|
[(set (match_dup 0)
|
(ashift:DI (match_dup 1) (const_int 32)))
|
(ashift:DI (match_dup 1) (const_int 32)))
|
(set (match_dup 0)
|
(set (match_dup 0)
|
(lshiftrt:DI (match_dup 0) (const_int 32)))])
|
(lshiftrt:DI (match_dup 0) (const_int 32)))])
|
|
|
(define_expand "zero_extend2"
|
(define_expand "zero_extend2"
|
[(set (match_operand:GPR 0 "register_operand")
|
[(set (match_operand:GPR 0 "register_operand")
|
(zero_extend:GPR (match_operand:SHORT 1 "nonimmediate_operand")))]
|
(zero_extend:GPR (match_operand:SHORT 1 "nonimmediate_operand")))]
|
""
|
""
|
{
|
{
|
if (TARGET_MIPS16 && !GENERATE_MIPS16E
|
if (TARGET_MIPS16 && !GENERATE_MIPS16E
|
&& !memory_operand (operands[1], mode))
|
&& !memory_operand (operands[1], mode))
|
{
|
{
|
emit_insn (gen_and3 (operands[0],
|
emit_insn (gen_and3 (operands[0],
|
gen_lowpart (mode, operands[1]),
|
gen_lowpart (mode, operands[1]),
|
force_reg (mode,
|
force_reg (mode,
|
GEN_INT ())));
|
GEN_INT ())));
|
DONE;
|
DONE;
|
}
|
}
|
})
|
})
|
|
|
(define_insn "*zero_extend2"
|
(define_insn "*zero_extend2"
|
[(set (match_operand:GPR 0 "register_operand" "=d,d")
|
[(set (match_operand:GPR 0 "register_operand" "=d,d")
|
(zero_extend:GPR
|
(zero_extend:GPR
|
(match_operand:SHORT 1 "nonimmediate_operand" "d,m")))]
|
(match_operand:SHORT 1 "nonimmediate_operand" "d,m")))]
|
"!TARGET_MIPS16"
|
"!TARGET_MIPS16"
|
"@
|
"@
|
andi\t%0,%1,
|
andi\t%0,%1,
|
lu\t%0,%1"
|
lu\t%0,%1"
|
[(set_attr "move_type" "andi,load")
|
[(set_attr "move_type" "andi,load")
|
(set_attr "mode" "")])
|
(set_attr "mode" "")])
|
|
|
(define_insn "*zero_extend2_mips16e"
|
(define_insn "*zero_extend2_mips16e"
|
[(set (match_operand:GPR 0 "register_operand" "=d")
|
[(set (match_operand:GPR 0 "register_operand" "=d")
|
(zero_extend:GPR (match_operand:SHORT 1 "register_operand" "0")))]
|
(zero_extend:GPR (match_operand:SHORT 1 "register_operand" "0")))]
|
"GENERATE_MIPS16E"
|
"GENERATE_MIPS16E"
|
"ze\t%0"
|
"ze\t%0"
|
;; This instruction is effectively a special encoding of ANDI.
|
;; This instruction is effectively a special encoding of ANDI.
|
[(set_attr "move_type" "andi")
|
[(set_attr "move_type" "andi")
|
(set_attr "mode" "")])
|
(set_attr "mode" "")])
|
|
|
(define_insn "*zero_extend2_mips16"
|
(define_insn "*zero_extend2_mips16"
|
[(set (match_operand:GPR 0 "register_operand" "=d")
|
[(set (match_operand:GPR 0 "register_operand" "=d")
|
(zero_extend:GPR (match_operand:SHORT 1 "memory_operand" "m")))]
|
(zero_extend:GPR (match_operand:SHORT 1 "memory_operand" "m")))]
|
"TARGET_MIPS16"
|
"TARGET_MIPS16"
|
"lu\t%0,%1"
|
"lu\t%0,%1"
|
[(set_attr "move_type" "load")
|
[(set_attr "move_type" "load")
|
(set_attr "mode" "")])
|
(set_attr "mode" "")])
|
|
|
(define_expand "zero_extendqihi2"
|
(define_expand "zero_extendqihi2"
|
[(set (match_operand:HI 0 "register_operand")
|
[(set (match_operand:HI 0 "register_operand")
|
(zero_extend:HI (match_operand:QI 1 "nonimmediate_operand")))]
|
(zero_extend:HI (match_operand:QI 1 "nonimmediate_operand")))]
|
""
|
""
|
{
|
{
|
if (TARGET_MIPS16 && !memory_operand (operands[1], QImode))
|
if (TARGET_MIPS16 && !memory_operand (operands[1], QImode))
|
{
|
{
|
emit_insn (gen_zero_extendqisi2 (gen_lowpart (SImode, operands[0]),
|
emit_insn (gen_zero_extendqisi2 (gen_lowpart (SImode, operands[0]),
|
operands[1]));
|
operands[1]));
|
DONE;
|
DONE;
|
}
|
}
|
})
|
})
|
|
|
(define_insn "*zero_extendqihi2"
|
(define_insn "*zero_extendqihi2"
|
[(set (match_operand:HI 0 "register_operand" "=d,d")
|
[(set (match_operand:HI 0 "register_operand" "=d,d")
|
(zero_extend:HI (match_operand:QI 1 "nonimmediate_operand" "d,m")))]
|
(zero_extend:HI (match_operand:QI 1 "nonimmediate_operand" "d,m")))]
|
"!TARGET_MIPS16"
|
"!TARGET_MIPS16"
|
"@
|
"@
|
andi\t%0,%1,0x00ff
|
andi\t%0,%1,0x00ff
|
lbu\t%0,%1"
|
lbu\t%0,%1"
|
[(set_attr "move_type" "andi,load")
|
[(set_attr "move_type" "andi,load")
|
(set_attr "mode" "HI")])
|
(set_attr "mode" "HI")])
|
|
|
(define_insn "*zero_extendqihi2_mips16"
|
(define_insn "*zero_extendqihi2_mips16"
|
[(set (match_operand:HI 0 "register_operand" "=d")
|
[(set (match_operand:HI 0 "register_operand" "=d")
|
(zero_extend:HI (match_operand:QI 1 "memory_operand" "m")))]
|
(zero_extend:HI (match_operand:QI 1 "memory_operand" "m")))]
|
"TARGET_MIPS16"
|
"TARGET_MIPS16"
|
"lbu\t%0,%1"
|
"lbu\t%0,%1"
|
[(set_attr "move_type" "load")
|
[(set_attr "move_type" "load")
|
(set_attr "mode" "HI")])
|
(set_attr "mode" "HI")])
|
|
|
;; Combiner patterns to optimize truncate/zero_extend combinations.
|
;; Combiner patterns to optimize truncate/zero_extend combinations.
|
|
|
(define_insn "*zero_extend_trunc"
|
(define_insn "*zero_extend_trunc"
|
[(set (match_operand:GPR 0 "register_operand" "=d")
|
[(set (match_operand:GPR 0 "register_operand" "=d")
|
(zero_extend:GPR
|
(zero_extend:GPR
|
(truncate:SHORT (match_operand:DI 1 "register_operand" "d"))))]
|
(truncate:SHORT (match_operand:DI 1 "register_operand" "d"))))]
|
"TARGET_64BIT && !TARGET_MIPS16"
|
"TARGET_64BIT && !TARGET_MIPS16"
|
{
|
{
|
operands[2] = GEN_INT (GET_MODE_MASK (mode));
|
operands[2] = GEN_INT (GET_MODE_MASK (mode));
|
return "andi\t%0,%1,%x2";
|
return "andi\t%0,%1,%x2";
|
}
|
}
|
[(set_attr "type" "logical")
|
[(set_attr "type" "logical")
|
(set_attr "mode" "")])
|
(set_attr "mode" "")])
|
|
|
(define_insn "*zero_extendhi_truncqi"
|
(define_insn "*zero_extendhi_truncqi"
|
[(set (match_operand:HI 0 "register_operand" "=d")
|
[(set (match_operand:HI 0 "register_operand" "=d")
|
(zero_extend:HI
|
(zero_extend:HI
|
(truncate:QI (match_operand:DI 1 "register_operand" "d"))))]
|
(truncate:QI (match_operand:DI 1 "register_operand" "d"))))]
|
"TARGET_64BIT && !TARGET_MIPS16"
|
"TARGET_64BIT && !TARGET_MIPS16"
|
"andi\t%0,%1,0xff"
|
"andi\t%0,%1,0xff"
|
[(set_attr "type" "logical")
|
[(set_attr "type" "logical")
|
(set_attr "mode" "HI")])
|
(set_attr "mode" "HI")])
|
|
|
;;
|
;;
|
;; ....................
|
;; ....................
|
;;
|
;;
|
;; SIGN EXTENSION
|
;; SIGN EXTENSION
|
;;
|
;;
|
;; ....................
|
;; ....................
|
|
|
;; Extension insns.
|
;; Extension insns.
|
;; Those for integer source operand are ordered widest source type first.
|
;; Those for integer source operand are ordered widest source type first.
|
|
|
;; When TARGET_64BIT, all SImode integer registers should already be in
|
;; When TARGET_64BIT, all SImode integer registers should already be in
|
;; sign-extended form (see TRULY_NOOP_TRUNCATION and truncdisi2). We can
|
;; sign-extended form (see TRULY_NOOP_TRUNCATION and truncdisi2). We can
|
;; therefore get rid of register->register instructions if we constrain
|
;; therefore get rid of register->register instructions if we constrain
|
;; the source to be in the same register as the destination.
|
;; the source to be in the same register as the destination.
|
;;
|
;;
|
;; The register alternative has type "arith" so that the pre-reload
|
;; The register alternative has type "arith" so that the pre-reload
|
;; scheduler will treat it as a move. This reflects what happens if
|
;; scheduler will treat it as a move. This reflects what happens if
|
;; the register alternative needs a reload.
|
;; the register alternative needs a reload.
|
(define_insn_and_split "extendsidi2"
|
(define_insn_and_split "extendsidi2"
|
[(set (match_operand:DI 0 "register_operand" "=d,d")
|
[(set (match_operand:DI 0 "register_operand" "=d,d")
|
(sign_extend:DI (match_operand:SI 1 "nonimmediate_operand" "0,m")))]
|
(sign_extend:DI (match_operand:SI 1 "nonimmediate_operand" "0,m")))]
|
"TARGET_64BIT"
|
"TARGET_64BIT"
|
"@
|
"@
|
#
|
#
|
lw\t%0,%1"
|
lw\t%0,%1"
|
"&& reload_completed && register_operand (operands[1], VOIDmode)"
|
"&& reload_completed && register_operand (operands[1], VOIDmode)"
|
[(const_int 0)]
|
[(const_int 0)]
|
{
|
{
|
emit_note (NOTE_INSN_DELETED);
|
emit_note (NOTE_INSN_DELETED);
|
DONE;
|
DONE;
|
}
|
}
|
[(set_attr "move_type" "move,load")
|
[(set_attr "move_type" "move,load")
|
(set_attr "mode" "DI")])
|
(set_attr "mode" "DI")])
|
|
|
(define_expand "extend2"
|
(define_expand "extend2"
|
[(set (match_operand:GPR 0 "register_operand")
|
[(set (match_operand:GPR 0 "register_operand")
|
(sign_extend:GPR (match_operand:SHORT 1 "nonimmediate_operand")))]
|
(sign_extend:GPR (match_operand:SHORT 1 "nonimmediate_operand")))]
|
"")
|
"")
|
|
|
(define_insn "*extend2_mips16e"
|
(define_insn "*extend2_mips16e"
|
[(set (match_operand:GPR 0 "register_operand" "=d,d")
|
[(set (match_operand:GPR 0 "register_operand" "=d,d")
|
(sign_extend:GPR (match_operand:SHORT 1 "nonimmediate_operand" "0,m")))]
|
(sign_extend:GPR (match_operand:SHORT 1 "nonimmediate_operand" "0,m")))]
|
"GENERATE_MIPS16E"
|
"GENERATE_MIPS16E"
|
"@
|
"@
|
se\t%0
|
se\t%0
|
l\t%0,%1"
|
l\t%0,%1"
|
[(set_attr "move_type" "signext,load")
|
[(set_attr "move_type" "signext,load")
|
(set_attr "mode" "")])
|
(set_attr "mode" "")])
|
|
|
(define_insn_and_split "*extend2"
|
(define_insn_and_split "*extend2"
|
[(set (match_operand:GPR 0 "register_operand" "=d,d")
|
[(set (match_operand:GPR 0 "register_operand" "=d,d")
|
(sign_extend:GPR
|
(sign_extend:GPR
|
(match_operand:SHORT 1 "nonimmediate_operand" "d,m")))]
|
(match_operand:SHORT 1 "nonimmediate_operand" "d,m")))]
|
"!ISA_HAS_SEB_SEH && !GENERATE_MIPS16E"
|
"!ISA_HAS_SEB_SEH && !GENERATE_MIPS16E"
|
"@
|
"@
|
#
|
#
|
l\t%0,%1"
|
l\t%0,%1"
|
"&& reload_completed && REG_P (operands[1])"
|
"&& reload_completed && REG_P (operands[1])"
|
[(set (match_dup 0) (ashift:GPR (match_dup 1) (match_dup 2)))
|
[(set (match_dup 0) (ashift:GPR (match_dup 1) (match_dup 2)))
|
(set (match_dup 0) (ashiftrt:GPR (match_dup 0) (match_dup 2)))]
|
(set (match_dup 0) (ashiftrt:GPR (match_dup 0) (match_dup 2)))]
|
{
|
{
|
operands[1] = gen_lowpart (mode, operands[1]);
|
operands[1] = gen_lowpart (mode, operands[1]);
|
operands[2] = GEN_INT (GET_MODE_BITSIZE (mode)
|
operands[2] = GEN_INT (GET_MODE_BITSIZE (mode)
|
- GET_MODE_BITSIZE (mode));
|
- GET_MODE_BITSIZE (mode));
|
}
|
}
|
[(set_attr "move_type" "shift_shift,load")
|
[(set_attr "move_type" "shift_shift,load")
|
(set_attr "mode" "")])
|
(set_attr "mode" "")])
|
|
|
(define_insn "*extend2_se"
|
(define_insn "*extend2_se"
|
[(set (match_operand:GPR 0 "register_operand" "=d,d")
|
[(set (match_operand:GPR 0 "register_operand" "=d,d")
|
(sign_extend:GPR
|
(sign_extend:GPR
|
(match_operand:SHORT 1 "nonimmediate_operand" "d,m")))]
|
(match_operand:SHORT 1 "nonimmediate_operand" "d,m")))]
|
"ISA_HAS_SEB_SEH"
|
"ISA_HAS_SEB_SEH"
|
"@
|
"@
|
se\t%0,%1
|
se\t%0,%1
|
l\t%0,%1"
|
l\t%0,%1"
|
[(set_attr "move_type" "signext,load")
|
[(set_attr "move_type" "signext,load")
|
(set_attr "mode" "")])
|
(set_attr "mode" "")])
|
|
|
(define_expand "extendqihi2"
|
(define_expand "extendqihi2"
|
[(set (match_operand:HI 0 "register_operand")
|
[(set (match_operand:HI 0 "register_operand")
|
(sign_extend:HI (match_operand:QI 1 "nonimmediate_operand")))]
|
(sign_extend:HI (match_operand:QI 1 "nonimmediate_operand")))]
|
"")
|
"")
|
|
|
(define_insn "*extendqihi2_mips16e"
|
(define_insn "*extendqihi2_mips16e"
|
[(set (match_operand:HI 0 "register_operand" "=d,d")
|
[(set (match_operand:HI 0 "register_operand" "=d,d")
|
(sign_extend:HI (match_operand:QI 1 "nonimmediate_operand" "0,m")))]
|
(sign_extend:HI (match_operand:QI 1 "nonimmediate_operand" "0,m")))]
|
"GENERATE_MIPS16E"
|
"GENERATE_MIPS16E"
|
"@
|
"@
|
seb\t%0
|
seb\t%0
|
lb\t%0,%1"
|
lb\t%0,%1"
|
[(set_attr "move_type" "signext,load")
|
[(set_attr "move_type" "signext,load")
|
(set_attr "mode" "SI")])
|
(set_attr "mode" "SI")])
|
|
|
(define_insn_and_split "*extendqihi2"
|
(define_insn_and_split "*extendqihi2"
|
[(set (match_operand:HI 0 "register_operand" "=d,d")
|
[(set (match_operand:HI 0 "register_operand" "=d,d")
|
(sign_extend:HI
|
(sign_extend:HI
|
(match_operand:QI 1 "nonimmediate_operand" "d,m")))]
|
(match_operand:QI 1 "nonimmediate_operand" "d,m")))]
|
"!ISA_HAS_SEB_SEH && !GENERATE_MIPS16E"
|
"!ISA_HAS_SEB_SEH && !GENERATE_MIPS16E"
|
"@
|
"@
|
#
|
#
|
lb\t%0,%1"
|
lb\t%0,%1"
|
"&& reload_completed && REG_P (operands[1])"
|
"&& reload_completed && REG_P (operands[1])"
|
[(set (match_dup 0) (ashift:SI (match_dup 1) (match_dup 2)))
|
[(set (match_dup 0) (ashift:SI (match_dup 1) (match_dup 2)))
|
(set (match_dup 0) (ashiftrt:SI (match_dup 0) (match_dup 2)))]
|
(set (match_dup 0) (ashiftrt:SI (match_dup 0) (match_dup 2)))]
|
{
|
{
|
operands[0] = gen_lowpart (SImode, operands[0]);
|
operands[0] = gen_lowpart (SImode, operands[0]);
|
operands[1] = gen_lowpart (SImode, operands[1]);
|
operands[1] = gen_lowpart (SImode, operands[1]);
|
operands[2] = GEN_INT (GET_MODE_BITSIZE (SImode)
|
operands[2] = GEN_INT (GET_MODE_BITSIZE (SImode)
|
- GET_MODE_BITSIZE (QImode));
|
- GET_MODE_BITSIZE (QImode));
|
}
|
}
|
[(set_attr "move_type" "shift_shift,load")
|
[(set_attr "move_type" "shift_shift,load")
|
(set_attr "mode" "SI")])
|
(set_attr "mode" "SI")])
|
|
|
(define_insn "*extendqihi2_seb"
|
(define_insn "*extendqihi2_seb"
|
[(set (match_operand:HI 0 "register_operand" "=d,d")
|
[(set (match_operand:HI 0 "register_operand" "=d,d")
|
(sign_extend:HI
|
(sign_extend:HI
|
(match_operand:QI 1 "nonimmediate_operand" "d,m")))]
|
(match_operand:QI 1 "nonimmediate_operand" "d,m")))]
|
"ISA_HAS_SEB_SEH"
|
"ISA_HAS_SEB_SEH"
|
"@
|
"@
|
seb\t%0,%1
|
seb\t%0,%1
|
lb\t%0,%1"
|
lb\t%0,%1"
|
[(set_attr "move_type" "signext,load")
|
[(set_attr "move_type" "signext,load")
|
(set_attr "mode" "SI")])
|
(set_attr "mode" "SI")])
|
|
|
;; Combiner patterns for truncate/sign_extend combinations. The SI versions
|
;; Combiner patterns for truncate/sign_extend combinations. The SI versions
|
;; use the shift/truncate patterns.
|
;; use the shift/truncate patterns.
|
|
|
(define_insn_and_split "*extenddi_truncate"
|
(define_insn_and_split "*extenddi_truncate"
|
[(set (match_operand:DI 0 "register_operand" "=d")
|
[(set (match_operand:DI 0 "register_operand" "=d")
|
(sign_extend:DI
|
(sign_extend:DI
|
(truncate:SHORT (match_operand:DI 1 "register_operand" "d"))))]
|
(truncate:SHORT (match_operand:DI 1 "register_operand" "d"))))]
|
"TARGET_64BIT && !TARGET_MIPS16 && !ISA_HAS_EXTS"
|
"TARGET_64BIT && !TARGET_MIPS16 && !ISA_HAS_EXTS"
|
"#"
|
"#"
|
"&& reload_completed"
|
"&& reload_completed"
|
[(set (match_dup 2)
|
[(set (match_dup 2)
|
(ashift:DI (match_dup 1)
|
(ashift:DI (match_dup 1)
|
(match_dup 3)))
|
(match_dup 3)))
|
(set (match_dup 0)
|
(set (match_dup 0)
|
(ashiftrt:DI (match_dup 2)
|
(ashiftrt:DI (match_dup 2)
|
(match_dup 3)))]
|
(match_dup 3)))]
|
{
|
{
|
operands[2] = gen_lowpart (DImode, operands[0]);
|
operands[2] = gen_lowpart (DImode, operands[0]);
|
operands[3] = GEN_INT (BITS_PER_WORD - GET_MODE_BITSIZE (mode));
|
operands[3] = GEN_INT (BITS_PER_WORD - GET_MODE_BITSIZE (mode));
|
}
|
}
|
[(set_attr "move_type" "shift_shift")
|
[(set_attr "move_type" "shift_shift")
|
(set_attr "mode" "DI")])
|
(set_attr "mode" "DI")])
|
|
|
(define_insn_and_split "*extendsi_truncate"
|
(define_insn_and_split "*extendsi_truncate"
|
[(set (match_operand:SI 0 "register_operand" "=d")
|
[(set (match_operand:SI 0 "register_operand" "=d")
|
(sign_extend:SI
|
(sign_extend:SI
|
(truncate:SHORT (match_operand:DI 1 "register_operand" "d"))))]
|
(truncate:SHORT (match_operand:DI 1 "register_operand" "d"))))]
|
"TARGET_64BIT && !TARGET_MIPS16 && !ISA_HAS_EXTS"
|
"TARGET_64BIT && !TARGET_MIPS16 && !ISA_HAS_EXTS"
|
"#"
|
"#"
|
"&& reload_completed"
|
"&& reload_completed"
|
[(set (match_dup 2)
|
[(set (match_dup 2)
|
(ashift:DI (match_dup 1)
|
(ashift:DI (match_dup 1)
|
(match_dup 3)))
|
(match_dup 3)))
|
(set (match_dup 0)
|
(set (match_dup 0)
|
(truncate:SI (ashiftrt:DI (match_dup 2)
|
(truncate:SI (ashiftrt:DI (match_dup 2)
|
(match_dup 3))))]
|
(match_dup 3))))]
|
{
|
{
|
operands[2] = gen_lowpart (DImode, operands[0]);
|
operands[2] = gen_lowpart (DImode, operands[0]);
|
operands[3] = GEN_INT (BITS_PER_WORD - GET_MODE_BITSIZE (mode));
|
operands[3] = GEN_INT (BITS_PER_WORD - GET_MODE_BITSIZE (mode));
|
}
|
}
|
[(set_attr "move_type" "shift_shift")
|
[(set_attr "move_type" "shift_shift")
|
(set_attr "mode" "SI")])
|
(set_attr "mode" "SI")])
|
|
|
(define_insn_and_split "*extendhi_truncateqi"
|
(define_insn_and_split "*extendhi_truncateqi"
|
[(set (match_operand:HI 0 "register_operand" "=d")
|
[(set (match_operand:HI 0 "register_operand" "=d")
|
(sign_extend:HI
|
(sign_extend:HI
|
(truncate:QI (match_operand:DI 1 "register_operand" "d"))))]
|
(truncate:QI (match_operand:DI 1 "register_operand" "d"))))]
|
"TARGET_64BIT && !TARGET_MIPS16 && !ISA_HAS_EXTS"
|
"TARGET_64BIT && !TARGET_MIPS16 && !ISA_HAS_EXTS"
|
"#"
|
"#"
|
"&& reload_completed"
|
"&& reload_completed"
|
[(set (match_dup 2)
|
[(set (match_dup 2)
|
(ashift:DI (match_dup 1)
|
(ashift:DI (match_dup 1)
|
(const_int 56)))
|
(const_int 56)))
|
(set (match_dup 0)
|
(set (match_dup 0)
|
(truncate:HI (ashiftrt:DI (match_dup 2)
|
(truncate:HI (ashiftrt:DI (match_dup 2)
|
(const_int 56))))]
|
(const_int 56))))]
|
{
|
{
|
operands[2] = gen_lowpart (DImode, operands[0]);
|
operands[2] = gen_lowpart (DImode, operands[0]);
|
}
|
}
|
[(set_attr "move_type" "shift_shift")
|
[(set_attr "move_type" "shift_shift")
|
(set_attr "mode" "SI")])
|
(set_attr "mode" "SI")])
|
|
|
(define_insn "*extend_truncate_exts"
|
(define_insn "*extend_truncate_exts"
|
[(set (match_operand:GPR 0 "register_operand" "=d")
|
[(set (match_operand:GPR 0 "register_operand" "=d")
|
(sign_extend:GPR
|
(sign_extend:GPR
|
(truncate:SHORT (match_operand:DI 1 "register_operand" "d"))))]
|
(truncate:SHORT (match_operand:DI 1 "register_operand" "d"))))]
|
"TARGET_64BIT && !TARGET_MIPS16 && ISA_HAS_EXTS"
|
"TARGET_64BIT && !TARGET_MIPS16 && ISA_HAS_EXTS"
|
{
|
{
|
operands[2] = GEN_INT (GET_MODE_BITSIZE (mode));
|
operands[2] = GEN_INT (GET_MODE_BITSIZE (mode));
|
return "exts\t%0,%1,0,%m2";
|
return "exts\t%0,%1,0,%m2";
|
}
|
}
|
[(set_attr "type" "arith")
|
[(set_attr "type" "arith")
|
(set_attr "mode" "")])
|
(set_attr "mode" "")])
|
|
|
(define_insn "*extendhi_truncateqi_exts"
|
(define_insn "*extendhi_truncateqi_exts"
|
[(set (match_operand:HI 0 "register_operand" "=d")
|
[(set (match_operand:HI 0 "register_operand" "=d")
|
(sign_extend:HI
|
(sign_extend:HI
|
(truncate:QI (match_operand:DI 1 "register_operand" "d"))))]
|
(truncate:QI (match_operand:DI 1 "register_operand" "d"))))]
|
"TARGET_64BIT && !TARGET_MIPS16 && ISA_HAS_EXTS"
|
"TARGET_64BIT && !TARGET_MIPS16 && ISA_HAS_EXTS"
|
"exts\t%0,%1,0,7"
|
"exts\t%0,%1,0,7"
|
[(set_attr "type" "arith")
|
[(set_attr "type" "arith")
|
(set_attr "mode" "SI")])
|
(set_attr "mode" "SI")])
|
|
|
(define_insn "extendsfdf2"
|
(define_insn "extendsfdf2"
|
[(set (match_operand:DF 0 "register_operand" "=f")
|
[(set (match_operand:DF 0 "register_operand" "=f")
|
(float_extend:DF (match_operand:SF 1 "register_operand" "f")))]
|
(float_extend:DF (match_operand:SF 1 "register_operand" "f")))]
|
"TARGET_HARD_FLOAT && TARGET_DOUBLE_FLOAT"
|
"TARGET_HARD_FLOAT && TARGET_DOUBLE_FLOAT"
|
"cvt.d.s\t%0,%1"
|
"cvt.d.s\t%0,%1"
|
[(set_attr "type" "fcvt")
|
[(set_attr "type" "fcvt")
|
(set_attr "cnv_mode" "S2D")
|
(set_attr "cnv_mode" "S2D")
|
(set_attr "mode" "DF")])
|
(set_attr "mode" "DF")])
|
|
|
;;
|
;;
|
;; ....................
|
;; ....................
|
;;
|
;;
|
;; CONVERSIONS
|
;; CONVERSIONS
|
;;
|
;;
|
;; ....................
|
;; ....................
|
|
|
(define_expand "fix_truncdfsi2"
|
(define_expand "fix_truncdfsi2"
|
[(set (match_operand:SI 0 "register_operand")
|
[(set (match_operand:SI 0 "register_operand")
|
(fix:SI (match_operand:DF 1 "register_operand")))]
|
(fix:SI (match_operand:DF 1 "register_operand")))]
|
"TARGET_HARD_FLOAT && TARGET_DOUBLE_FLOAT"
|
"TARGET_HARD_FLOAT && TARGET_DOUBLE_FLOAT"
|
{
|
{
|
if (!ISA_HAS_TRUNC_W)
|
if (!ISA_HAS_TRUNC_W)
|
{
|
{
|
emit_insn (gen_fix_truncdfsi2_macro (operands[0], operands[1]));
|
emit_insn (gen_fix_truncdfsi2_macro (operands[0], operands[1]));
|
DONE;
|
DONE;
|
}
|
}
|
})
|
})
|
|
|
(define_insn "fix_truncdfsi2_insn"
|
(define_insn "fix_truncdfsi2_insn"
|
[(set (match_operand:SI 0 "register_operand" "=f")
|
[(set (match_operand:SI 0 "register_operand" "=f")
|
(fix:SI (match_operand:DF 1 "register_operand" "f")))]
|
(fix:SI (match_operand:DF 1 "register_operand" "f")))]
|
"TARGET_HARD_FLOAT && TARGET_DOUBLE_FLOAT && ISA_HAS_TRUNC_W"
|
"TARGET_HARD_FLOAT && TARGET_DOUBLE_FLOAT && ISA_HAS_TRUNC_W"
|
"trunc.w.d %0,%1"
|
"trunc.w.d %0,%1"
|
[(set_attr "type" "fcvt")
|
[(set_attr "type" "fcvt")
|
(set_attr "mode" "DF")
|
(set_attr "mode" "DF")
|
(set_attr "cnv_mode" "D2I")])
|
(set_attr "cnv_mode" "D2I")])
|
|
|
(define_insn "fix_truncdfsi2_macro"
|
(define_insn "fix_truncdfsi2_macro"
|
[(set (match_operand:SI 0 "register_operand" "=f")
|
[(set (match_operand:SI 0 "register_operand" "=f")
|
(fix:SI (match_operand:DF 1 "register_operand" "f")))
|
(fix:SI (match_operand:DF 1 "register_operand" "f")))
|
(clobber (match_scratch:DF 2 "=d"))]
|
(clobber (match_scratch:DF 2 "=d"))]
|
"TARGET_HARD_FLOAT && TARGET_DOUBLE_FLOAT && !ISA_HAS_TRUNC_W"
|
"TARGET_HARD_FLOAT && TARGET_DOUBLE_FLOAT && !ISA_HAS_TRUNC_W"
|
{
|
{
|
if (mips_nomacro.nesting_level > 0)
|
if (mips_nomacro.nesting_level > 0)
|
return ".set\tmacro\;trunc.w.d %0,%1,%2\;.set\tnomacro";
|
return ".set\tmacro\;trunc.w.d %0,%1,%2\;.set\tnomacro";
|
else
|
else
|
return "trunc.w.d %0,%1,%2";
|
return "trunc.w.d %0,%1,%2";
|
}
|
}
|
[(set_attr "type" "fcvt")
|
[(set_attr "type" "fcvt")
|
(set_attr "mode" "DF")
|
(set_attr "mode" "DF")
|
(set_attr "cnv_mode" "D2I")
|
(set_attr "cnv_mode" "D2I")
|
(set_attr "length" "36")])
|
(set_attr "length" "36")])
|
|
|
(define_expand "fix_truncsfsi2"
|
(define_expand "fix_truncsfsi2"
|
[(set (match_operand:SI 0 "register_operand")
|
[(set (match_operand:SI 0 "register_operand")
|
(fix:SI (match_operand:SF 1 "register_operand")))]
|
(fix:SI (match_operand:SF 1 "register_operand")))]
|
"TARGET_HARD_FLOAT"
|
"TARGET_HARD_FLOAT"
|
{
|
{
|
if (!ISA_HAS_TRUNC_W)
|
if (!ISA_HAS_TRUNC_W)
|
{
|
{
|
emit_insn (gen_fix_truncsfsi2_macro (operands[0], operands[1]));
|
emit_insn (gen_fix_truncsfsi2_macro (operands[0], operands[1]));
|
DONE;
|
DONE;
|
}
|
}
|
})
|
})
|
|
|
(define_insn "fix_truncsfsi2_insn"
|
(define_insn "fix_truncsfsi2_insn"
|
[(set (match_operand:SI 0 "register_operand" "=f")
|
[(set (match_operand:SI 0 "register_operand" "=f")
|
(fix:SI (match_operand:SF 1 "register_operand" "f")))]
|
(fix:SI (match_operand:SF 1 "register_operand" "f")))]
|
"TARGET_HARD_FLOAT && ISA_HAS_TRUNC_W"
|
"TARGET_HARD_FLOAT && ISA_HAS_TRUNC_W"
|
"trunc.w.s %0,%1"
|
"trunc.w.s %0,%1"
|
[(set_attr "type" "fcvt")
|
[(set_attr "type" "fcvt")
|
(set_attr "mode" "SF")
|
(set_attr "mode" "SF")
|
(set_attr "cnv_mode" "S2I")])
|
(set_attr "cnv_mode" "S2I")])
|
|
|
(define_insn "fix_truncsfsi2_macro"
|
(define_insn "fix_truncsfsi2_macro"
|
[(set (match_operand:SI 0 "register_operand" "=f")
|
[(set (match_operand:SI 0 "register_operand" "=f")
|
(fix:SI (match_operand:SF 1 "register_operand" "f")))
|
(fix:SI (match_operand:SF 1 "register_operand" "f")))
|
(clobber (match_scratch:SF 2 "=d"))]
|
(clobber (match_scratch:SF 2 "=d"))]
|
"TARGET_HARD_FLOAT && !ISA_HAS_TRUNC_W"
|
"TARGET_HARD_FLOAT && !ISA_HAS_TRUNC_W"
|
{
|
{
|
if (mips_nomacro.nesting_level > 0)
|
if (mips_nomacro.nesting_level > 0)
|
return ".set\tmacro\;trunc.w.s %0,%1,%2\;.set\tnomacro";
|
return ".set\tmacro\;trunc.w.s %0,%1,%2\;.set\tnomacro";
|
else
|
else
|
return "trunc.w.s %0,%1,%2";
|
return "trunc.w.s %0,%1,%2";
|
}
|
}
|
[(set_attr "type" "fcvt")
|
[(set_attr "type" "fcvt")
|
(set_attr "mode" "SF")
|
(set_attr "mode" "SF")
|
(set_attr "cnv_mode" "S2I")
|
(set_attr "cnv_mode" "S2I")
|
(set_attr "length" "36")])
|
(set_attr "length" "36")])
|
|
|
|
|
(define_insn "fix_truncdfdi2"
|
(define_insn "fix_truncdfdi2"
|
[(set (match_operand:DI 0 "register_operand" "=f")
|
[(set (match_operand:DI 0 "register_operand" "=f")
|
(fix:DI (match_operand:DF 1 "register_operand" "f")))]
|
(fix:DI (match_operand:DF 1 "register_operand" "f")))]
|
"TARGET_HARD_FLOAT && TARGET_FLOAT64 && TARGET_DOUBLE_FLOAT"
|
"TARGET_HARD_FLOAT && TARGET_FLOAT64 && TARGET_DOUBLE_FLOAT"
|
"trunc.l.d %0,%1"
|
"trunc.l.d %0,%1"
|
[(set_attr "type" "fcvt")
|
[(set_attr "type" "fcvt")
|
(set_attr "mode" "DF")
|
(set_attr "mode" "DF")
|
(set_attr "cnv_mode" "D2I")])
|
(set_attr "cnv_mode" "D2I")])
|
|
|
|
|
(define_insn "fix_truncsfdi2"
|
(define_insn "fix_truncsfdi2"
|
[(set (match_operand:DI 0 "register_operand" "=f")
|
[(set (match_operand:DI 0 "register_operand" "=f")
|
(fix:DI (match_operand:SF 1 "register_operand" "f")))]
|
(fix:DI (match_operand:SF 1 "register_operand" "f")))]
|
"TARGET_HARD_FLOAT && TARGET_FLOAT64 && TARGET_DOUBLE_FLOAT"
|
"TARGET_HARD_FLOAT && TARGET_FLOAT64 && TARGET_DOUBLE_FLOAT"
|
"trunc.l.s %0,%1"
|
"trunc.l.s %0,%1"
|
[(set_attr "type" "fcvt")
|
[(set_attr "type" "fcvt")
|
(set_attr "mode" "SF")
|
(set_attr "mode" "SF")
|
(set_attr "cnv_mode" "S2I")])
|
(set_attr "cnv_mode" "S2I")])
|
|
|
|
|
(define_insn "floatsidf2"
|
(define_insn "floatsidf2"
|
[(set (match_operand:DF 0 "register_operand" "=f")
|
[(set (match_operand:DF 0 "register_operand" "=f")
|
(float:DF (match_operand:SI 1 "register_operand" "f")))]
|
(float:DF (match_operand:SI 1 "register_operand" "f")))]
|
"TARGET_HARD_FLOAT && TARGET_DOUBLE_FLOAT"
|
"TARGET_HARD_FLOAT && TARGET_DOUBLE_FLOAT"
|
"cvt.d.w\t%0,%1"
|
"cvt.d.w\t%0,%1"
|
[(set_attr "type" "fcvt")
|
[(set_attr "type" "fcvt")
|
(set_attr "mode" "DF")
|
(set_attr "mode" "DF")
|
(set_attr "cnv_mode" "I2D")])
|
(set_attr "cnv_mode" "I2D")])
|
|
|
|
|
(define_insn "floatdidf2"
|
(define_insn "floatdidf2"
|
[(set (match_operand:DF 0 "register_operand" "=f")
|
[(set (match_operand:DF 0 "register_operand" "=f")
|
(float:DF (match_operand:DI 1 "register_operand" "f")))]
|
(float:DF (match_operand:DI 1 "register_operand" "f")))]
|
"TARGET_HARD_FLOAT && TARGET_FLOAT64 && TARGET_DOUBLE_FLOAT"
|
"TARGET_HARD_FLOAT && TARGET_FLOAT64 && TARGET_DOUBLE_FLOAT"
|
"cvt.d.l\t%0,%1"
|
"cvt.d.l\t%0,%1"
|
[(set_attr "type" "fcvt")
|
[(set_attr "type" "fcvt")
|
(set_attr "mode" "DF")
|
(set_attr "mode" "DF")
|
(set_attr "cnv_mode" "I2D")])
|
(set_attr "cnv_mode" "I2D")])
|
|
|
|
|
(define_insn "floatsisf2"
|
(define_insn "floatsisf2"
|
[(set (match_operand:SF 0 "register_operand" "=f")
|
[(set (match_operand:SF 0 "register_operand" "=f")
|
(float:SF (match_operand:SI 1 "register_operand" "f")))]
|
(float:SF (match_operand:SI 1 "register_operand" "f")))]
|
"TARGET_HARD_FLOAT"
|
"TARGET_HARD_FLOAT"
|
"cvt.s.w\t%0,%1"
|
"cvt.s.w\t%0,%1"
|
[(set_attr "type" "fcvt")
|
[(set_attr "type" "fcvt")
|
(set_attr "mode" "SF")
|
(set_attr "mode" "SF")
|
(set_attr "cnv_mode" "I2S")])
|
(set_attr "cnv_mode" "I2S")])
|
|
|
|
|
(define_insn "floatdisf2"
|
(define_insn "floatdisf2"
|
[(set (match_operand:SF 0 "register_operand" "=f")
|
[(set (match_operand:SF 0 "register_operand" "=f")
|
(float:SF (match_operand:DI 1 "register_operand" "f")))]
|
(float:SF (match_operand:DI 1 "register_operand" "f")))]
|
"TARGET_HARD_FLOAT && TARGET_FLOAT64 && TARGET_DOUBLE_FLOAT"
|
"TARGET_HARD_FLOAT && TARGET_FLOAT64 && TARGET_DOUBLE_FLOAT"
|
"cvt.s.l\t%0,%1"
|
"cvt.s.l\t%0,%1"
|
[(set_attr "type" "fcvt")
|
[(set_attr "type" "fcvt")
|
(set_attr "mode" "SF")
|
(set_attr "mode" "SF")
|
(set_attr "cnv_mode" "I2S")])
|
(set_attr "cnv_mode" "I2S")])
|
|
|
|
|
(define_expand "fixuns_truncdfsi2"
|
(define_expand "fixuns_truncdfsi2"
|
[(set (match_operand:SI 0 "register_operand")
|
[(set (match_operand:SI 0 "register_operand")
|
(unsigned_fix:SI (match_operand:DF 1 "register_operand")))]
|
(unsigned_fix:SI (match_operand:DF 1 "register_operand")))]
|
"TARGET_HARD_FLOAT && TARGET_DOUBLE_FLOAT"
|
"TARGET_HARD_FLOAT && TARGET_DOUBLE_FLOAT"
|
{
|
{
|
rtx reg1 = gen_reg_rtx (DFmode);
|
rtx reg1 = gen_reg_rtx (DFmode);
|
rtx reg2 = gen_reg_rtx (DFmode);
|
rtx reg2 = gen_reg_rtx (DFmode);
|
rtx reg3 = gen_reg_rtx (SImode);
|
rtx reg3 = gen_reg_rtx (SImode);
|
rtx label1 = gen_label_rtx ();
|
rtx label1 = gen_label_rtx ();
|
rtx label2 = gen_label_rtx ();
|
rtx label2 = gen_label_rtx ();
|
rtx test;
|
rtx test;
|
REAL_VALUE_TYPE offset;
|
REAL_VALUE_TYPE offset;
|
|
|
real_2expN (&offset, 31, DFmode);
|
real_2expN (&offset, 31, DFmode);
|
|
|
if (reg1) /* Turn off complaints about unreached code. */
|
if (reg1) /* Turn off complaints about unreached code. */
|
{
|
{
|
mips_emit_move (reg1, CONST_DOUBLE_FROM_REAL_VALUE (offset, DFmode));
|
mips_emit_move (reg1, CONST_DOUBLE_FROM_REAL_VALUE (offset, DFmode));
|
do_pending_stack_adjust ();
|
do_pending_stack_adjust ();
|
|
|
test = gen_rtx_GE (VOIDmode, operands[1], reg1);
|
test = gen_rtx_GE (VOIDmode, operands[1], reg1);
|
emit_jump_insn (gen_cbranchdf4 (test, operands[1], reg1, label1));
|
emit_jump_insn (gen_cbranchdf4 (test, operands[1], reg1, label1));
|
|
|
emit_insn (gen_fix_truncdfsi2 (operands[0], operands[1]));
|
emit_insn (gen_fix_truncdfsi2 (operands[0], operands[1]));
|
emit_jump_insn (gen_rtx_SET (VOIDmode, pc_rtx,
|
emit_jump_insn (gen_rtx_SET (VOIDmode, pc_rtx,
|
gen_rtx_LABEL_REF (VOIDmode, label2)));
|
gen_rtx_LABEL_REF (VOIDmode, label2)));
|
emit_barrier ();
|
emit_barrier ();
|
|
|
emit_label (label1);
|
emit_label (label1);
|
mips_emit_move (reg2, gen_rtx_MINUS (DFmode, operands[1], reg1));
|
mips_emit_move (reg2, gen_rtx_MINUS (DFmode, operands[1], reg1));
|
mips_emit_move (reg3, GEN_INT (trunc_int_for_mode
|
mips_emit_move (reg3, GEN_INT (trunc_int_for_mode
|
(BITMASK_HIGH, SImode)));
|
(BITMASK_HIGH, SImode)));
|
|
|
emit_insn (gen_fix_truncdfsi2 (operands[0], reg2));
|
emit_insn (gen_fix_truncdfsi2 (operands[0], reg2));
|
emit_insn (gen_iorsi3 (operands[0], operands[0], reg3));
|
emit_insn (gen_iorsi3 (operands[0], operands[0], reg3));
|
|
|
emit_label (label2);
|
emit_label (label2);
|
|
|
/* Allow REG_NOTES to be set on last insn (labels don't have enough
|
/* Allow REG_NOTES to be set on last insn (labels don't have enough
|
fields, and can't be used for REG_NOTES anyway). */
|
fields, and can't be used for REG_NOTES anyway). */
|
emit_use (stack_pointer_rtx);
|
emit_use (stack_pointer_rtx);
|
DONE;
|
DONE;
|
}
|
}
|
})
|
})
|
|
|
|
|
(define_expand "fixuns_truncdfdi2"
|
(define_expand "fixuns_truncdfdi2"
|
[(set (match_operand:DI 0 "register_operand")
|
[(set (match_operand:DI 0 "register_operand")
|
(unsigned_fix:DI (match_operand:DF 1 "register_operand")))]
|
(unsigned_fix:DI (match_operand:DF 1 "register_operand")))]
|
"TARGET_HARD_FLOAT && TARGET_64BIT && TARGET_DOUBLE_FLOAT"
|
"TARGET_HARD_FLOAT && TARGET_64BIT && TARGET_DOUBLE_FLOAT"
|
{
|
{
|
rtx reg1 = gen_reg_rtx (DFmode);
|
rtx reg1 = gen_reg_rtx (DFmode);
|
rtx reg2 = gen_reg_rtx (DFmode);
|
rtx reg2 = gen_reg_rtx (DFmode);
|
rtx reg3 = gen_reg_rtx (DImode);
|
rtx reg3 = gen_reg_rtx (DImode);
|
rtx label1 = gen_label_rtx ();
|
rtx label1 = gen_label_rtx ();
|
rtx label2 = gen_label_rtx ();
|
rtx label2 = gen_label_rtx ();
|
rtx test;
|
rtx test;
|
REAL_VALUE_TYPE offset;
|
REAL_VALUE_TYPE offset;
|
|
|
real_2expN (&offset, 63, DFmode);
|
real_2expN (&offset, 63, DFmode);
|
|
|
mips_emit_move (reg1, CONST_DOUBLE_FROM_REAL_VALUE (offset, DFmode));
|
mips_emit_move (reg1, CONST_DOUBLE_FROM_REAL_VALUE (offset, DFmode));
|
do_pending_stack_adjust ();
|
do_pending_stack_adjust ();
|
|
|
test = gen_rtx_GE (VOIDmode, operands[1], reg1);
|
test = gen_rtx_GE (VOIDmode, operands[1], reg1);
|
emit_jump_insn (gen_cbranchdf4 (test, operands[1], reg1, label1));
|
emit_jump_insn (gen_cbranchdf4 (test, operands[1], reg1, label1));
|
|
|
emit_insn (gen_fix_truncdfdi2 (operands[0], operands[1]));
|
emit_insn (gen_fix_truncdfdi2 (operands[0], operands[1]));
|
emit_jump_insn (gen_rtx_SET (VOIDmode, pc_rtx,
|
emit_jump_insn (gen_rtx_SET (VOIDmode, pc_rtx,
|
gen_rtx_LABEL_REF (VOIDmode, label2)));
|
gen_rtx_LABEL_REF (VOIDmode, label2)));
|
emit_barrier ();
|
emit_barrier ();
|
|
|
emit_label (label1);
|
emit_label (label1);
|
mips_emit_move (reg2, gen_rtx_MINUS (DFmode, operands[1], reg1));
|
mips_emit_move (reg2, gen_rtx_MINUS (DFmode, operands[1], reg1));
|
mips_emit_move (reg3, GEN_INT (BITMASK_HIGH));
|
mips_emit_move (reg3, GEN_INT (BITMASK_HIGH));
|
emit_insn (gen_ashldi3 (reg3, reg3, GEN_INT (32)));
|
emit_insn (gen_ashldi3 (reg3, reg3, GEN_INT (32)));
|
|
|
emit_insn (gen_fix_truncdfdi2 (operands[0], reg2));
|
emit_insn (gen_fix_truncdfdi2 (operands[0], reg2));
|
emit_insn (gen_iordi3 (operands[0], operands[0], reg3));
|
emit_insn (gen_iordi3 (operands[0], operands[0], reg3));
|
|
|
emit_label (label2);
|
emit_label (label2);
|
|
|
/* Allow REG_NOTES to be set on last insn (labels don't have enough
|
/* Allow REG_NOTES to be set on last insn (labels don't have enough
|
fields, and can't be used for REG_NOTES anyway). */
|
fields, and can't be used for REG_NOTES anyway). */
|
emit_use (stack_pointer_rtx);
|
emit_use (stack_pointer_rtx);
|
DONE;
|
DONE;
|
})
|
})
|
|
|
|
|
(define_expand "fixuns_truncsfsi2"
|
(define_expand "fixuns_truncsfsi2"
|
[(set (match_operand:SI 0 "register_operand")
|
[(set (match_operand:SI 0 "register_operand")
|
(unsigned_fix:SI (match_operand:SF 1 "register_operand")))]
|
(unsigned_fix:SI (match_operand:SF 1 "register_operand")))]
|
"TARGET_HARD_FLOAT"
|
"TARGET_HARD_FLOAT"
|
{
|
{
|
rtx reg1 = gen_reg_rtx (SFmode);
|
rtx reg1 = gen_reg_rtx (SFmode);
|
rtx reg2 = gen_reg_rtx (SFmode);
|
rtx reg2 = gen_reg_rtx (SFmode);
|
rtx reg3 = gen_reg_rtx (SImode);
|
rtx reg3 = gen_reg_rtx (SImode);
|
rtx label1 = gen_label_rtx ();
|
rtx label1 = gen_label_rtx ();
|
rtx label2 = gen_label_rtx ();
|
rtx label2 = gen_label_rtx ();
|
rtx test;
|
rtx test;
|
REAL_VALUE_TYPE offset;
|
REAL_VALUE_TYPE offset;
|
|
|
real_2expN (&offset, 31, SFmode);
|
real_2expN (&offset, 31, SFmode);
|
|
|
mips_emit_move (reg1, CONST_DOUBLE_FROM_REAL_VALUE (offset, SFmode));
|
mips_emit_move (reg1, CONST_DOUBLE_FROM_REAL_VALUE (offset, SFmode));
|
do_pending_stack_adjust ();
|
do_pending_stack_adjust ();
|
|
|
test = gen_rtx_GE (VOIDmode, operands[1], reg1);
|
test = gen_rtx_GE (VOIDmode, operands[1], reg1);
|
emit_jump_insn (gen_cbranchsf4 (test, operands[1], reg1, label1));
|
emit_jump_insn (gen_cbranchsf4 (test, operands[1], reg1, label1));
|
|
|
emit_insn (gen_fix_truncsfsi2 (operands[0], operands[1]));
|
emit_insn (gen_fix_truncsfsi2 (operands[0], operands[1]));
|
emit_jump_insn (gen_rtx_SET (VOIDmode, pc_rtx,
|
emit_jump_insn (gen_rtx_SET (VOIDmode, pc_rtx,
|
gen_rtx_LABEL_REF (VOIDmode, label2)));
|
gen_rtx_LABEL_REF (VOIDmode, label2)));
|
emit_barrier ();
|
emit_barrier ();
|
|
|
emit_label (label1);
|
emit_label (label1);
|
mips_emit_move (reg2, gen_rtx_MINUS (SFmode, operands[1], reg1));
|
mips_emit_move (reg2, gen_rtx_MINUS (SFmode, operands[1], reg1));
|
mips_emit_move (reg3, GEN_INT (trunc_int_for_mode
|
mips_emit_move (reg3, GEN_INT (trunc_int_for_mode
|
(BITMASK_HIGH, SImode)));
|
(BITMASK_HIGH, SImode)));
|
|
|
emit_insn (gen_fix_truncsfsi2 (operands[0], reg2));
|
emit_insn (gen_fix_truncsfsi2 (operands[0], reg2));
|
emit_insn (gen_iorsi3 (operands[0], operands[0], reg3));
|
emit_insn (gen_iorsi3 (operands[0], operands[0], reg3));
|
|
|
emit_label (label2);
|
emit_label (label2);
|
|
|
/* Allow REG_NOTES to be set on last insn (labels don't have enough
|
/* Allow REG_NOTES to be set on last insn (labels don't have enough
|
fields, and can't be used for REG_NOTES anyway). */
|
fields, and can't be used for REG_NOTES anyway). */
|
emit_use (stack_pointer_rtx);
|
emit_use (stack_pointer_rtx);
|
DONE;
|
DONE;
|
})
|
})
|
|
|
|
|
(define_expand "fixuns_truncsfdi2"
|
(define_expand "fixuns_truncsfdi2"
|
[(set (match_operand:DI 0 "register_operand")
|
[(set (match_operand:DI 0 "register_operand")
|
(unsigned_fix:DI (match_operand:SF 1 "register_operand")))]
|
(unsigned_fix:DI (match_operand:SF 1 "register_operand")))]
|
"TARGET_HARD_FLOAT && TARGET_64BIT && TARGET_DOUBLE_FLOAT"
|
"TARGET_HARD_FLOAT && TARGET_64BIT && TARGET_DOUBLE_FLOAT"
|
{
|
{
|
rtx reg1 = gen_reg_rtx (SFmode);
|
rtx reg1 = gen_reg_rtx (SFmode);
|
rtx reg2 = gen_reg_rtx (SFmode);
|
rtx reg2 = gen_reg_rtx (SFmode);
|
rtx reg3 = gen_reg_rtx (DImode);
|
rtx reg3 = gen_reg_rtx (DImode);
|
rtx label1 = gen_label_rtx ();
|
rtx label1 = gen_label_rtx ();
|
rtx label2 = gen_label_rtx ();
|
rtx label2 = gen_label_rtx ();
|
rtx test;
|
rtx test;
|
REAL_VALUE_TYPE offset;
|
REAL_VALUE_TYPE offset;
|
|
|
real_2expN (&offset, 63, SFmode);
|
real_2expN (&offset, 63, SFmode);
|
|
|
mips_emit_move (reg1, CONST_DOUBLE_FROM_REAL_VALUE (offset, SFmode));
|
mips_emit_move (reg1, CONST_DOUBLE_FROM_REAL_VALUE (offset, SFmode));
|
do_pending_stack_adjust ();
|
do_pending_stack_adjust ();
|
|
|
test = gen_rtx_GE (VOIDmode, operands[1], reg1);
|
test = gen_rtx_GE (VOIDmode, operands[1], reg1);
|
emit_jump_insn (gen_cbranchsf4 (test, operands[1], reg1, label1));
|
emit_jump_insn (gen_cbranchsf4 (test, operands[1], reg1, label1));
|
|
|
emit_insn (gen_fix_truncsfdi2 (operands[0], operands[1]));
|
emit_insn (gen_fix_truncsfdi2 (operands[0], operands[1]));
|
emit_jump_insn (gen_rtx_SET (VOIDmode, pc_rtx,
|
emit_jump_insn (gen_rtx_SET (VOIDmode, pc_rtx,
|
gen_rtx_LABEL_REF (VOIDmode, label2)));
|
gen_rtx_LABEL_REF (VOIDmode, label2)));
|
emit_barrier ();
|
emit_barrier ();
|
|
|
emit_label (label1);
|
emit_label (label1);
|
mips_emit_move (reg2, gen_rtx_MINUS (SFmode, operands[1], reg1));
|
mips_emit_move (reg2, gen_rtx_MINUS (SFmode, operands[1], reg1));
|
mips_emit_move (reg3, GEN_INT (BITMASK_HIGH));
|
mips_emit_move (reg3, GEN_INT (BITMASK_HIGH));
|
emit_insn (gen_ashldi3 (reg3, reg3, GEN_INT (32)));
|
emit_insn (gen_ashldi3 (reg3, reg3, GEN_INT (32)));
|
|
|
emit_insn (gen_fix_truncsfdi2 (operands[0], reg2));
|
emit_insn (gen_fix_truncsfdi2 (operands[0], reg2));
|
emit_insn (gen_iordi3 (operands[0], operands[0], reg3));
|
emit_insn (gen_iordi3 (operands[0], operands[0], reg3));
|
|
|
emit_label (label2);
|
emit_label (label2);
|
|
|
/* Allow REG_NOTES to be set on last insn (labels don't have enough
|
/* Allow REG_NOTES to be set on last insn (labels don't have enough
|
fields, and can't be used for REG_NOTES anyway). */
|
fields, and can't be used for REG_NOTES anyway). */
|
emit_use (stack_pointer_rtx);
|
emit_use (stack_pointer_rtx);
|
DONE;
|
DONE;
|
})
|
})
|
|
|
;;
|
;;
|
;; ....................
|
;; ....................
|
;;
|
;;
|
;; DATA MOVEMENT
|
;; DATA MOVEMENT
|
;;
|
;;
|
;; ....................
|
;; ....................
|
|
|
;; Bit field extract patterns which use lwl/lwr or ldl/ldr.
|
;; Bit field extract patterns which use lwl/lwr or ldl/ldr.
|
|
|
(define_expand "extv"
|
(define_expand "extv"
|
[(set (match_operand 0 "register_operand")
|
[(set (match_operand 0 "register_operand")
|
(sign_extract (match_operand 1 "nonimmediate_operand")
|
(sign_extract (match_operand 1 "nonimmediate_operand")
|
(match_operand 2 "const_int_operand")
|
(match_operand 2 "const_int_operand")
|
(match_operand 3 "const_int_operand")))]
|
(match_operand 3 "const_int_operand")))]
|
"!TARGET_MIPS16"
|
"!TARGET_MIPS16"
|
{
|
{
|
if (mips_expand_ext_as_unaligned_load (operands[0], operands[1],
|
if (mips_expand_ext_as_unaligned_load (operands[0], operands[1],
|
INTVAL (operands[2]),
|
INTVAL (operands[2]),
|
INTVAL (operands[3])))
|
INTVAL (operands[3])))
|
DONE;
|
DONE;
|
else if (register_operand (operands[1], GET_MODE (operands[0]))
|
else if (register_operand (operands[1], GET_MODE (operands[0]))
|
&& ISA_HAS_EXTS && UINTVAL (operands[2]) <= 32)
|
&& ISA_HAS_EXTS && UINTVAL (operands[2]) <= 32)
|
{
|
{
|
if (GET_MODE (operands[0]) == DImode)
|
if (GET_MODE (operands[0]) == DImode)
|
emit_insn (gen_extvdi (operands[0], operands[1], operands[2],
|
emit_insn (gen_extvdi (operands[0], operands[1], operands[2],
|
operands[3]));
|
operands[3]));
|
else
|
else
|
emit_insn (gen_extvsi (operands[0], operands[1], operands[2],
|
emit_insn (gen_extvsi (operands[0], operands[1], operands[2],
|
operands[3]));
|
operands[3]));
|
DONE;
|
DONE;
|
}
|
}
|
else
|
else
|
FAIL;
|
FAIL;
|
})
|
})
|
|
|
(define_insn "extv"
|
(define_insn "extv"
|
[(set (match_operand:GPR 0 "register_operand" "=d")
|
[(set (match_operand:GPR 0 "register_operand" "=d")
|
(sign_extract:GPR (match_operand:GPR 1 "register_operand" "d")
|
(sign_extract:GPR (match_operand:GPR 1 "register_operand" "d")
|
(match_operand 2 "const_int_operand" "")
|
(match_operand 2 "const_int_operand" "")
|
(match_operand 3 "const_int_operand" "")))]
|
(match_operand 3 "const_int_operand" "")))]
|
"ISA_HAS_EXTS && UINTVAL (operands[2]) <= 32"
|
"ISA_HAS_EXTS && UINTVAL (operands[2]) <= 32"
|
"exts\t%0,%1,%3,%m2"
|
"exts\t%0,%1,%3,%m2"
|
[(set_attr "type" "arith")
|
[(set_attr "type" "arith")
|
(set_attr "mode" "")])
|
(set_attr "mode" "")])
|
|
|
|
|
(define_expand "extzv"
|
(define_expand "extzv"
|
[(set (match_operand 0 "register_operand")
|
[(set (match_operand 0 "register_operand")
|
(zero_extract (match_operand 1 "nonimmediate_operand")
|
(zero_extract (match_operand 1 "nonimmediate_operand")
|
(match_operand 2 "const_int_operand")
|
(match_operand 2 "const_int_operand")
|
(match_operand 3 "const_int_operand")))]
|
(match_operand 3 "const_int_operand")))]
|
"!TARGET_MIPS16"
|
"!TARGET_MIPS16"
|
{
|
{
|
if (mips_expand_ext_as_unaligned_load (operands[0], operands[1],
|
if (mips_expand_ext_as_unaligned_load (operands[0], operands[1],
|
INTVAL (operands[2]),
|
INTVAL (operands[2]),
|
INTVAL (operands[3])))
|
INTVAL (operands[3])))
|
DONE;
|
DONE;
|
else if (mips_use_ins_ext_p (operands[1], INTVAL (operands[2]),
|
else if (mips_use_ins_ext_p (operands[1], INTVAL (operands[2]),
|
INTVAL (operands[3])))
|
INTVAL (operands[3])))
|
{
|
{
|
if (GET_MODE (operands[0]) == DImode)
|
if (GET_MODE (operands[0]) == DImode)
|
emit_insn (gen_extzvdi (operands[0], operands[1], operands[2],
|
emit_insn (gen_extzvdi (operands[0], operands[1], operands[2],
|
operands[3]));
|
operands[3]));
|
else
|
else
|
emit_insn (gen_extzvsi (operands[0], operands[1], operands[2],
|
emit_insn (gen_extzvsi (operands[0], operands[1], operands[2],
|
operands[3]));
|
operands[3]));
|
DONE;
|
DONE;
|
}
|
}
|
else
|
else
|
FAIL;
|
FAIL;
|
})
|
})
|
|
|
(define_insn "extzv"
|
(define_insn "extzv"
|
[(set (match_operand:GPR 0 "register_operand" "=d")
|
[(set (match_operand:GPR 0 "register_operand" "=d")
|
(zero_extract:GPR (match_operand:GPR 1 "register_operand" "d")
|
(zero_extract:GPR (match_operand:GPR 1 "register_operand" "d")
|
(match_operand 2 "const_int_operand" "")
|
(match_operand 2 "const_int_operand" "")
|
(match_operand 3 "const_int_operand" "")))]
|
(match_operand 3 "const_int_operand" "")))]
|
"mips_use_ins_ext_p (operands[1], INTVAL (operands[2]),
|
"mips_use_ins_ext_p (operands[1], INTVAL (operands[2]),
|
INTVAL (operands[3]))"
|
INTVAL (operands[3]))"
|
"ext\t%0,%1,%3,%2"
|
"ext\t%0,%1,%3,%2"
|
[(set_attr "type" "arith")
|
[(set_attr "type" "arith")
|
(set_attr "mode" "")])
|
(set_attr "mode" "")])
|
|
|
(define_insn "*extzv_truncsi_exts"
|
(define_insn "*extzv_truncsi_exts"
|
[(set (match_operand:SI 0 "register_operand" "=d")
|
[(set (match_operand:SI 0 "register_operand" "=d")
|
(truncate:SI
|
(truncate:SI
|
(zero_extract:DI (match_operand:DI 1 "register_operand" "d")
|
(zero_extract:DI (match_operand:DI 1 "register_operand" "d")
|
(match_operand 2 "const_int_operand" "")
|
(match_operand 2 "const_int_operand" "")
|
(match_operand 3 "const_int_operand" ""))))]
|
(match_operand 3 "const_int_operand" ""))))]
|
"ISA_HAS_EXTS && TARGET_64BIT && IN_RANGE (INTVAL (operands[2]), 32, 63)"
|
"ISA_HAS_EXTS && TARGET_64BIT && IN_RANGE (INTVAL (operands[2]), 32, 63)"
|
"exts\t%0,%1,%3,31"
|
"exts\t%0,%1,%3,31"
|
[(set_attr "type" "arith")
|
[(set_attr "type" "arith")
|
(set_attr "mode" "SI")])
|
(set_attr "mode" "SI")])
|
|
|
|
|
(define_expand "insv"
|
(define_expand "insv"
|
[(set (zero_extract (match_operand 0 "nonimmediate_operand")
|
[(set (zero_extract (match_operand 0 "nonimmediate_operand")
|
(match_operand 1 "immediate_operand")
|
(match_operand 1 "immediate_operand")
|
(match_operand 2 "immediate_operand"))
|
(match_operand 2 "immediate_operand"))
|
(match_operand 3 "reg_or_0_operand"))]
|
(match_operand 3 "reg_or_0_operand"))]
|
"!TARGET_MIPS16"
|
"!TARGET_MIPS16"
|
{
|
{
|
if (mips_expand_ins_as_unaligned_store (operands[0], operands[3],
|
if (mips_expand_ins_as_unaligned_store (operands[0], operands[3],
|
INTVAL (operands[1]),
|
INTVAL (operands[1]),
|
INTVAL (operands[2])))
|
INTVAL (operands[2])))
|
DONE;
|
DONE;
|
else if (mips_use_ins_ext_p (operands[0], INTVAL (operands[1]),
|
else if (mips_use_ins_ext_p (operands[0], INTVAL (operands[1]),
|
INTVAL (operands[2])))
|
INTVAL (operands[2])))
|
{
|
{
|
if (GET_MODE (operands[0]) == DImode)
|
if (GET_MODE (operands[0]) == DImode)
|
emit_insn (gen_insvdi (operands[0], operands[1], operands[2],
|
emit_insn (gen_insvdi (operands[0], operands[1], operands[2],
|
operands[3]));
|
operands[3]));
|
else
|
else
|
emit_insn (gen_insvsi (operands[0], operands[1], operands[2],
|
emit_insn (gen_insvsi (operands[0], operands[1], operands[2],
|
operands[3]));
|
operands[3]));
|
DONE;
|
DONE;
|
}
|
}
|
else
|
else
|
FAIL;
|
FAIL;
|
})
|
})
|
|
|
(define_insn "insv"
|
(define_insn "insv"
|
[(set (zero_extract:GPR (match_operand:GPR 0 "register_operand" "+d")
|
[(set (zero_extract:GPR (match_operand:GPR 0 "register_operand" "+d")
|
(match_operand:SI 1 "immediate_operand" "I")
|
(match_operand:SI 1 "immediate_operand" "I")
|
(match_operand:SI 2 "immediate_operand" "I"))
|
(match_operand:SI 2 "immediate_operand" "I"))
|
(match_operand:GPR 3 "reg_or_0_operand" "dJ"))]
|
(match_operand:GPR 3 "reg_or_0_operand" "dJ"))]
|
"mips_use_ins_ext_p (operands[0], INTVAL (operands[1]),
|
"mips_use_ins_ext_p (operands[0], INTVAL (operands[1]),
|
INTVAL (operands[2]))"
|
INTVAL (operands[2]))"
|
"ins\t%0,%z3,%2,%1"
|
"ins\t%0,%z3,%2,%1"
|
[(set_attr "type" "arith")
|
[(set_attr "type" "arith")
|
(set_attr "mode" "")])
|
(set_attr "mode" "")])
|
|
|
;; Combiner pattern for cins (clear and insert bit field). We can
|
;; Combiner pattern for cins (clear and insert bit field). We can
|
;; implement mask-and-shift-left operation with this. Note that if
|
;; implement mask-and-shift-left operation with this. Note that if
|
;; the upper bit of the mask is set in an SImode operation, the mask
|
;; the upper bit of the mask is set in an SImode operation, the mask
|
;; itself will be sign-extended. mask_low_and_shift_len will
|
;; itself will be sign-extended. mask_low_and_shift_len will
|
;; therefore be greater than our threshold of 32.
|
;; therefore be greater than our threshold of 32.
|
|
|
(define_insn "*cins"
|
(define_insn "*cins"
|
[(set (match_operand:GPR 0 "register_operand" "=d")
|
[(set (match_operand:GPR 0 "register_operand" "=d")
|
(and:GPR
|
(and:GPR
|
(ashift:GPR (match_operand:GPR 1 "register_operand" "d")
|
(ashift:GPR (match_operand:GPR 1 "register_operand" "d")
|
(match_operand:GPR 2 "const_int_operand" ""))
|
(match_operand:GPR 2 "const_int_operand" ""))
|
(match_operand:GPR 3 "const_int_operand" "")))]
|
(match_operand:GPR 3 "const_int_operand" "")))]
|
"ISA_HAS_CINS
|
"ISA_HAS_CINS
|
&& mask_low_and_shift_p (mode, operands[3], operands[2], 32)"
|
&& mask_low_and_shift_p (mode, operands[3], operands[2], 32)"
|
{
|
{
|
operands[3] =
|
operands[3] =
|
GEN_INT (mask_low_and_shift_len (mode, operands[3], operands[2]));
|
GEN_INT (mask_low_and_shift_len (mode, operands[3], operands[2]));
|
return "cins\t%0,%1,%2,%m3";
|
return "cins\t%0,%1,%2,%m3";
|
}
|
}
|
[(set_attr "type" "shift")
|
[(set_attr "type" "shift")
|
(set_attr "mode" "")])
|
(set_attr "mode" "")])
|
|
|
;; Unaligned word moves generated by the bit field patterns.
|
;; Unaligned word moves generated by the bit field patterns.
|
;;
|
;;
|
;; As far as the rtl is concerned, both the left-part and right-part
|
;; As far as the rtl is concerned, both the left-part and right-part
|
;; instructions can access the whole field. However, the real operand
|
;; instructions can access the whole field. However, the real operand
|
;; refers to just the first or the last byte (depending on endianness).
|
;; refers to just the first or the last byte (depending on endianness).
|
;; We therefore use two memory operands to each instruction, one to
|
;; We therefore use two memory operands to each instruction, one to
|
;; describe the rtl effect and one to use in the assembly output.
|
;; describe the rtl effect and one to use in the assembly output.
|
;;
|
;;
|
;; Operands 0 and 1 are the rtl-level target and source respectively.
|
;; Operands 0 and 1 are the rtl-level target and source respectively.
|
;; This allows us to use the standard length calculations for the "load"
|
;; This allows us to use the standard length calculations for the "load"
|
;; and "store" type attributes.
|
;; and "store" type attributes.
|
|
|
(define_insn "mov_l"
|
(define_insn "mov_l"
|
[(set (match_operand:GPR 0 "register_operand" "=d")
|
[(set (match_operand:GPR 0 "register_operand" "=d")
|
(unspec:GPR [(match_operand:BLK 1 "memory_operand" "m")
|
(unspec:GPR [(match_operand:BLK 1 "memory_operand" "m")
|
(match_operand:QI 2 "memory_operand" "m")]
|
(match_operand:QI 2 "memory_operand" "m")]
|
UNSPEC_LOAD_LEFT))]
|
UNSPEC_LOAD_LEFT))]
|
"!TARGET_MIPS16 && mips_mem_fits_mode_p (mode, operands[1])"
|
"!TARGET_MIPS16 && mips_mem_fits_mode_p (mode, operands[1])"
|
"l\t%0,%2"
|
"l\t%0,%2"
|
[(set_attr "move_type" "load")
|
[(set_attr "move_type" "load")
|
(set_attr "mode" "")])
|
(set_attr "mode" "")])
|
|
|
(define_insn "mov_r"
|
(define_insn "mov_r"
|
[(set (match_operand:GPR 0 "register_operand" "=d")
|
[(set (match_operand:GPR 0 "register_operand" "=d")
|
(unspec:GPR [(match_operand:BLK 1 "memory_operand" "m")
|
(unspec:GPR [(match_operand:BLK 1 "memory_operand" "m")
|
(match_operand:QI 2 "memory_operand" "m")
|
(match_operand:QI 2 "memory_operand" "m")
|
(match_operand:GPR 3 "register_operand" "0")]
|
(match_operand:GPR 3 "register_operand" "0")]
|
UNSPEC_LOAD_RIGHT))]
|
UNSPEC_LOAD_RIGHT))]
|
"!TARGET_MIPS16 && mips_mem_fits_mode_p (mode, operands[1])"
|
"!TARGET_MIPS16 && mips_mem_fits_mode_p (mode, operands[1])"
|
"r\t%0,%2"
|
"r\t%0,%2"
|
[(set_attr "move_type" "load")
|
[(set_attr "move_type" "load")
|
(set_attr "mode" "")])
|
(set_attr "mode" "")])
|
|
|
(define_insn "mov_l"
|
(define_insn "mov_l"
|
[(set (match_operand:BLK 0 "memory_operand" "=m")
|
[(set (match_operand:BLK 0 "memory_operand" "=m")
|
(unspec:BLK [(match_operand:GPR 1 "reg_or_0_operand" "dJ")
|
(unspec:BLK [(match_operand:GPR 1 "reg_or_0_operand" "dJ")
|
(match_operand:QI 2 "memory_operand" "m")]
|
(match_operand:QI 2 "memory_operand" "m")]
|
UNSPEC_STORE_LEFT))]
|
UNSPEC_STORE_LEFT))]
|
"!TARGET_MIPS16 && mips_mem_fits_mode_p (mode, operands[0])"
|
"!TARGET_MIPS16 && mips_mem_fits_mode_p (mode, operands[0])"
|
"l\t%z1,%2"
|
"l\t%z1,%2"
|
[(set_attr "move_type" "store")
|
[(set_attr "move_type" "store")
|
(set_attr "mode" "")])
|
(set_attr "mode" "")])
|
|
|
(define_insn "mov_r"
|
(define_insn "mov_r"
|
[(set (match_operand:BLK 0 "memory_operand" "+m")
|
[(set (match_operand:BLK 0 "memory_operand" "+m")
|
(unspec:BLK [(match_operand:GPR 1 "reg_or_0_operand" "dJ")
|
(unspec:BLK [(match_operand:GPR 1 "reg_or_0_operand" "dJ")
|
(match_operand:QI 2 "memory_operand" "m")
|
(match_operand:QI 2 "memory_operand" "m")
|
(match_dup 0)]
|
(match_dup 0)]
|
UNSPEC_STORE_RIGHT))]
|
UNSPEC_STORE_RIGHT))]
|
"!TARGET_MIPS16 && mips_mem_fits_mode_p (mode, operands[0])"
|
"!TARGET_MIPS16 && mips_mem_fits_mode_p (mode, operands[0])"
|
"r\t%z1,%2"
|
"r\t%z1,%2"
|
[(set_attr "move_type" "store")
|
[(set_attr "move_type" "store")
|
(set_attr "mode" "")])
|
(set_attr "mode" "")])
|
|
|
;; An instruction to calculate the high part of a 64-bit SYMBOL_ABSOLUTE.
|
;; An instruction to calculate the high part of a 64-bit SYMBOL_ABSOLUTE.
|
;; The required value is:
|
;; The required value is:
|
;;
|
;;
|
;; (%highest(op1) << 48) + (%higher(op1) << 32) + (%hi(op1) << 16)
|
;; (%highest(op1) << 48) + (%higher(op1) << 32) + (%hi(op1) << 16)
|
;;
|
;;
|
;; which translates to:
|
;; which translates to:
|
;;
|
;;
|
;; lui op0,%highest(op1)
|
;; lui op0,%highest(op1)
|
;; daddiu op0,op0,%higher(op1)
|
;; daddiu op0,op0,%higher(op1)
|
;; dsll op0,op0,16
|
;; dsll op0,op0,16
|
;; daddiu op0,op0,%hi(op1)
|
;; daddiu op0,op0,%hi(op1)
|
;; dsll op0,op0,16
|
;; dsll op0,op0,16
|
;;
|
;;
|
;; The split is deferred until after flow2 to allow the peephole2 below
|
;; The split is deferred until after flow2 to allow the peephole2 below
|
;; to take effect.
|
;; to take effect.
|
(define_insn_and_split "*lea_high64"
|
(define_insn_and_split "*lea_high64"
|
[(set (match_operand:DI 0 "register_operand" "=d")
|
[(set (match_operand:DI 0 "register_operand" "=d")
|
(high:DI (match_operand:DI 1 "absolute_symbolic_operand" "")))]
|
(high:DI (match_operand:DI 1 "absolute_symbolic_operand" "")))]
|
"TARGET_EXPLICIT_RELOCS && ABI_HAS_64BIT_SYMBOLS"
|
"TARGET_EXPLICIT_RELOCS && ABI_HAS_64BIT_SYMBOLS"
|
"#"
|
"#"
|
"&& epilogue_completed"
|
"&& epilogue_completed"
|
[(set (match_dup 0) (high:DI (match_dup 2)))
|
[(set (match_dup 0) (high:DI (match_dup 2)))
|
(set (match_dup 0) (lo_sum:DI (match_dup 0) (match_dup 2)))
|
(set (match_dup 0) (lo_sum:DI (match_dup 0) (match_dup 2)))
|
(set (match_dup 0) (ashift:DI (match_dup 0) (const_int 16)))
|
(set (match_dup 0) (ashift:DI (match_dup 0) (const_int 16)))
|
(set (match_dup 0) (lo_sum:DI (match_dup 0) (match_dup 3)))
|
(set (match_dup 0) (lo_sum:DI (match_dup 0) (match_dup 3)))
|
(set (match_dup 0) (ashift:DI (match_dup 0) (const_int 16)))]
|
(set (match_dup 0) (ashift:DI (match_dup 0) (const_int 16)))]
|
{
|
{
|
operands[2] = mips_unspec_address (operands[1], SYMBOL_64_HIGH);
|
operands[2] = mips_unspec_address (operands[1], SYMBOL_64_HIGH);
|
operands[3] = mips_unspec_address (operands[1], SYMBOL_64_MID);
|
operands[3] = mips_unspec_address (operands[1], SYMBOL_64_MID);
|
}
|
}
|
[(set_attr "length" "20")])
|
[(set_attr "length" "20")])
|
|
|
;; Use a scratch register to reduce the latency of the above pattern
|
;; Use a scratch register to reduce the latency of the above pattern
|
;; on superscalar machines. The optimized sequence is:
|
;; on superscalar machines. The optimized sequence is:
|
;;
|
;;
|
;; lui op1,%highest(op2)
|
;; lui op1,%highest(op2)
|
;; lui op0,%hi(op2)
|
;; lui op0,%hi(op2)
|
;; daddiu op1,op1,%higher(op2)
|
;; daddiu op1,op1,%higher(op2)
|
;; dsll32 op1,op1,0
|
;; dsll32 op1,op1,0
|
;; daddu op1,op1,op0
|
;; daddu op1,op1,op0
|
(define_peephole2
|
(define_peephole2
|
[(set (match_operand:DI 1 "d_operand")
|
[(set (match_operand:DI 1 "d_operand")
|
(high:DI (match_operand:DI 2 "absolute_symbolic_operand")))
|
(high:DI (match_operand:DI 2 "absolute_symbolic_operand")))
|
(match_scratch:DI 0 "d")]
|
(match_scratch:DI 0 "d")]
|
"TARGET_EXPLICIT_RELOCS && ABI_HAS_64BIT_SYMBOLS"
|
"TARGET_EXPLICIT_RELOCS && ABI_HAS_64BIT_SYMBOLS"
|
[(set (match_dup 1) (high:DI (match_dup 3)))
|
[(set (match_dup 1) (high:DI (match_dup 3)))
|
(set (match_dup 0) (high:DI (match_dup 4)))
|
(set (match_dup 0) (high:DI (match_dup 4)))
|
(set (match_dup 1) (lo_sum:DI (match_dup 1) (match_dup 3)))
|
(set (match_dup 1) (lo_sum:DI (match_dup 1) (match_dup 3)))
|
(set (match_dup 1) (ashift:DI (match_dup 1) (const_int 32)))
|
(set (match_dup 1) (ashift:DI (match_dup 1) (const_int 32)))
|
(set (match_dup 1) (plus:DI (match_dup 1) (match_dup 0)))]
|
(set (match_dup 1) (plus:DI (match_dup 1) (match_dup 0)))]
|
{
|
{
|
operands[3] = mips_unspec_address (operands[2], SYMBOL_64_HIGH);
|
operands[3] = mips_unspec_address (operands[2], SYMBOL_64_HIGH);
|
operands[4] = mips_unspec_address (operands[2], SYMBOL_64_LOW);
|
operands[4] = mips_unspec_address (operands[2], SYMBOL_64_LOW);
|
})
|
})
|
|
|
;; On most targets, the expansion of (lo_sum (high X) X) for a 64-bit
|
;; On most targets, the expansion of (lo_sum (high X) X) for a 64-bit
|
;; SYMBOL_ABSOLUTE X will take 6 cycles. This next pattern allows combine
|
;; SYMBOL_ABSOLUTE X will take 6 cycles. This next pattern allows combine
|
;; to merge the HIGH and LO_SUM parts of a move if the HIGH part is only
|
;; to merge the HIGH and LO_SUM parts of a move if the HIGH part is only
|
;; used once. We can then use the sequence:
|
;; used once. We can then use the sequence:
|
;;
|
;;
|
;; lui op0,%highest(op1)
|
;; lui op0,%highest(op1)
|
;; lui op2,%hi(op1)
|
;; lui op2,%hi(op1)
|
;; daddiu op0,op0,%higher(op1)
|
;; daddiu op0,op0,%higher(op1)
|
;; daddiu op2,op2,%lo(op1)
|
;; daddiu op2,op2,%lo(op1)
|
;; dsll32 op0,op0,0
|
;; dsll32 op0,op0,0
|
;; daddu op0,op0,op2
|
;; daddu op0,op0,op2
|
;;
|
;;
|
;; which takes 4 cycles on most superscalar targets.
|
;; which takes 4 cycles on most superscalar targets.
|
(define_insn_and_split "*lea64"
|
(define_insn_and_split "*lea64"
|
[(set (match_operand:DI 0 "register_operand" "=d")
|
[(set (match_operand:DI 0 "register_operand" "=d")
|
(match_operand:DI 1 "absolute_symbolic_operand" ""))
|
(match_operand:DI 1 "absolute_symbolic_operand" ""))
|
(clobber (match_scratch:DI 2 "=&d"))]
|
(clobber (match_scratch:DI 2 "=&d"))]
|
"TARGET_EXPLICIT_RELOCS && ABI_HAS_64BIT_SYMBOLS && cse_not_expected"
|
"TARGET_EXPLICIT_RELOCS && ABI_HAS_64BIT_SYMBOLS && cse_not_expected"
|
"#"
|
"#"
|
"&& reload_completed"
|
"&& reload_completed"
|
[(set (match_dup 0) (high:DI (match_dup 3)))
|
[(set (match_dup 0) (high:DI (match_dup 3)))
|
(set (match_dup 2) (high:DI (match_dup 4)))
|
(set (match_dup 2) (high:DI (match_dup 4)))
|
(set (match_dup 0) (lo_sum:DI (match_dup 0) (match_dup 3)))
|
(set (match_dup 0) (lo_sum:DI (match_dup 0) (match_dup 3)))
|
(set (match_dup 2) (lo_sum:DI (match_dup 2) (match_dup 4)))
|
(set (match_dup 2) (lo_sum:DI (match_dup 2) (match_dup 4)))
|
(set (match_dup 0) (ashift:DI (match_dup 0) (const_int 32)))
|
(set (match_dup 0) (ashift:DI (match_dup 0) (const_int 32)))
|
(set (match_dup 0) (plus:DI (match_dup 0) (match_dup 2)))]
|
(set (match_dup 0) (plus:DI (match_dup 0) (match_dup 2)))]
|
{
|
{
|
operands[3] = mips_unspec_address (operands[1], SYMBOL_64_HIGH);
|
operands[3] = mips_unspec_address (operands[1], SYMBOL_64_HIGH);
|
operands[4] = mips_unspec_address (operands[1], SYMBOL_64_LOW);
|
operands[4] = mips_unspec_address (operands[1], SYMBOL_64_LOW);
|
}
|
}
|
[(set_attr "length" "24")])
|
[(set_attr "length" "24")])
|
|
|
;; Split HIGHs into:
|
;; Split HIGHs into:
|
;;
|
;;
|
;; li op0,%hi(sym)
|
;; li op0,%hi(sym)
|
;; sll op0,16
|
;; sll op0,16
|
;;
|
;;
|
;; on MIPS16 targets.
|
;; on MIPS16 targets.
|
(define_split
|
(define_split
|
[(set (match_operand:SI 0 "d_operand")
|
[(set (match_operand:SI 0 "d_operand")
|
(high:SI (match_operand:SI 1 "absolute_symbolic_operand")))]
|
(high:SI (match_operand:SI 1 "absolute_symbolic_operand")))]
|
"TARGET_MIPS16 && reload_completed"
|
"TARGET_MIPS16 && reload_completed"
|
[(set (match_dup 0) (match_dup 2))
|
[(set (match_dup 0) (match_dup 2))
|
(set (match_dup 0) (ashift:SI (match_dup 0) (const_int 16)))]
|
(set (match_dup 0) (ashift:SI (match_dup 0) (const_int 16)))]
|
{
|
{
|
operands[2] = mips_unspec_address (operands[1], SYMBOL_32_HIGH);
|
operands[2] = mips_unspec_address (operands[1], SYMBOL_32_HIGH);
|
})
|
})
|
|
|
;; Insns to fetch a symbol from a big GOT.
|
;; Insns to fetch a symbol from a big GOT.
|
|
|
(define_insn_and_split "*xgot_hi"
|
(define_insn_and_split "*xgot_hi"
|
[(set (match_operand:P 0 "register_operand" "=d")
|
[(set (match_operand:P 0 "register_operand" "=d")
|
(high:P (match_operand:P 1 "got_disp_operand" "")))]
|
(high:P (match_operand:P 1 "got_disp_operand" "")))]
|
"TARGET_EXPLICIT_RELOCS && TARGET_XGOT"
|
"TARGET_EXPLICIT_RELOCS && TARGET_XGOT"
|
"#"
|
"#"
|
"&& reload_completed"
|
"&& reload_completed"
|
[(set (match_dup 0) (high:P (match_dup 2)))
|
[(set (match_dup 0) (high:P (match_dup 2)))
|
(set (match_dup 0) (plus:P (match_dup 0) (match_dup 3)))]
|
(set (match_dup 0) (plus:P (match_dup 0) (match_dup 3)))]
|
{
|
{
|
operands[2] = mips_unspec_address (operands[1], SYMBOL_GOTOFF_DISP);
|
operands[2] = mips_unspec_address (operands[1], SYMBOL_GOTOFF_DISP);
|
operands[3] = pic_offset_table_rtx;
|
operands[3] = pic_offset_table_rtx;
|
}
|
}
|
[(set_attr "got" "xgot_high")
|
[(set_attr "got" "xgot_high")
|
(set_attr "mode" "")])
|
(set_attr "mode" "")])
|
|
|
(define_insn_and_split "*xgot_lo"
|
(define_insn_and_split "*xgot_lo"
|
[(set (match_operand:P 0 "register_operand" "=d")
|
[(set (match_operand:P 0 "register_operand" "=d")
|
(lo_sum:P (match_operand:P 1 "register_operand" "d")
|
(lo_sum:P (match_operand:P 1 "register_operand" "d")
|
(match_operand:P 2 "got_disp_operand" "")))]
|
(match_operand:P 2 "got_disp_operand" "")))]
|
"TARGET_EXPLICIT_RELOCS && TARGET_XGOT"
|
"TARGET_EXPLICIT_RELOCS && TARGET_XGOT"
|
"#"
|
"#"
|
"&& reload_completed"
|
"&& reload_completed"
|
[(set (match_dup 0)
|
[(set (match_dup 0)
|
(unspec:P [(match_dup 1) (match_dup 3)] UNSPEC_LOAD_GOT))]
|
(unspec:P [(match_dup 1) (match_dup 3)] UNSPEC_LOAD_GOT))]
|
{ operands[3] = mips_unspec_address (operands[2], SYMBOL_GOTOFF_DISP); }
|
{ operands[3] = mips_unspec_address (operands[2], SYMBOL_GOTOFF_DISP); }
|
[(set_attr "got" "load")
|
[(set_attr "got" "load")
|
(set_attr "mode" "")])
|
(set_attr "mode" "")])
|
|
|
;; Insns to fetch a symbol from a normal GOT.
|
;; Insns to fetch a symbol from a normal GOT.
|
|
|
(define_insn_and_split "*got_disp"
|
(define_insn_and_split "*got_disp"
|
[(set (match_operand:P 0 "register_operand" "=d")
|
[(set (match_operand:P 0 "register_operand" "=d")
|
(match_operand:P 1 "got_disp_operand" ""))]
|
(match_operand:P 1 "got_disp_operand" ""))]
|
"TARGET_EXPLICIT_RELOCS && !mips_split_p[SYMBOL_GOT_DISP]"
|
"TARGET_EXPLICIT_RELOCS && !mips_split_p[SYMBOL_GOT_DISP]"
|
"#"
|
"#"
|
"&& reload_completed"
|
"&& reload_completed"
|
[(set (match_dup 0) (match_dup 2))]
|
[(set (match_dup 0) (match_dup 2))]
|
{ operands[2] = mips_got_load (NULL, operands[1], SYMBOL_GOTOFF_DISP); }
|
{ operands[2] = mips_got_load (NULL, operands[1], SYMBOL_GOTOFF_DISP); }
|
[(set_attr "got" "load")
|
[(set_attr "got" "load")
|
(set_attr "mode" "")])
|
(set_attr "mode" "")])
|
|
|
;; Insns for loading the "page" part of a page/ofst address from the GOT.
|
;; Insns for loading the "page" part of a page/ofst address from the GOT.
|
|
|
(define_insn_and_split "*got_page"
|
(define_insn_and_split "*got_page"
|
[(set (match_operand:P 0 "register_operand" "=d")
|
[(set (match_operand:P 0 "register_operand" "=d")
|
(high:P (match_operand:P 1 "got_page_ofst_operand" "")))]
|
(high:P (match_operand:P 1 "got_page_ofst_operand" "")))]
|
"TARGET_EXPLICIT_RELOCS && !mips_split_hi_p[SYMBOL_GOT_PAGE_OFST]"
|
"TARGET_EXPLICIT_RELOCS && !mips_split_hi_p[SYMBOL_GOT_PAGE_OFST]"
|
"#"
|
"#"
|
"&& reload_completed"
|
"&& reload_completed"
|
[(set (match_dup 0) (match_dup 2))]
|
[(set (match_dup 0) (match_dup 2))]
|
{ operands[2] = mips_got_load (NULL, operands[1], SYMBOL_GOTOFF_PAGE); }
|
{ operands[2] = mips_got_load (NULL, operands[1], SYMBOL_GOTOFF_PAGE); }
|
[(set_attr "got" "load")
|
[(set_attr "got" "load")
|
(set_attr "mode" "")])
|
(set_attr "mode" "")])
|
|
|
;; Convenience expander that generates the rhs of a load_got insn.
|
;; Convenience expander that generates the rhs of a load_got insn.
|
(define_expand "unspec_got"
|
(define_expand "unspec_got"
|
[(unspec:P [(match_operand:P 0)
|
[(unspec:P [(match_operand:P 0)
|
(match_operand:P 1)] UNSPEC_LOAD_GOT)])
|
(match_operand:P 1)] UNSPEC_LOAD_GOT)])
|
|
|
;; Lower-level instructions for loading an address from the GOT.
|
;; Lower-level instructions for loading an address from the GOT.
|
;; We could use MEMs, but an unspec gives more optimization
|
;; We could use MEMs, but an unspec gives more optimization
|
;; opportunities.
|
;; opportunities.
|
|
|
(define_insn "load_got"
|
(define_insn "load_got"
|
[(set (match_operand:P 0 "register_operand" "=d")
|
[(set (match_operand:P 0 "register_operand" "=d")
|
(unspec:P [(match_operand:P 1 "register_operand" "d")
|
(unspec:P [(match_operand:P 1 "register_operand" "d")
|
(match_operand:P 2 "immediate_operand" "")]
|
(match_operand:P 2 "immediate_operand" "")]
|
UNSPEC_LOAD_GOT))]
|
UNSPEC_LOAD_GOT))]
|
""
|
""
|
"\t%0,%R2(%1)"
|
"\t%0,%R2(%1)"
|
[(set_attr "got" "load")
|
[(set_attr "got" "load")
|
(set_attr "mode" "")])
|
(set_attr "mode" "")])
|
|
|
;; Instructions for adding the low 16 bits of an address to a register.
|
;; Instructions for adding the low 16 bits of an address to a register.
|
;; Operand 2 is the address: mips_print_operand works out which relocation
|
;; Operand 2 is the address: mips_print_operand works out which relocation
|
;; should be applied.
|
;; should be applied.
|
|
|
(define_insn "*low"
|
(define_insn "*low"
|
[(set (match_operand:P 0 "register_operand" "=d")
|
[(set (match_operand:P 0 "register_operand" "=d")
|
(lo_sum:P (match_operand:P 1 "register_operand" "d")
|
(lo_sum:P (match_operand:P 1 "register_operand" "d")
|
(match_operand:P 2 "immediate_operand" "")))]
|
(match_operand:P 2 "immediate_operand" "")))]
|
"!TARGET_MIPS16"
|
"!TARGET_MIPS16"
|
"addiu\t%0,%1,%R2"
|
"addiu\t%0,%1,%R2"
|
[(set_attr "type" "arith")
|
[(set_attr "type" "arith")
|
(set_attr "mode" "")])
|
(set_attr "mode" "")])
|
|
|
(define_insn "*low_mips16"
|
(define_insn "*low_mips16"
|
[(set (match_operand:P 0 "register_operand" "=d")
|
[(set (match_operand:P 0 "register_operand" "=d")
|
(lo_sum:P (match_operand:P 1 "register_operand" "0")
|
(lo_sum:P (match_operand:P 1 "register_operand" "0")
|
(match_operand:P 2 "immediate_operand" "")))]
|
(match_operand:P 2 "immediate_operand" "")))]
|
"TARGET_MIPS16"
|
"TARGET_MIPS16"
|
"addiu\t%0,%R2"
|
"addiu\t%0,%R2"
|
[(set_attr "type" "arith")
|
[(set_attr "type" "arith")
|
(set_attr "mode" "")
|
(set_attr "mode" "")
|
(set_attr "extended_mips16" "yes")])
|
(set_attr "extended_mips16" "yes")])
|
|
|
;; Expose MIPS16 uses of the global pointer after reload if the function
|
;; Expose MIPS16 uses of the global pointer after reload if the function
|
;; is responsible for setting up the register itself.
|
;; is responsible for setting up the register itself.
|
(define_split
|
(define_split
|
[(set (match_operand:GPR 0 "d_operand")
|
[(set (match_operand:GPR 0 "d_operand")
|
(const:GPR (unspec:GPR [(const_int 0)] UNSPEC_GP)))]
|
(const:GPR (unspec:GPR [(const_int 0)] UNSPEC_GP)))]
|
"TARGET_MIPS16 && TARGET_USE_GOT && reload_completed"
|
"TARGET_MIPS16 && TARGET_USE_GOT && reload_completed"
|
[(set (match_dup 0) (match_dup 1))]
|
[(set (match_dup 0) (match_dup 1))]
|
{ operands[1] = pic_offset_table_rtx; })
|
{ operands[1] = pic_offset_table_rtx; })
|
|
|
;; Allow combine to split complex const_int load sequences, using operand 2
|
;; Allow combine to split complex const_int load sequences, using operand 2
|
;; to store the intermediate results. See move_operand for details.
|
;; to store the intermediate results. See move_operand for details.
|
(define_split
|
(define_split
|
[(set (match_operand:GPR 0 "register_operand")
|
[(set (match_operand:GPR 0 "register_operand")
|
(match_operand:GPR 1 "splittable_const_int_operand"))
|
(match_operand:GPR 1 "splittable_const_int_operand"))
|
(clobber (match_operand:GPR 2 "register_operand"))]
|
(clobber (match_operand:GPR 2 "register_operand"))]
|
""
|
""
|
[(const_int 0)]
|
[(const_int 0)]
|
{
|
{
|
mips_move_integer (operands[2], operands[0], INTVAL (operands[1]));
|
mips_move_integer (operands[2], operands[0], INTVAL (operands[1]));
|
DONE;
|
DONE;
|
})
|
})
|
|
|
;; Likewise, for symbolic operands.
|
;; Likewise, for symbolic operands.
|
(define_split
|
(define_split
|
[(set (match_operand:P 0 "register_operand")
|
[(set (match_operand:P 0 "register_operand")
|
(match_operand:P 1))
|
(match_operand:P 1))
|
(clobber (match_operand:P 2 "register_operand"))]
|
(clobber (match_operand:P 2 "register_operand"))]
|
"mips_split_symbol (operands[2], operands[1], MAX_MACHINE_MODE, NULL)"
|
"mips_split_symbol (operands[2], operands[1], MAX_MACHINE_MODE, NULL)"
|
[(set (match_dup 0) (match_dup 3))]
|
[(set (match_dup 0) (match_dup 3))]
|
{
|
{
|
mips_split_symbol (operands[2], operands[1],
|
mips_split_symbol (operands[2], operands[1],
|
MAX_MACHINE_MODE, &operands[3]);
|
MAX_MACHINE_MODE, &operands[3]);
|
})
|
})
|
|
|
;; 64-bit integer moves
|
;; 64-bit integer moves
|
|
|
;; Unlike most other insns, the move insns can't be split with
|
;; Unlike most other insns, the move insns can't be split with
|
;; different predicates, because register spilling and other parts of
|
;; different predicates, because register spilling and other parts of
|
;; the compiler, have memoized the insn number already.
|
;; the compiler, have memoized the insn number already.
|
|
|
(define_expand "movdi"
|
(define_expand "movdi"
|
[(set (match_operand:DI 0 "")
|
[(set (match_operand:DI 0 "")
|
(match_operand:DI 1 ""))]
|
(match_operand:DI 1 ""))]
|
""
|
""
|
{
|
{
|
if (mips_legitimize_move (DImode, operands[0], operands[1]))
|
if (mips_legitimize_move (DImode, operands[0], operands[1]))
|
DONE;
|
DONE;
|
})
|
})
|
|
|
;; For mips16, we need a special case to handle storing $31 into
|
;; For mips16, we need a special case to handle storing $31 into
|
;; memory, since we don't have a constraint to match $31. This
|
;; memory, since we don't have a constraint to match $31. This
|
;; instruction can be generated by save_restore_insns.
|
;; instruction can be generated by save_restore_insns.
|
|
|
(define_insn "*mov_ra"
|
(define_insn "*mov_ra"
|
[(set (match_operand:GPR 0 "stack_operand" "=m")
|
[(set (match_operand:GPR 0 "stack_operand" "=m")
|
(reg:GPR RETURN_ADDR_REGNUM))]
|
(reg:GPR RETURN_ADDR_REGNUM))]
|
"TARGET_MIPS16"
|
"TARGET_MIPS16"
|
"\t$31,%0"
|
"\t$31,%0"
|
[(set_attr "move_type" "store")
|
[(set_attr "move_type" "store")
|
(set_attr "mode" "")])
|
(set_attr "mode" "")])
|
|
|
(define_insn "*movdi_32bit"
|
(define_insn "*movdi_32bit"
|
[(set (match_operand:DI 0 "nonimmediate_operand" "=d,d,d,m,*a,*d,*f,*f,*d,*m,*B*C*D,*B*C*D,*d,*m")
|
[(set (match_operand:DI 0 "nonimmediate_operand" "=d,d,d,m,*a,*d,*f,*f,*d,*m,*B*C*D,*B*C*D,*d,*m")
|
(match_operand:DI 1 "move_operand" "d,i,m,d,*J*d,*a,*J*d,*m,*f,*f,*d,*m,*B*C*D,*B*C*D"))]
|
(match_operand:DI 1 "move_operand" "d,i,m,d,*J*d,*a,*J*d,*m,*f,*f,*d,*m,*B*C*D,*B*C*D"))]
|
"!TARGET_64BIT && !TARGET_MIPS16
|
"!TARGET_64BIT && !TARGET_MIPS16
|
&& (register_operand (operands[0], DImode)
|
&& (register_operand (operands[0], DImode)
|
|| reg_or_0_operand (operands[1], DImode))"
|
|| reg_or_0_operand (operands[1], DImode))"
|
{ return mips_output_move (operands[0], operands[1]); }
|
{ return mips_output_move (operands[0], operands[1]); }
|
[(set_attr "move_type" "move,const,load,store,mthilo,mfhilo,mtc,fpload,mfc,fpstore,mtc,fpload,mfc,fpstore")
|
[(set_attr "move_type" "move,const,load,store,mthilo,mfhilo,mtc,fpload,mfc,fpstore,mtc,fpload,mfc,fpstore")
|
(set_attr "mode" "DI")])
|
(set_attr "mode" "DI")])
|
|
|
(define_insn "*movdi_32bit_mips16"
|
(define_insn "*movdi_32bit_mips16"
|
[(set (match_operand:DI 0 "nonimmediate_operand" "=d,y,d,d,d,d,m,*d")
|
[(set (match_operand:DI 0 "nonimmediate_operand" "=d,y,d,d,d,d,m,*d")
|
(match_operand:DI 1 "move_operand" "d,d,y,K,N,m,d,*x"))]
|
(match_operand:DI 1 "move_operand" "d,d,y,K,N,m,d,*x"))]
|
"!TARGET_64BIT && TARGET_MIPS16
|
"!TARGET_64BIT && TARGET_MIPS16
|
&& (register_operand (operands[0], DImode)
|
&& (register_operand (operands[0], DImode)
|
|| register_operand (operands[1], DImode))"
|
|| register_operand (operands[1], DImode))"
|
{ return mips_output_move (operands[0], operands[1]); }
|
{ return mips_output_move (operands[0], operands[1]); }
|
[(set_attr "move_type" "move,move,move,const,constN,load,store,mfhilo")
|
[(set_attr "move_type" "move,move,move,const,constN,load,store,mfhilo")
|
(set_attr "mode" "DI")])
|
(set_attr "mode" "DI")])
|
|
|
(define_insn "*movdi_64bit"
|
(define_insn "*movdi_64bit"
|
[(set (match_operand:DI 0 "nonimmediate_operand" "=d,d,e,d,m,*f,*f,*d,*m,*a,*d,*B*C*D,*B*C*D,*d,*m")
|
[(set (match_operand:DI 0 "nonimmediate_operand" "=d,d,e,d,m,*f,*f,*d,*m,*a,*d,*B*C*D,*B*C*D,*d,*m")
|
(match_operand:DI 1 "move_operand" "d,U,T,m,dJ,*d*J,*m,*f,*f,*J*d,*a,*d,*m,*B*C*D,*B*C*D"))]
|
(match_operand:DI 1 "move_operand" "d,U,T,m,dJ,*d*J,*m,*f,*f,*J*d,*a,*d,*m,*B*C*D,*B*C*D"))]
|
"TARGET_64BIT && !TARGET_MIPS16
|
"TARGET_64BIT && !TARGET_MIPS16
|
&& (register_operand (operands[0], DImode)
|
&& (register_operand (operands[0], DImode)
|
|| reg_or_0_operand (operands[1], DImode))"
|
|| reg_or_0_operand (operands[1], DImode))"
|
{ return mips_output_move (operands[0], operands[1]); }
|
{ return mips_output_move (operands[0], operands[1]); }
|
[(set_attr "move_type" "move,const,const,load,store,mtc,fpload,mfc,fpstore,mthilo,mfhilo,mtc,fpload,mfc,fpstore")
|
[(set_attr "move_type" "move,const,const,load,store,mtc,fpload,mfc,fpstore,mthilo,mfhilo,mtc,fpload,mfc,fpstore")
|
(set_attr "mode" "DI")])
|
(set_attr "mode" "DI")])
|
|
|
(define_insn "*movdi_64bit_mips16"
|
(define_insn "*movdi_64bit_mips16"
|
[(set (match_operand:DI 0 "nonimmediate_operand" "=d,y,d,d,d,d,d,d,m,*d")
|
[(set (match_operand:DI 0 "nonimmediate_operand" "=d,y,d,d,d,d,d,d,m,*d")
|
(match_operand:DI 1 "move_operand" "d,d,y,K,N,U,kf,m,d,*a"))]
|
(match_operand:DI 1 "move_operand" "d,d,y,K,N,U,kf,m,d,*a"))]
|
"TARGET_64BIT && TARGET_MIPS16
|
"TARGET_64BIT && TARGET_MIPS16
|
&& (register_operand (operands[0], DImode)
|
&& (register_operand (operands[0], DImode)
|
|| register_operand (operands[1], DImode))"
|
|| register_operand (operands[1], DImode))"
|
{ return mips_output_move (operands[0], operands[1]); }
|
{ return mips_output_move (operands[0], operands[1]); }
|
[(set_attr "move_type" "move,move,move,const,constN,const,loadpool,load,store,mfhilo")
|
[(set_attr "move_type" "move,move,move,const,constN,const,loadpool,load,store,mfhilo")
|
(set_attr "mode" "DI")])
|
(set_attr "mode" "DI")])
|
|
|
;; On the mips16, we can split ld $r,N($r) into an add and a load,
|
;; On the mips16, we can split ld $r,N($r) into an add and a load,
|
;; when the original load is a 4 byte instruction but the add and the
|
;; when the original load is a 4 byte instruction but the add and the
|
;; load are 2 2 byte instructions.
|
;; load are 2 2 byte instructions.
|
|
|
(define_split
|
(define_split
|
[(set (match_operand:DI 0 "d_operand")
|
[(set (match_operand:DI 0 "d_operand")
|
(mem:DI (plus:DI (match_dup 0)
|
(mem:DI (plus:DI (match_dup 0)
|
(match_operand:DI 1 "const_int_operand"))))]
|
(match_operand:DI 1 "const_int_operand"))))]
|
"TARGET_64BIT && TARGET_MIPS16 && reload_completed
|
"TARGET_64BIT && TARGET_MIPS16 && reload_completed
|
&& !TARGET_DEBUG_D_MODE
|
&& !TARGET_DEBUG_D_MODE
|
&& ((INTVAL (operands[1]) < 0
|
&& ((INTVAL (operands[1]) < 0
|
&& INTVAL (operands[1]) >= -0x10)
|
&& INTVAL (operands[1]) >= -0x10)
|
|| (INTVAL (operands[1]) >= 32 * 8
|
|| (INTVAL (operands[1]) >= 32 * 8
|
&& INTVAL (operands[1]) <= 31 * 8 + 0x8)
|
&& INTVAL (operands[1]) <= 31 * 8 + 0x8)
|
|| (INTVAL (operands[1]) >= 0
|
|| (INTVAL (operands[1]) >= 0
|
&& INTVAL (operands[1]) < 32 * 8
|
&& INTVAL (operands[1]) < 32 * 8
|
&& (INTVAL (operands[1]) & 7) != 0))"
|
&& (INTVAL (operands[1]) & 7) != 0))"
|
[(set (match_dup 0) (plus:DI (match_dup 0) (match_dup 1)))
|
[(set (match_dup 0) (plus:DI (match_dup 0) (match_dup 1)))
|
(set (match_dup 0) (mem:DI (plus:DI (match_dup 0) (match_dup 2))))]
|
(set (match_dup 0) (mem:DI (plus:DI (match_dup 0) (match_dup 2))))]
|
{
|
{
|
HOST_WIDE_INT val = INTVAL (operands[1]);
|
HOST_WIDE_INT val = INTVAL (operands[1]);
|
|
|
if (val < 0)
|
if (val < 0)
|
operands[2] = const0_rtx;
|
operands[2] = const0_rtx;
|
else if (val >= 32 * 8)
|
else if (val >= 32 * 8)
|
{
|
{
|
int off = val & 7;
|
int off = val & 7;
|
|
|
operands[1] = GEN_INT (0x8 + off);
|
operands[1] = GEN_INT (0x8 + off);
|
operands[2] = GEN_INT (val - off - 0x8);
|
operands[2] = GEN_INT (val - off - 0x8);
|
}
|
}
|
else
|
else
|
{
|
{
|
int off = val & 7;
|
int off = val & 7;
|
|
|
operands[1] = GEN_INT (off);
|
operands[1] = GEN_INT (off);
|
operands[2] = GEN_INT (val - off);
|
operands[2] = GEN_INT (val - off);
|
}
|
}
|
})
|
})
|
|
|
;; 32-bit Integer moves
|
;; 32-bit Integer moves
|
|
|
;; Unlike most other insns, the move insns can't be split with
|
;; Unlike most other insns, the move insns can't be split with
|
;; different predicates, because register spilling and other parts of
|
;; different predicates, because register spilling and other parts of
|
;; the compiler, have memoized the insn number already.
|
;; the compiler, have memoized the insn number already.
|
|
|
(define_expand "mov"
|
(define_expand "mov"
|
[(set (match_operand:IMOVE32 0 "")
|
[(set (match_operand:IMOVE32 0 "")
|
(match_operand:IMOVE32 1 ""))]
|
(match_operand:IMOVE32 1 ""))]
|
""
|
""
|
{
|
{
|
if (mips_legitimize_move (mode, operands[0], operands[1]))
|
if (mips_legitimize_move (mode, operands[0], operands[1]))
|
DONE;
|
DONE;
|
})
|
})
|
|
|
;; The difference between these two is whether or not ints are allowed
|
;; The difference between these two is whether or not ints are allowed
|
;; in FP registers (off by default, use -mdebugh to enable).
|
;; in FP registers (off by default, use -mdebugh to enable).
|
|
|
(define_insn "*mov_internal"
|
(define_insn "*mov_internal"
|
[(set (match_operand:IMOVE32 0 "nonimmediate_operand" "=d,d,e,d,m,*f,*f,*d,*m,*d,*z,*a,*d,*B*C*D,*B*C*D,*d,*m")
|
[(set (match_operand:IMOVE32 0 "nonimmediate_operand" "=d,d,e,d,m,*f,*f,*d,*m,*d,*z,*a,*d,*B*C*D,*B*C*D,*d,*m")
|
(match_operand:IMOVE32 1 "move_operand" "d,U,T,m,dJ,*d*J,*m,*f,*f,*z,*d,*J*d,*a,*d,*m,*B*C*D,*B*C*D"))]
|
(match_operand:IMOVE32 1 "move_operand" "d,U,T,m,dJ,*d*J,*m,*f,*f,*z,*d,*J*d,*a,*d,*m,*B*C*D,*B*C*D"))]
|
"!TARGET_MIPS16
|
"!TARGET_MIPS16
|
&& (register_operand (operands[0], mode)
|
&& (register_operand (operands[0], mode)
|
|| reg_or_0_operand (operands[1], mode))"
|
|| reg_or_0_operand (operands[1], mode))"
|
{ return mips_output_move (operands[0], operands[1]); }
|
{ return mips_output_move (operands[0], operands[1]); }
|
[(set_attr "move_type" "move,const,const,load,store,mtc,fpload,mfc,fpstore,mfc,mtc,mthilo,mfhilo,mtc,fpload,mfc,fpstore")
|
[(set_attr "move_type" "move,const,const,load,store,mtc,fpload,mfc,fpstore,mfc,mtc,mthilo,mfhilo,mtc,fpload,mfc,fpstore")
|
(set_attr "mode" "SI")])
|
(set_attr "mode" "SI")])
|
|
|
(define_insn "*mov_mips16"
|
(define_insn "*mov_mips16"
|
[(set (match_operand:IMOVE32 0 "nonimmediate_operand" "=d,y,d,d,d,d,d,d,m,*d")
|
[(set (match_operand:IMOVE32 0 "nonimmediate_operand" "=d,y,d,d,d,d,d,d,m,*d")
|
(match_operand:IMOVE32 1 "move_operand" "d,d,y,K,N,U,kf,m,d,*a"))]
|
(match_operand:IMOVE32 1 "move_operand" "d,d,y,K,N,U,kf,m,d,*a"))]
|
"TARGET_MIPS16
|
"TARGET_MIPS16
|
&& (register_operand (operands[0], mode)
|
&& (register_operand (operands[0], mode)
|
|| register_operand (operands[1], mode))"
|
|| register_operand (operands[1], mode))"
|
{ return mips_output_move (operands[0], operands[1]); }
|
{ return mips_output_move (operands[0], operands[1]); }
|
[(set_attr "move_type" "move,move,move,const,constN,const,loadpool,load,store,mfhilo")
|
[(set_attr "move_type" "move,move,move,const,constN,const,loadpool,load,store,mfhilo")
|
(set_attr "mode" "SI")])
|
(set_attr "mode" "SI")])
|
|
|
;; On the mips16, we can split lw $r,N($r) into an add and a load,
|
;; On the mips16, we can split lw $r,N($r) into an add and a load,
|
;; when the original load is a 4 byte instruction but the add and the
|
;; when the original load is a 4 byte instruction but the add and the
|
;; load are 2 2 byte instructions.
|
;; load are 2 2 byte instructions.
|
|
|
(define_split
|
(define_split
|
[(set (match_operand:SI 0 "d_operand")
|
[(set (match_operand:SI 0 "d_operand")
|
(mem:SI (plus:SI (match_dup 0)
|
(mem:SI (plus:SI (match_dup 0)
|
(match_operand:SI 1 "const_int_operand"))))]
|
(match_operand:SI 1 "const_int_operand"))))]
|
"TARGET_MIPS16 && reload_completed && !TARGET_DEBUG_D_MODE
|
"TARGET_MIPS16 && reload_completed && !TARGET_DEBUG_D_MODE
|
&& ((INTVAL (operands[1]) < 0
|
&& ((INTVAL (operands[1]) < 0
|
&& INTVAL (operands[1]) >= -0x80)
|
&& INTVAL (operands[1]) >= -0x80)
|
|| (INTVAL (operands[1]) >= 32 * 4
|
|| (INTVAL (operands[1]) >= 32 * 4
|
&& INTVAL (operands[1]) <= 31 * 4 + 0x7c)
|
&& INTVAL (operands[1]) <= 31 * 4 + 0x7c)
|
|| (INTVAL (operands[1]) >= 0
|
|| (INTVAL (operands[1]) >= 0
|
&& INTVAL (operands[1]) < 32 * 4
|
&& INTVAL (operands[1]) < 32 * 4
|
&& (INTVAL (operands[1]) & 3) != 0))"
|
&& (INTVAL (operands[1]) & 3) != 0))"
|
[(set (match_dup 0) (plus:SI (match_dup 0) (match_dup 1)))
|
[(set (match_dup 0) (plus:SI (match_dup 0) (match_dup 1)))
|
(set (match_dup 0) (mem:SI (plus:SI (match_dup 0) (match_dup 2))))]
|
(set (match_dup 0) (mem:SI (plus:SI (match_dup 0) (match_dup 2))))]
|
{
|
{
|
HOST_WIDE_INT val = INTVAL (operands[1]);
|
HOST_WIDE_INT val = INTVAL (operands[1]);
|
|
|
if (val < 0)
|
if (val < 0)
|
operands[2] = const0_rtx;
|
operands[2] = const0_rtx;
|
else if (val >= 32 * 4)
|
else if (val >= 32 * 4)
|
{
|
{
|
int off = val & 3;
|
int off = val & 3;
|
|
|
operands[1] = GEN_INT (0x7c + off);
|
operands[1] = GEN_INT (0x7c + off);
|
operands[2] = GEN_INT (val - off - 0x7c);
|
operands[2] = GEN_INT (val - off - 0x7c);
|
}
|
}
|
else
|
else
|
{
|
{
|
int off = val & 3;
|
int off = val & 3;
|
|
|
operands[1] = GEN_INT (off);
|
operands[1] = GEN_INT (off);
|
operands[2] = GEN_INT (val - off);
|
operands[2] = GEN_INT (val - off);
|
}
|
}
|
})
|
})
|
|
|
;; On the mips16, we can split a load of certain constants into a load
|
;; On the mips16, we can split a load of certain constants into a load
|
;; and an add. This turns a 4 byte instruction into 2 2 byte
|
;; and an add. This turns a 4 byte instruction into 2 2 byte
|
;; instructions.
|
;; instructions.
|
|
|
(define_split
|
(define_split
|
[(set (match_operand:SI 0 "d_operand")
|
[(set (match_operand:SI 0 "d_operand")
|
(match_operand:SI 1 "const_int_operand"))]
|
(match_operand:SI 1 "const_int_operand"))]
|
"TARGET_MIPS16 && reload_completed && !TARGET_DEBUG_D_MODE
|
"TARGET_MIPS16 && reload_completed && !TARGET_DEBUG_D_MODE
|
&& INTVAL (operands[1]) >= 0x100
|
&& INTVAL (operands[1]) >= 0x100
|
&& INTVAL (operands[1]) <= 0xff + 0x7f"
|
&& INTVAL (operands[1]) <= 0xff + 0x7f"
|
[(set (match_dup 0) (match_dup 1))
|
[(set (match_dup 0) (match_dup 1))
|
(set (match_dup 0) (plus:SI (match_dup 0) (match_dup 2)))]
|
(set (match_dup 0) (plus:SI (match_dup 0) (match_dup 2)))]
|
{
|
{
|
int val = INTVAL (operands[1]);
|
int val = INTVAL (operands[1]);
|
|
|
operands[1] = GEN_INT (0xff);
|
operands[1] = GEN_INT (0xff);
|
operands[2] = GEN_INT (val - 0xff);
|
operands[2] = GEN_INT (val - 0xff);
|
})
|
})
|
|
|
;; This insn handles moving CCmode values. It's really just a
|
;; This insn handles moving CCmode values. It's really just a
|
;; slightly simplified copy of movsi_internal2, with additional cases
|
;; slightly simplified copy of movsi_internal2, with additional cases
|
;; to move a condition register to a general register and to move
|
;; to move a condition register to a general register and to move
|
;; between the general registers and the floating point registers.
|
;; between the general registers and the floating point registers.
|
|
|
(define_insn "movcc"
|
(define_insn "movcc"
|
[(set (match_operand:CC 0 "nonimmediate_operand" "=d,*d,*d,*m,*d,*f,*f,*f,*m")
|
[(set (match_operand:CC 0 "nonimmediate_operand" "=d,*d,*d,*m,*d,*f,*f,*f,*m")
|
(match_operand:CC 1 "general_operand" "z,*d,*m,*d,*f,*d,*f,*m,*f"))]
|
(match_operand:CC 1 "general_operand" "z,*d,*m,*d,*f,*d,*f,*m,*f"))]
|
"ISA_HAS_8CC && TARGET_HARD_FLOAT"
|
"ISA_HAS_8CC && TARGET_HARD_FLOAT"
|
{ return mips_output_move (operands[0], operands[1]); }
|
{ return mips_output_move (operands[0], operands[1]); }
|
[(set_attr "move_type" "lui_movf,move,load,store,mfc,mtc,fmove,fpload,fpstore")
|
[(set_attr "move_type" "lui_movf,move,load,store,mfc,mtc,fmove,fpload,fpstore")
|
(set_attr "mode" "SI")])
|
(set_attr "mode" "SI")])
|
|
|
;; Reload condition code registers. reload_incc and reload_outcc
|
;; Reload condition code registers. reload_incc and reload_outcc
|
;; both handle moves from arbitrary operands into condition code
|
;; both handle moves from arbitrary operands into condition code
|
;; registers. reload_incc handles the more common case in which
|
;; registers. reload_incc handles the more common case in which
|
;; a source operand is constrained to be in a condition-code
|
;; a source operand is constrained to be in a condition-code
|
;; register, but has not been allocated to one.
|
;; register, but has not been allocated to one.
|
;;
|
;;
|
;; Sometimes, such as in movcc, we have a CCmode destination whose
|
;; Sometimes, such as in movcc, we have a CCmode destination whose
|
;; constraints do not include 'z'. reload_outcc handles the case
|
;; constraints do not include 'z'. reload_outcc handles the case
|
;; when such an operand is allocated to a condition-code register.
|
;; when such an operand is allocated to a condition-code register.
|
;;
|
;;
|
;; Note that reloads from a condition code register to some
|
;; Note that reloads from a condition code register to some
|
;; other location can be done using ordinary moves. Moving
|
;; other location can be done using ordinary moves. Moving
|
;; into a GPR takes a single movcc, moving elsewhere takes
|
;; into a GPR takes a single movcc, moving elsewhere takes
|
;; two. We can leave these cases to the generic reload code.
|
;; two. We can leave these cases to the generic reload code.
|
(define_expand "reload_incc"
|
(define_expand "reload_incc"
|
[(set (match_operand:CC 0 "fcc_reload_operand" "=z")
|
[(set (match_operand:CC 0 "fcc_reload_operand" "=z")
|
(match_operand:CC 1 "general_operand" ""))
|
(match_operand:CC 1 "general_operand" ""))
|
(clobber (match_operand:TF 2 "register_operand" "=&f"))]
|
(clobber (match_operand:TF 2 "register_operand" "=&f"))]
|
"ISA_HAS_8CC && TARGET_HARD_FLOAT"
|
"ISA_HAS_8CC && TARGET_HARD_FLOAT"
|
{
|
{
|
mips_expand_fcc_reload (operands[0], operands[1], operands[2]);
|
mips_expand_fcc_reload (operands[0], operands[1], operands[2]);
|
DONE;
|
DONE;
|
})
|
})
|
|
|
(define_expand "reload_outcc"
|
(define_expand "reload_outcc"
|
[(set (match_operand:CC 0 "fcc_reload_operand" "=z")
|
[(set (match_operand:CC 0 "fcc_reload_operand" "=z")
|
(match_operand:CC 1 "register_operand" ""))
|
(match_operand:CC 1 "register_operand" ""))
|
(clobber (match_operand:TF 2 "register_operand" "=&f"))]
|
(clobber (match_operand:TF 2 "register_operand" "=&f"))]
|
"ISA_HAS_8CC && TARGET_HARD_FLOAT"
|
"ISA_HAS_8CC && TARGET_HARD_FLOAT"
|
{
|
{
|
mips_expand_fcc_reload (operands[0], operands[1], operands[2]);
|
mips_expand_fcc_reload (operands[0], operands[1], operands[2]);
|
DONE;
|
DONE;
|
})
|
})
|
|
|
;; MIPS4 supports loading and storing a floating point register from
|
;; MIPS4 supports loading and storing a floating point register from
|
;; the sum of two general registers. We use two versions for each of
|
;; the sum of two general registers. We use two versions for each of
|
;; these four instructions: one where the two general registers are
|
;; these four instructions: one where the two general registers are
|
;; SImode, and one where they are DImode. This is because general
|
;; SImode, and one where they are DImode. This is because general
|
;; registers will be in SImode when they hold 32-bit values, but,
|
;; registers will be in SImode when they hold 32-bit values, but,
|
;; since the 32-bit values are always sign extended, the [ls][wd]xc1
|
;; since the 32-bit values are always sign extended, the [ls][wd]xc1
|
;; instructions will still work correctly.
|
;; instructions will still work correctly.
|
|
|
;; ??? Perhaps it would be better to support these instructions by
|
;; ??? Perhaps it would be better to support these instructions by
|
;; modifying TARGET_LEGITIMATE_ADDRESS_P and friends. However, since
|
;; modifying TARGET_LEGITIMATE_ADDRESS_P and friends. However, since
|
;; these instructions can only be used to load and store floating
|
;; these instructions can only be used to load and store floating
|
;; point registers, that would probably cause trouble in reload.
|
;; point registers, that would probably cause trouble in reload.
|
|
|
(define_insn "*_"
|
(define_insn "*_"
|
[(set (match_operand:ANYF 0 "register_operand" "=f")
|
[(set (match_operand:ANYF 0 "register_operand" "=f")
|
(mem:ANYF (plus:P (match_operand:P 1 "register_operand" "d")
|
(mem:ANYF (plus:P (match_operand:P 1 "register_operand" "d")
|
(match_operand:P 2 "register_operand" "d"))))]
|
(match_operand:P 2 "register_operand" "d"))))]
|
"ISA_HAS_FP4"
|
"ISA_HAS_FP4"
|
"\t%0,%1(%2)"
|
"\t%0,%1(%2)"
|
[(set_attr "type" "fpidxload")
|
[(set_attr "type" "fpidxload")
|
(set_attr "mode" "")])
|
(set_attr "mode" "")])
|
|
|
(define_insn "*_"
|
(define_insn "*_"
|
[(set (mem:ANYF (plus:P (match_operand:P 1 "register_operand" "d")
|
[(set (mem:ANYF (plus:P (match_operand:P 1 "register_operand" "d")
|
(match_operand:P 2 "register_operand" "d")))
|
(match_operand:P 2 "register_operand" "d")))
|
(match_operand:ANYF 0 "register_operand" "f"))]
|
(match_operand:ANYF 0 "register_operand" "f"))]
|
"ISA_HAS_FP4"
|
"ISA_HAS_FP4"
|
"\t%0,%1(%2)"
|
"\t%0,%1(%2)"
|
[(set_attr "type" "fpidxstore")
|
[(set_attr "type" "fpidxstore")
|
(set_attr "mode" "")])
|
(set_attr "mode" "")])
|
|
|
;; Scaled indexed address load.
|
;; Scaled indexed address load.
|
;; Per md.texi, we only need to look for a pattern with multiply in the
|
;; Per md.texi, we only need to look for a pattern with multiply in the
|
;; address expression, not shift.
|
;; address expression, not shift.
|
|
|
(define_insn "*lwxs"
|
(define_insn "*lwxs"
|
[(set (match_operand:IMOVE32 0 "register_operand" "=d")
|
[(set (match_operand:IMOVE32 0 "register_operand" "=d")
|
(mem:IMOVE32
|
(mem:IMOVE32
|
(plus:P (mult:P (match_operand:P 1 "register_operand" "d")
|
(plus:P (mult:P (match_operand:P 1 "register_operand" "d")
|
(const_int 4))
|
(const_int 4))
|
(match_operand:P 2 "register_operand" "d"))))]
|
(match_operand:P 2 "register_operand" "d"))))]
|
"ISA_HAS_LWXS"
|
"ISA_HAS_LWXS"
|
"lwxs\t%0,%1(%2)"
|
"lwxs\t%0,%1(%2)"
|
[(set_attr "type" "load")
|
[(set_attr "type" "load")
|
(set_attr "mode" "SI")])
|
(set_attr "mode" "SI")])
|
|
|
;; 16-bit Integer moves
|
;; 16-bit Integer moves
|
|
|
;; Unlike most other insns, the move insns can't be split with
|
;; Unlike most other insns, the move insns can't be split with
|
;; different predicates, because register spilling and other parts of
|
;; different predicates, because register spilling and other parts of
|
;; the compiler, have memoized the insn number already.
|
;; the compiler, have memoized the insn number already.
|
;; Unsigned loads are used because LOAD_EXTEND_OP returns ZERO_EXTEND.
|
;; Unsigned loads are used because LOAD_EXTEND_OP returns ZERO_EXTEND.
|
|
|
(define_expand "movhi"
|
(define_expand "movhi"
|
[(set (match_operand:HI 0 "")
|
[(set (match_operand:HI 0 "")
|
(match_operand:HI 1 ""))]
|
(match_operand:HI 1 ""))]
|
""
|
""
|
{
|
{
|
if (mips_legitimize_move (HImode, operands[0], operands[1]))
|
if (mips_legitimize_move (HImode, operands[0], operands[1]))
|
DONE;
|
DONE;
|
})
|
})
|
|
|
(define_insn "*movhi_internal"
|
(define_insn "*movhi_internal"
|
[(set (match_operand:HI 0 "nonimmediate_operand" "=d,d,d,m,*a,*d")
|
[(set (match_operand:HI 0 "nonimmediate_operand" "=d,d,d,m,*a,*d")
|
(match_operand:HI 1 "move_operand" "d,I,m,dJ,*d*J,*a"))]
|
(match_operand:HI 1 "move_operand" "d,I,m,dJ,*d*J,*a"))]
|
"!TARGET_MIPS16
|
"!TARGET_MIPS16
|
&& (register_operand (operands[0], HImode)
|
&& (register_operand (operands[0], HImode)
|
|| reg_or_0_operand (operands[1], HImode))"
|
|| reg_or_0_operand (operands[1], HImode))"
|
{ return mips_output_move (operands[0], operands[1]); }
|
{ return mips_output_move (operands[0], operands[1]); }
|
[(set_attr "move_type" "move,const,load,store,mthilo,mfhilo")
|
[(set_attr "move_type" "move,const,load,store,mthilo,mfhilo")
|
(set_attr "mode" "HI")])
|
(set_attr "mode" "HI")])
|
|
|
(define_insn "*movhi_mips16"
|
(define_insn "*movhi_mips16"
|
[(set (match_operand:HI 0 "nonimmediate_operand" "=d,y,d,d,d,d,m,*d")
|
[(set (match_operand:HI 0 "nonimmediate_operand" "=d,y,d,d,d,d,m,*d")
|
(match_operand:HI 1 "move_operand" "d,d,y,K,N,m,d,*a"))]
|
(match_operand:HI 1 "move_operand" "d,d,y,K,N,m,d,*a"))]
|
"TARGET_MIPS16
|
"TARGET_MIPS16
|
&& (register_operand (operands[0], HImode)
|
&& (register_operand (operands[0], HImode)
|
|| register_operand (operands[1], HImode))"
|
|| register_operand (operands[1], HImode))"
|
{ return mips_output_move (operands[0], operands[1]); }
|
{ return mips_output_move (operands[0], operands[1]); }
|
[(set_attr "move_type" "move,move,move,const,constN,load,store,mfhilo")
|
[(set_attr "move_type" "move,move,move,const,constN,load,store,mfhilo")
|
(set_attr "mode" "HI")])
|
(set_attr "mode" "HI")])
|
|
|
;; On the mips16, we can split lh $r,N($r) into an add and a load,
|
;; On the mips16, we can split lh $r,N($r) into an add and a load,
|
;; when the original load is a 4 byte instruction but the add and the
|
;; when the original load is a 4 byte instruction but the add and the
|
;; load are 2 2 byte instructions.
|
;; load are 2 2 byte instructions.
|
|
|
(define_split
|
(define_split
|
[(set (match_operand:HI 0 "d_operand")
|
[(set (match_operand:HI 0 "d_operand")
|
(mem:HI (plus:SI (match_dup 0)
|
(mem:HI (plus:SI (match_dup 0)
|
(match_operand:SI 1 "const_int_operand"))))]
|
(match_operand:SI 1 "const_int_operand"))))]
|
"TARGET_MIPS16 && reload_completed && !TARGET_DEBUG_D_MODE
|
"TARGET_MIPS16 && reload_completed && !TARGET_DEBUG_D_MODE
|
&& ((INTVAL (operands[1]) < 0
|
&& ((INTVAL (operands[1]) < 0
|
&& INTVAL (operands[1]) >= -0x80)
|
&& INTVAL (operands[1]) >= -0x80)
|
|| (INTVAL (operands[1]) >= 32 * 2
|
|| (INTVAL (operands[1]) >= 32 * 2
|
&& INTVAL (operands[1]) <= 31 * 2 + 0x7e)
|
&& INTVAL (operands[1]) <= 31 * 2 + 0x7e)
|
|| (INTVAL (operands[1]) >= 0
|
|| (INTVAL (operands[1]) >= 0
|
&& INTVAL (operands[1]) < 32 * 2
|
&& INTVAL (operands[1]) < 32 * 2
|
&& (INTVAL (operands[1]) & 1) != 0))"
|
&& (INTVAL (operands[1]) & 1) != 0))"
|
[(set (match_dup 0) (plus:SI (match_dup 0) (match_dup 1)))
|
[(set (match_dup 0) (plus:SI (match_dup 0) (match_dup 1)))
|
(set (match_dup 0) (mem:HI (plus:SI (match_dup 0) (match_dup 2))))]
|
(set (match_dup 0) (mem:HI (plus:SI (match_dup 0) (match_dup 2))))]
|
{
|
{
|
HOST_WIDE_INT val = INTVAL (operands[1]);
|
HOST_WIDE_INT val = INTVAL (operands[1]);
|
|
|
if (val < 0)
|
if (val < 0)
|
operands[2] = const0_rtx;
|
operands[2] = const0_rtx;
|
else if (val >= 32 * 2)
|
else if (val >= 32 * 2)
|
{
|
{
|
int off = val & 1;
|
int off = val & 1;
|
|
|
operands[1] = GEN_INT (0x7e + off);
|
operands[1] = GEN_INT (0x7e + off);
|
operands[2] = GEN_INT (val - off - 0x7e);
|
operands[2] = GEN_INT (val - off - 0x7e);
|
}
|
}
|
else
|
else
|
{
|
{
|
int off = val & 1;
|
int off = val & 1;
|
|
|
operands[1] = GEN_INT (off);
|
operands[1] = GEN_INT (off);
|
operands[2] = GEN_INT (val - off);
|
operands[2] = GEN_INT (val - off);
|
}
|
}
|
})
|
})
|
|
|
;; 8-bit Integer moves
|
;; 8-bit Integer moves
|
|
|
;; Unlike most other insns, the move insns can't be split with
|
;; Unlike most other insns, the move insns can't be split with
|
;; different predicates, because register spilling and other parts of
|
;; different predicates, because register spilling and other parts of
|
;; the compiler, have memoized the insn number already.
|
;; the compiler, have memoized the insn number already.
|
;; Unsigned loads are used because LOAD_EXTEND_OP returns ZERO_EXTEND.
|
;; Unsigned loads are used because LOAD_EXTEND_OP returns ZERO_EXTEND.
|
|
|
(define_expand "movqi"
|
(define_expand "movqi"
|
[(set (match_operand:QI 0 "")
|
[(set (match_operand:QI 0 "")
|
(match_operand:QI 1 ""))]
|
(match_operand:QI 1 ""))]
|
""
|
""
|
{
|
{
|
if (mips_legitimize_move (QImode, operands[0], operands[1]))
|
if (mips_legitimize_move (QImode, operands[0], operands[1]))
|
DONE;
|
DONE;
|
})
|
})
|
|
|
(define_insn "*movqi_internal"
|
(define_insn "*movqi_internal"
|
[(set (match_operand:QI 0 "nonimmediate_operand" "=d,d,d,m,*a,*d")
|
[(set (match_operand:QI 0 "nonimmediate_operand" "=d,d,d,m,*a,*d")
|
(match_operand:QI 1 "move_operand" "d,I,m,dJ,*d*J,*a"))]
|
(match_operand:QI 1 "move_operand" "d,I,m,dJ,*d*J,*a"))]
|
"!TARGET_MIPS16
|
"!TARGET_MIPS16
|
&& (register_operand (operands[0], QImode)
|
&& (register_operand (operands[0], QImode)
|
|| reg_or_0_operand (operands[1], QImode))"
|
|| reg_or_0_operand (operands[1], QImode))"
|
{ return mips_output_move (operands[0], operands[1]); }
|
{ return mips_output_move (operands[0], operands[1]); }
|
[(set_attr "move_type" "move,const,load,store,mthilo,mfhilo")
|
[(set_attr "move_type" "move,const,load,store,mthilo,mfhilo")
|
(set_attr "mode" "QI")])
|
(set_attr "mode" "QI")])
|
|
|
(define_insn "*movqi_mips16"
|
(define_insn "*movqi_mips16"
|
[(set (match_operand:QI 0 "nonimmediate_operand" "=d,y,d,d,d,d,m,*d")
|
[(set (match_operand:QI 0 "nonimmediate_operand" "=d,y,d,d,d,d,m,*d")
|
(match_operand:QI 1 "move_operand" "d,d,y,K,N,m,d,*a"))]
|
(match_operand:QI 1 "move_operand" "d,d,y,K,N,m,d,*a"))]
|
"TARGET_MIPS16
|
"TARGET_MIPS16
|
&& (register_operand (operands[0], QImode)
|
&& (register_operand (operands[0], QImode)
|
|| register_operand (operands[1], QImode))"
|
|| register_operand (operands[1], QImode))"
|
{ return mips_output_move (operands[0], operands[1]); }
|
{ return mips_output_move (operands[0], operands[1]); }
|
[(set_attr "move_type" "move,move,move,const,constN,load,store,mfhilo")
|
[(set_attr "move_type" "move,move,move,const,constN,load,store,mfhilo")
|
(set_attr "mode" "QI")])
|
(set_attr "mode" "QI")])
|
|
|
;; On the mips16, we can split lb $r,N($r) into an add and a load,
|
;; On the mips16, we can split lb $r,N($r) into an add and a load,
|
;; when the original load is a 4 byte instruction but the add and the
|
;; when the original load is a 4 byte instruction but the add and the
|
;; load are 2 2 byte instructions.
|
;; load are 2 2 byte instructions.
|
|
|
(define_split
|
(define_split
|
[(set (match_operand:QI 0 "d_operand")
|
[(set (match_operand:QI 0 "d_operand")
|
(mem:QI (plus:SI (match_dup 0)
|
(mem:QI (plus:SI (match_dup 0)
|
(match_operand:SI 1 "const_int_operand"))))]
|
(match_operand:SI 1 "const_int_operand"))))]
|
"TARGET_MIPS16 && reload_completed && !TARGET_DEBUG_D_MODE
|
"TARGET_MIPS16 && reload_completed && !TARGET_DEBUG_D_MODE
|
&& ((INTVAL (operands[1]) < 0
|
&& ((INTVAL (operands[1]) < 0
|
&& INTVAL (operands[1]) >= -0x80)
|
&& INTVAL (operands[1]) >= -0x80)
|
|| (INTVAL (operands[1]) >= 32
|
|| (INTVAL (operands[1]) >= 32
|
&& INTVAL (operands[1]) <= 31 + 0x7f))"
|
&& INTVAL (operands[1]) <= 31 + 0x7f))"
|
[(set (match_dup 0) (plus:SI (match_dup 0) (match_dup 1)))
|
[(set (match_dup 0) (plus:SI (match_dup 0) (match_dup 1)))
|
(set (match_dup 0) (mem:QI (plus:SI (match_dup 0) (match_dup 2))))]
|
(set (match_dup 0) (mem:QI (plus:SI (match_dup 0) (match_dup 2))))]
|
{
|
{
|
HOST_WIDE_INT val = INTVAL (operands[1]);
|
HOST_WIDE_INT val = INTVAL (operands[1]);
|
|
|
if (val < 0)
|
if (val < 0)
|
operands[2] = const0_rtx;
|
operands[2] = const0_rtx;
|
else
|
else
|
{
|
{
|
operands[1] = GEN_INT (0x7f);
|
operands[1] = GEN_INT (0x7f);
|
operands[2] = GEN_INT (val - 0x7f);
|
operands[2] = GEN_INT (val - 0x7f);
|
}
|
}
|
})
|
})
|
|
|
;; 32-bit floating point moves
|
;; 32-bit floating point moves
|
|
|
(define_expand "movsf"
|
(define_expand "movsf"
|
[(set (match_operand:SF 0 "")
|
[(set (match_operand:SF 0 "")
|
(match_operand:SF 1 ""))]
|
(match_operand:SF 1 ""))]
|
""
|
""
|
{
|
{
|
if (mips_legitimize_move (SFmode, operands[0], operands[1]))
|
if (mips_legitimize_move (SFmode, operands[0], operands[1]))
|
DONE;
|
DONE;
|
})
|
})
|
|
|
(define_insn "*movsf_hardfloat"
|
(define_insn "*movsf_hardfloat"
|
[(set (match_operand:SF 0 "nonimmediate_operand" "=f,f,f,m,m,*f,*d,*d,*d,*m")
|
[(set (match_operand:SF 0 "nonimmediate_operand" "=f,f,f,m,m,*f,*d,*d,*d,*m")
|
(match_operand:SF 1 "move_operand" "f,G,m,f,G,*d,*f,*G*d,*m,*d"))]
|
(match_operand:SF 1 "move_operand" "f,G,m,f,G,*d,*f,*G*d,*m,*d"))]
|
"TARGET_HARD_FLOAT
|
"TARGET_HARD_FLOAT
|
&& (register_operand (operands[0], SFmode)
|
&& (register_operand (operands[0], SFmode)
|
|| reg_or_0_operand (operands[1], SFmode))"
|
|| reg_or_0_operand (operands[1], SFmode))"
|
{ return mips_output_move (operands[0], operands[1]); }
|
{ return mips_output_move (operands[0], operands[1]); }
|
[(set_attr "move_type" "fmove,mtc,fpload,fpstore,store,mtc,mfc,move,load,store")
|
[(set_attr "move_type" "fmove,mtc,fpload,fpstore,store,mtc,mfc,move,load,store")
|
(set_attr "mode" "SF")])
|
(set_attr "mode" "SF")])
|
|
|
(define_insn "*movsf_softfloat"
|
(define_insn "*movsf_softfloat"
|
[(set (match_operand:SF 0 "nonimmediate_operand" "=d,d,m")
|
[(set (match_operand:SF 0 "nonimmediate_operand" "=d,d,m")
|
(match_operand:SF 1 "move_operand" "Gd,m,d"))]
|
(match_operand:SF 1 "move_operand" "Gd,m,d"))]
|
"TARGET_SOFT_FLOAT && !TARGET_MIPS16
|
"TARGET_SOFT_FLOAT && !TARGET_MIPS16
|
&& (register_operand (operands[0], SFmode)
|
&& (register_operand (operands[0], SFmode)
|
|| reg_or_0_operand (operands[1], SFmode))"
|
|| reg_or_0_operand (operands[1], SFmode))"
|
{ return mips_output_move (operands[0], operands[1]); }
|
{ return mips_output_move (operands[0], operands[1]); }
|
[(set_attr "move_type" "move,load,store")
|
[(set_attr "move_type" "move,load,store")
|
(set_attr "mode" "SF")])
|
(set_attr "mode" "SF")])
|
|
|
(define_insn "*movsf_mips16"
|
(define_insn "*movsf_mips16"
|
[(set (match_operand:SF 0 "nonimmediate_operand" "=d,y,d,d,m")
|
[(set (match_operand:SF 0 "nonimmediate_operand" "=d,y,d,d,m")
|
(match_operand:SF 1 "move_operand" "d,d,y,m,d"))]
|
(match_operand:SF 1 "move_operand" "d,d,y,m,d"))]
|
"TARGET_MIPS16
|
"TARGET_MIPS16
|
&& (register_operand (operands[0], SFmode)
|
&& (register_operand (operands[0], SFmode)
|
|| register_operand (operands[1], SFmode))"
|
|| register_operand (operands[1], SFmode))"
|
{ return mips_output_move (operands[0], operands[1]); }
|
{ return mips_output_move (operands[0], operands[1]); }
|
[(set_attr "move_type" "move,move,move,load,store")
|
[(set_attr "move_type" "move,move,move,load,store")
|
(set_attr "mode" "SF")])
|
(set_attr "mode" "SF")])
|
|
|
;; 64-bit floating point moves
|
;; 64-bit floating point moves
|
|
|
(define_expand "movdf"
|
(define_expand "movdf"
|
[(set (match_operand:DF 0 "")
|
[(set (match_operand:DF 0 "")
|
(match_operand:DF 1 ""))]
|
(match_operand:DF 1 ""))]
|
""
|
""
|
{
|
{
|
if (mips_legitimize_move (DFmode, operands[0], operands[1]))
|
if (mips_legitimize_move (DFmode, operands[0], operands[1]))
|
DONE;
|
DONE;
|
})
|
})
|
|
|
(define_insn "*movdf_hardfloat"
|
(define_insn "*movdf_hardfloat"
|
[(set (match_operand:DF 0 "nonimmediate_operand" "=f,f,f,m,m,*f,*d,*d,*d,*m")
|
[(set (match_operand:DF 0 "nonimmediate_operand" "=f,f,f,m,m,*f,*d,*d,*d,*m")
|
(match_operand:DF 1 "move_operand" "f,G,m,f,G,*d,*f,*d*G,*m,*d"))]
|
(match_operand:DF 1 "move_operand" "f,G,m,f,G,*d,*f,*d*G,*m,*d"))]
|
"TARGET_HARD_FLOAT && TARGET_DOUBLE_FLOAT
|
"TARGET_HARD_FLOAT && TARGET_DOUBLE_FLOAT
|
&& (register_operand (operands[0], DFmode)
|
&& (register_operand (operands[0], DFmode)
|
|| reg_or_0_operand (operands[1], DFmode))"
|
|| reg_or_0_operand (operands[1], DFmode))"
|
{ return mips_output_move (operands[0], operands[1]); }
|
{ return mips_output_move (operands[0], operands[1]); }
|
[(set_attr "move_type" "fmove,mtc,fpload,fpstore,store,mtc,mfc,move,load,store")
|
[(set_attr "move_type" "fmove,mtc,fpload,fpstore,store,mtc,mfc,move,load,store")
|
(set_attr "mode" "DF")])
|
(set_attr "mode" "DF")])
|
|
|
(define_insn "*movdf_softfloat"
|
(define_insn "*movdf_softfloat"
|
[(set (match_operand:DF 0 "nonimmediate_operand" "=d,d,m")
|
[(set (match_operand:DF 0 "nonimmediate_operand" "=d,d,m")
|
(match_operand:DF 1 "move_operand" "dG,m,dG"))]
|
(match_operand:DF 1 "move_operand" "dG,m,dG"))]
|
"(TARGET_SOFT_FLOAT || TARGET_SINGLE_FLOAT) && !TARGET_MIPS16
|
"(TARGET_SOFT_FLOAT || TARGET_SINGLE_FLOAT) && !TARGET_MIPS16
|
&& (register_operand (operands[0], DFmode)
|
&& (register_operand (operands[0], DFmode)
|
|| reg_or_0_operand (operands[1], DFmode))"
|
|| reg_or_0_operand (operands[1], DFmode))"
|
{ return mips_output_move (operands[0], operands[1]); }
|
{ return mips_output_move (operands[0], operands[1]); }
|
[(set_attr "move_type" "move,load,store")
|
[(set_attr "move_type" "move,load,store")
|
(set_attr "mode" "DF")])
|
(set_attr "mode" "DF")])
|
|
|
(define_insn "*movdf_mips16"
|
(define_insn "*movdf_mips16"
|
[(set (match_operand:DF 0 "nonimmediate_operand" "=d,y,d,d,m")
|
[(set (match_operand:DF 0 "nonimmediate_operand" "=d,y,d,d,m")
|
(match_operand:DF 1 "move_operand" "d,d,y,m,d"))]
|
(match_operand:DF 1 "move_operand" "d,d,y,m,d"))]
|
"TARGET_MIPS16
|
"TARGET_MIPS16
|
&& (register_operand (operands[0], DFmode)
|
&& (register_operand (operands[0], DFmode)
|
|| register_operand (operands[1], DFmode))"
|
|| register_operand (operands[1], DFmode))"
|
{ return mips_output_move (operands[0], operands[1]); }
|
{ return mips_output_move (operands[0], operands[1]); }
|
[(set_attr "move_type" "move,move,move,load,store")
|
[(set_attr "move_type" "move,move,move,load,store")
|
(set_attr "mode" "DF")])
|
(set_attr "mode" "DF")])
|
|
|
;; 128-bit integer moves
|
;; 128-bit integer moves
|
|
|
(define_expand "movti"
|
(define_expand "movti"
|
[(set (match_operand:TI 0)
|
[(set (match_operand:TI 0)
|
(match_operand:TI 1))]
|
(match_operand:TI 1))]
|
"TARGET_64BIT"
|
"TARGET_64BIT"
|
{
|
{
|
if (mips_legitimize_move (TImode, operands[0], operands[1]))
|
if (mips_legitimize_move (TImode, operands[0], operands[1]))
|
DONE;
|
DONE;
|
})
|
})
|
|
|
(define_insn "*movti"
|
(define_insn "*movti"
|
[(set (match_operand:TI 0 "nonimmediate_operand" "=d,d,d,m,*a,*d")
|
[(set (match_operand:TI 0 "nonimmediate_operand" "=d,d,d,m,*a,*d")
|
(match_operand:TI 1 "move_operand" "d,i,m,dJ,*d*J,*a"))]
|
(match_operand:TI 1 "move_operand" "d,i,m,dJ,*d*J,*a"))]
|
"TARGET_64BIT
|
"TARGET_64BIT
|
&& !TARGET_MIPS16
|
&& !TARGET_MIPS16
|
&& (register_operand (operands[0], TImode)
|
&& (register_operand (operands[0], TImode)
|
|| reg_or_0_operand (operands[1], TImode))"
|
|| reg_or_0_operand (operands[1], TImode))"
|
"#"
|
"#"
|
[(set_attr "move_type" "move,const,load,store,mthilo,mfhilo")
|
[(set_attr "move_type" "move,const,load,store,mthilo,mfhilo")
|
(set_attr "mode" "TI")])
|
(set_attr "mode" "TI")])
|
|
|
(define_insn "*movti_mips16"
|
(define_insn "*movti_mips16"
|
[(set (match_operand:TI 0 "nonimmediate_operand" "=d,y,d,d,d,d,m,*d")
|
[(set (match_operand:TI 0 "nonimmediate_operand" "=d,y,d,d,d,d,m,*d")
|
(match_operand:TI 1 "move_operand" "d,d,y,K,N,m,d,*a"))]
|
(match_operand:TI 1 "move_operand" "d,d,y,K,N,m,d,*a"))]
|
"TARGET_64BIT
|
"TARGET_64BIT
|
&& TARGET_MIPS16
|
&& TARGET_MIPS16
|
&& (register_operand (operands[0], TImode)
|
&& (register_operand (operands[0], TImode)
|
|| register_operand (operands[1], TImode))"
|
|| register_operand (operands[1], TImode))"
|
"#"
|
"#"
|
[(set_attr "move_type" "move,move,move,const,constN,load,store,mfhilo")
|
[(set_attr "move_type" "move,move,move,const,constN,load,store,mfhilo")
|
(set_attr "mode" "TI")])
|
(set_attr "mode" "TI")])
|
|
|
;; 128-bit floating point moves
|
;; 128-bit floating point moves
|
|
|
(define_expand "movtf"
|
(define_expand "movtf"
|
[(set (match_operand:TF 0)
|
[(set (match_operand:TF 0)
|
(match_operand:TF 1))]
|
(match_operand:TF 1))]
|
"TARGET_64BIT"
|
"TARGET_64BIT"
|
{
|
{
|
if (mips_legitimize_move (TFmode, operands[0], operands[1]))
|
if (mips_legitimize_move (TFmode, operands[0], operands[1]))
|
DONE;
|
DONE;
|
})
|
})
|
|
|
;; This pattern handles both hard- and soft-float cases.
|
;; This pattern handles both hard- and soft-float cases.
|
(define_insn "*movtf"
|
(define_insn "*movtf"
|
[(set (match_operand:TF 0 "nonimmediate_operand" "=d,d,m,f,d,f,m")
|
[(set (match_operand:TF 0 "nonimmediate_operand" "=d,d,m,f,d,f,m")
|
(match_operand:TF 1 "move_operand" "dG,m,dG,dG,f,m,f"))]
|
(match_operand:TF 1 "move_operand" "dG,m,dG,dG,f,m,f"))]
|
"TARGET_64BIT
|
"TARGET_64BIT
|
&& !TARGET_MIPS16
|
&& !TARGET_MIPS16
|
&& (register_operand (operands[0], TFmode)
|
&& (register_operand (operands[0], TFmode)
|
|| reg_or_0_operand (operands[1], TFmode))"
|
|| reg_or_0_operand (operands[1], TFmode))"
|
"#"
|
"#"
|
[(set_attr "move_type" "move,load,store,mtc,mfc,fpload,fpstore")
|
[(set_attr "move_type" "move,load,store,mtc,mfc,fpload,fpstore")
|
(set_attr "mode" "TF")])
|
(set_attr "mode" "TF")])
|
|
|
(define_insn "*movtf_mips16"
|
(define_insn "*movtf_mips16"
|
[(set (match_operand:TF 0 "nonimmediate_operand" "=d,y,d,d,m")
|
[(set (match_operand:TF 0 "nonimmediate_operand" "=d,y,d,d,m")
|
(match_operand:TF 1 "move_operand" "d,d,y,m,d"))]
|
(match_operand:TF 1 "move_operand" "d,d,y,m,d"))]
|
"TARGET_64BIT
|
"TARGET_64BIT
|
&& TARGET_MIPS16
|
&& TARGET_MIPS16
|
&& (register_operand (operands[0], TFmode)
|
&& (register_operand (operands[0], TFmode)
|
|| register_operand (operands[1], TFmode))"
|
|| register_operand (operands[1], TFmode))"
|
"#"
|
"#"
|
[(set_attr "move_type" "move,move,move,load,store")
|
[(set_attr "move_type" "move,move,move,load,store")
|
(set_attr "mode" "TF")])
|
(set_attr "mode" "TF")])
|
|
|
(define_split
|
(define_split
|
[(set (match_operand:MOVE64 0 "nonimmediate_operand")
|
[(set (match_operand:MOVE64 0 "nonimmediate_operand")
|
(match_operand:MOVE64 1 "move_operand"))]
|
(match_operand:MOVE64 1 "move_operand"))]
|
"reload_completed && !TARGET_64BIT
|
"reload_completed && !TARGET_64BIT
|
&& mips_split_64bit_move_p (operands[0], operands[1])"
|
&& mips_split_64bit_move_p (operands[0], operands[1])"
|
[(const_int 0)]
|
[(const_int 0)]
|
{
|
{
|
mips_split_doubleword_move (operands[0], operands[1]);
|
mips_split_doubleword_move (operands[0], operands[1]);
|
DONE;
|
DONE;
|
})
|
})
|
|
|
(define_split
|
(define_split
|
[(set (match_operand:MOVE128 0 "nonimmediate_operand")
|
[(set (match_operand:MOVE128 0 "nonimmediate_operand")
|
(match_operand:MOVE128 1 "move_operand"))]
|
(match_operand:MOVE128 1 "move_operand"))]
|
"TARGET_64BIT && reload_completed"
|
"TARGET_64BIT && reload_completed"
|
[(const_int 0)]
|
[(const_int 0)]
|
{
|
{
|
mips_split_doubleword_move (operands[0], operands[1]);
|
mips_split_doubleword_move (operands[0], operands[1]);
|
DONE;
|
DONE;
|
})
|
})
|
|
|
;; When generating mips16 code, split moves of negative constants into
|
;; When generating mips16 code, split moves of negative constants into
|
;; a positive "li" followed by a negation.
|
;; a positive "li" followed by a negation.
|
(define_split
|
(define_split
|
[(set (match_operand 0 "d_operand")
|
[(set (match_operand 0 "d_operand")
|
(match_operand 1 "const_int_operand"))]
|
(match_operand 1 "const_int_operand"))]
|
"TARGET_MIPS16 && reload_completed && INTVAL (operands[1]) < 0"
|
"TARGET_MIPS16 && reload_completed && INTVAL (operands[1]) < 0"
|
[(set (match_dup 2)
|
[(set (match_dup 2)
|
(match_dup 3))
|
(match_dup 3))
|
(set (match_dup 2)
|
(set (match_dup 2)
|
(neg:SI (match_dup 2)))]
|
(neg:SI (match_dup 2)))]
|
{
|
{
|
operands[2] = gen_lowpart (SImode, operands[0]);
|
operands[2] = gen_lowpart (SImode, operands[0]);
|
operands[3] = GEN_INT (-INTVAL (operands[1]));
|
operands[3] = GEN_INT (-INTVAL (operands[1]));
|
})
|
})
|
|
|
;; 64-bit paired-single floating point moves
|
;; 64-bit paired-single floating point moves
|
|
|
(define_expand "movv2sf"
|
(define_expand "movv2sf"
|
[(set (match_operand:V2SF 0)
|
[(set (match_operand:V2SF 0)
|
(match_operand:V2SF 1))]
|
(match_operand:V2SF 1))]
|
"TARGET_HARD_FLOAT && TARGET_PAIRED_SINGLE_FLOAT"
|
"TARGET_HARD_FLOAT && TARGET_PAIRED_SINGLE_FLOAT"
|
{
|
{
|
if (mips_legitimize_move (V2SFmode, operands[0], operands[1]))
|
if (mips_legitimize_move (V2SFmode, operands[0], operands[1]))
|
DONE;
|
DONE;
|
})
|
})
|
|
|
(define_insn "*movv2sf"
|
(define_insn "*movv2sf"
|
[(set (match_operand:V2SF 0 "nonimmediate_operand" "=f,f,f,m,m,*f,*d,*d,*d,*m")
|
[(set (match_operand:V2SF 0 "nonimmediate_operand" "=f,f,f,m,m,*f,*d,*d,*d,*m")
|
(match_operand:V2SF 1 "move_operand" "f,YG,m,f,YG,*d,*f,*d*YG,*m,*d"))]
|
(match_operand:V2SF 1 "move_operand" "f,YG,m,f,YG,*d,*f,*d*YG,*m,*d"))]
|
"TARGET_HARD_FLOAT
|
"TARGET_HARD_FLOAT
|
&& TARGET_PAIRED_SINGLE_FLOAT
|
&& TARGET_PAIRED_SINGLE_FLOAT
|
&& (register_operand (operands[0], V2SFmode)
|
&& (register_operand (operands[0], V2SFmode)
|
|| reg_or_0_operand (operands[1], V2SFmode))"
|
|| reg_or_0_operand (operands[1], V2SFmode))"
|
{ return mips_output_move (operands[0], operands[1]); }
|
{ return mips_output_move (operands[0], operands[1]); }
|
[(set_attr "move_type" "fmove,mtc,fpload,fpstore,store,mtc,mfc,move,load,store")
|
[(set_attr "move_type" "fmove,mtc,fpload,fpstore,store,mtc,mfc,move,load,store")
|
(set_attr "mode" "DF")])
|
(set_attr "mode" "DF")])
|
|
|
;; Extract the high part of a HI/LO value. See mips_hard_regno_mode_ok_p
|
;; Extract the high part of a HI/LO value. See mips_hard_regno_mode_ok_p
|
;; for the reason why we can't just use (reg:GPR HI_REGNUM).
|
;; for the reason why we can't just use (reg:GPR HI_REGNUM).
|
;;
|
;;
|
;; When generating VR4120 or VR4130 code, we use MACCHI and DMACCHI
|
;; When generating VR4120 or VR4130 code, we use MACCHI and DMACCHI
|
;; instead of MFHI. This avoids both the normal MIPS III hi/lo hazards
|
;; instead of MFHI. This avoids both the normal MIPS III hi/lo hazards
|
;; and the errata related to -mfix-vr4130.
|
;; and the errata related to -mfix-vr4130.
|
(define_insn "mfhi_"
|
(define_insn "mfhi_"
|
[(set (match_operand:GPR 0 "register_operand" "=d")
|
[(set (match_operand:GPR 0 "register_operand" "=d")
|
(unspec:GPR [(match_operand:HILO 1 "register_operand" "x")]
|
(unspec:GPR [(match_operand:HILO 1 "register_operand" "x")]
|
UNSPEC_MFHI))]
|
UNSPEC_MFHI))]
|
""
|
""
|
{ return ISA_HAS_MACCHI ? "macchi\t%0,%.,%." : "mfhi\t%0"; }
|
{ return ISA_HAS_MACCHI ? "macchi\t%0,%.,%." : "mfhi\t%0"; }
|
[(set_attr "move_type" "mfhilo")
|
[(set_attr "move_type" "mfhilo")
|
(set_attr "mode" "")])
|
(set_attr "mode" "")])
|
|
|
;; Set the high part of a HI/LO value, given that the low part has
|
;; Set the high part of a HI/LO value, given that the low part has
|
;; already been set. See mips_hard_regno_mode_ok_p for the reason
|
;; already been set. See mips_hard_regno_mode_ok_p for the reason
|
;; why we can't just use (reg:GPR HI_REGNUM).
|
;; why we can't just use (reg:GPR HI_REGNUM).
|
(define_insn "mthi_"
|
(define_insn "mthi_"
|
[(set (match_operand:HILO 0 "register_operand" "=x")
|
[(set (match_operand:HILO 0 "register_operand" "=x")
|
(unspec:HILO [(match_operand:GPR 1 "reg_or_0_operand" "dJ")
|
(unspec:HILO [(match_operand:GPR 1 "reg_or_0_operand" "dJ")
|
(match_operand:GPR 2 "register_operand" "l")]
|
(match_operand:GPR 2 "register_operand" "l")]
|
UNSPEC_MTHI))]
|
UNSPEC_MTHI))]
|
""
|
""
|
"mthi\t%z1"
|
"mthi\t%z1"
|
[(set_attr "move_type" "mthilo")
|
[(set_attr "move_type" "mthilo")
|
(set_attr "mode" "SI")])
|
(set_attr "mode" "SI")])
|
|
|
;; Emit a doubleword move in which exactly one of the operands is
|
;; Emit a doubleword move in which exactly one of the operands is
|
;; a floating-point register. We can't just emit two normal moves
|
;; a floating-point register. We can't just emit two normal moves
|
;; because of the constraints imposed by the FPU register model;
|
;; because of the constraints imposed by the FPU register model;
|
;; see mips_cannot_change_mode_class for details. Instead, we keep
|
;; see mips_cannot_change_mode_class for details. Instead, we keep
|
;; the FPR whole and use special patterns to refer to each word of
|
;; the FPR whole and use special patterns to refer to each word of
|
;; the other operand.
|
;; the other operand.
|
|
|
(define_expand "move_doubleword_fpr"
|
(define_expand "move_doubleword_fpr"
|
[(set (match_operand:SPLITF 0)
|
[(set (match_operand:SPLITF 0)
|
(match_operand:SPLITF 1))]
|
(match_operand:SPLITF 1))]
|
""
|
""
|
{
|
{
|
if (FP_REG_RTX_P (operands[0]))
|
if (FP_REG_RTX_P (operands[0]))
|
{
|
{
|
rtx low = mips_subword (operands[1], 0);
|
rtx low = mips_subword (operands[1], 0);
|
rtx high = mips_subword (operands[1], 1);
|
rtx high = mips_subword (operands[1], 1);
|
emit_insn (gen_load_low (operands[0], low));
|
emit_insn (gen_load_low (operands[0], low));
|
if (TARGET_FLOAT64 && !TARGET_64BIT)
|
if (TARGET_FLOAT64 && !TARGET_64BIT)
|
emit_insn (gen_mthc1 (operands[0], high, operands[0]));
|
emit_insn (gen_mthc1 (operands[0], high, operands[0]));
|
else
|
else
|
emit_insn (gen_load_high (operands[0], high, operands[0]));
|
emit_insn (gen_load_high (operands[0], high, operands[0]));
|
}
|
}
|
else
|
else
|
{
|
{
|
rtx low = mips_subword (operands[0], 0);
|
rtx low = mips_subword (operands[0], 0);
|
rtx high = mips_subword (operands[0], 1);
|
rtx high = mips_subword (operands[0], 1);
|
emit_insn (gen_store_word (low, operands[1], const0_rtx));
|
emit_insn (gen_store_word (low, operands[1], const0_rtx));
|
if (TARGET_FLOAT64 && !TARGET_64BIT)
|
if (TARGET_FLOAT64 && !TARGET_64BIT)
|
emit_insn (gen_mfhc1 (high, operands[1]));
|
emit_insn (gen_mfhc1 (high, operands[1]));
|
else
|
else
|
emit_insn (gen_store_word (high, operands[1], const1_rtx));
|
emit_insn (gen_store_word (high, operands[1], const1_rtx));
|
}
|
}
|
DONE;
|
DONE;
|
})
|
})
|
|
|
;; Load the low word of operand 0 with operand 1.
|
;; Load the low word of operand 0 with operand 1.
|
(define_insn "load_low"
|
(define_insn "load_low"
|
[(set (match_operand:SPLITF 0 "register_operand" "=f,f")
|
[(set (match_operand:SPLITF 0 "register_operand" "=f,f")
|
(unspec:SPLITF [(match_operand: 1 "general_operand" "dJ,m")]
|
(unspec:SPLITF [(match_operand: 1 "general_operand" "dJ,m")]
|
UNSPEC_LOAD_LOW))]
|
UNSPEC_LOAD_LOW))]
|
"TARGET_HARD_FLOAT"
|
"TARGET_HARD_FLOAT"
|
{
|
{
|
operands[0] = mips_subword (operands[0], 0);
|
operands[0] = mips_subword (operands[0], 0);
|
return mips_output_move (operands[0], operands[1]);
|
return mips_output_move (operands[0], operands[1]);
|
}
|
}
|
[(set_attr "move_type" "mtc,fpload")
|
[(set_attr "move_type" "mtc,fpload")
|
(set_attr "mode" "")])
|
(set_attr "mode" "")])
|
|
|
;; Load the high word of operand 0 from operand 1, preserving the value
|
;; Load the high word of operand 0 from operand 1, preserving the value
|
;; in the low word.
|
;; in the low word.
|
(define_insn "load_high"
|
(define_insn "load_high"
|
[(set (match_operand:SPLITF 0 "register_operand" "=f,f")
|
[(set (match_operand:SPLITF 0 "register_operand" "=f,f")
|
(unspec:SPLITF [(match_operand: 1 "general_operand" "dJ,m")
|
(unspec:SPLITF [(match_operand: 1 "general_operand" "dJ,m")
|
(match_operand:SPLITF 2 "register_operand" "0,0")]
|
(match_operand:SPLITF 2 "register_operand" "0,0")]
|
UNSPEC_LOAD_HIGH))]
|
UNSPEC_LOAD_HIGH))]
|
"TARGET_HARD_FLOAT"
|
"TARGET_HARD_FLOAT"
|
{
|
{
|
operands[0] = mips_subword (operands[0], 1);
|
operands[0] = mips_subword (operands[0], 1);
|
return mips_output_move (operands[0], operands[1]);
|
return mips_output_move (operands[0], operands[1]);
|
}
|
}
|
[(set_attr "move_type" "mtc,fpload")
|
[(set_attr "move_type" "mtc,fpload")
|
(set_attr "mode" "")])
|
(set_attr "mode" "")])
|
|
|
;; Store one word of operand 1 in operand 0. Operand 2 is 1 to store the
|
;; Store one word of operand 1 in operand 0. Operand 2 is 1 to store the
|
;; high word and 0 to store the low word.
|
;; high word and 0 to store the low word.
|
(define_insn "store_word"
|
(define_insn "store_word"
|
[(set (match_operand: 0 "nonimmediate_operand" "=d,m")
|
[(set (match_operand: 0 "nonimmediate_operand" "=d,m")
|
(unspec: [(match_operand:SPLITF 1 "register_operand" "f,f")
|
(unspec: [(match_operand:SPLITF 1 "register_operand" "f,f")
|
(match_operand 2 "const_int_operand")]
|
(match_operand 2 "const_int_operand")]
|
UNSPEC_STORE_WORD))]
|
UNSPEC_STORE_WORD))]
|
"TARGET_HARD_FLOAT"
|
"TARGET_HARD_FLOAT"
|
{
|
{
|
operands[1] = mips_subword (operands[1], INTVAL (operands[2]));
|
operands[1] = mips_subword (operands[1], INTVAL (operands[2]));
|
return mips_output_move (operands[0], operands[1]);
|
return mips_output_move (operands[0], operands[1]);
|
}
|
}
|
[(set_attr "move_type" "mfc,fpstore")
|
[(set_attr "move_type" "mfc,fpstore")
|
(set_attr "mode" "")])
|
(set_attr "mode" "")])
|
|
|
;; Move operand 1 to the high word of operand 0 using mthc1, preserving the
|
;; Move operand 1 to the high word of operand 0 using mthc1, preserving the
|
;; value in the low word.
|
;; value in the low word.
|
(define_insn "mthc1"
|
(define_insn "mthc1"
|
[(set (match_operand:SPLITF 0 "register_operand" "=f")
|
[(set (match_operand:SPLITF 0 "register_operand" "=f")
|
(unspec:SPLITF [(match_operand: 1 "reg_or_0_operand" "dJ")
|
(unspec:SPLITF [(match_operand: 1 "reg_or_0_operand" "dJ")
|
(match_operand:SPLITF 2 "register_operand" "0")]
|
(match_operand:SPLITF 2 "register_operand" "0")]
|
UNSPEC_MTHC1))]
|
UNSPEC_MTHC1))]
|
"TARGET_HARD_FLOAT && ISA_HAS_MXHC1"
|
"TARGET_HARD_FLOAT && ISA_HAS_MXHC1"
|
"mthc1\t%z1,%0"
|
"mthc1\t%z1,%0"
|
[(set_attr "move_type" "mtc")
|
[(set_attr "move_type" "mtc")
|
(set_attr "mode" "")])
|
(set_attr "mode" "")])
|
|
|
;; Move high word of operand 1 to operand 0 using mfhc1.
|
;; Move high word of operand 1 to operand 0 using mfhc1.
|
(define_insn "mfhc1"
|
(define_insn "mfhc1"
|
[(set (match_operand: 0 "register_operand" "=d")
|
[(set (match_operand: 0 "register_operand" "=d")
|
(unspec: [(match_operand:SPLITF 1 "register_operand" "f")]
|
(unspec: [(match_operand:SPLITF 1 "register_operand" "f")]
|
UNSPEC_MFHC1))]
|
UNSPEC_MFHC1))]
|
"TARGET_HARD_FLOAT && ISA_HAS_MXHC1"
|
"TARGET_HARD_FLOAT && ISA_HAS_MXHC1"
|
"mfhc1\t%0,%1"
|
"mfhc1\t%0,%1"
|
[(set_attr "move_type" "mfc")
|
[(set_attr "move_type" "mfc")
|
(set_attr "mode" "")])
|
(set_attr "mode" "")])
|
|
|
;; Move a constant that satisfies CONST_GP_P into operand 0.
|
;; Move a constant that satisfies CONST_GP_P into operand 0.
|
(define_expand "load_const_gp_"
|
(define_expand "load_const_gp_"
|
[(set (match_operand:P 0 "register_operand" "=d")
|
[(set (match_operand:P 0 "register_operand" "=d")
|
(const:P (unspec:P [(const_int 0)] UNSPEC_GP)))])
|
(const:P (unspec:P [(const_int 0)] UNSPEC_GP)))])
|
|
|
;; Insn to initialize $gp for n32/n64 abicalls. Operand 0 is the offset
|
;; Insn to initialize $gp for n32/n64 abicalls. Operand 0 is the offset
|
;; of _gp from the start of this function. Operand 1 is the incoming
|
;; of _gp from the start of this function. Operand 1 is the incoming
|
;; function address.
|
;; function address.
|
(define_insn_and_split "loadgp_newabi_"
|
(define_insn_and_split "loadgp_newabi_"
|
[(set (match_operand:P 0 "register_operand" "=d")
|
[(set (match_operand:P 0 "register_operand" "=d")
|
(unspec:P [(match_operand:P 1)
|
(unspec:P [(match_operand:P 1)
|
(match_operand:P 2 "register_operand" "d")]
|
(match_operand:P 2 "register_operand" "d")]
|
UNSPEC_LOADGP))]
|
UNSPEC_LOADGP))]
|
"mips_current_loadgp_style () == LOADGP_NEWABI"
|
"mips_current_loadgp_style () == LOADGP_NEWABI"
|
{ return mips_must_initialize_gp_p () ? "#" : ""; }
|
{ return mips_must_initialize_gp_p () ? "#" : ""; }
|
"&& mips_must_initialize_gp_p ()"
|
"&& mips_must_initialize_gp_p ()"
|
[(set (match_dup 0) (match_dup 3))
|
[(set (match_dup 0) (match_dup 3))
|
(set (match_dup 0) (match_dup 4))
|
(set (match_dup 0) (match_dup 4))
|
(set (match_dup 0) (match_dup 5))]
|
(set (match_dup 0) (match_dup 5))]
|
{
|
{
|
operands[3] = gen_rtx_HIGH (Pmode, operands[1]);
|
operands[3] = gen_rtx_HIGH (Pmode, operands[1]);
|
operands[4] = gen_rtx_PLUS (Pmode, operands[0], operands[2]);
|
operands[4] = gen_rtx_PLUS (Pmode, operands[0], operands[2]);
|
operands[5] = gen_rtx_LO_SUM (Pmode, operands[0], operands[1]);
|
operands[5] = gen_rtx_LO_SUM (Pmode, operands[0], operands[1]);
|
}
|
}
|
[(set_attr "type" "ghost")])
|
[(set_attr "type" "ghost")])
|
|
|
;; Likewise, for -mno-shared code. Operand 0 is the __gnu_local_gp symbol.
|
;; Likewise, for -mno-shared code. Operand 0 is the __gnu_local_gp symbol.
|
(define_insn_and_split "loadgp_absolute_"
|
(define_insn_and_split "loadgp_absolute_"
|
[(set (match_operand:P 0 "register_operand" "=d")
|
[(set (match_operand:P 0 "register_operand" "=d")
|
(unspec:P [(match_operand:P 1)] UNSPEC_LOADGP))]
|
(unspec:P [(match_operand:P 1)] UNSPEC_LOADGP))]
|
"mips_current_loadgp_style () == LOADGP_ABSOLUTE"
|
"mips_current_loadgp_style () == LOADGP_ABSOLUTE"
|
{ return mips_must_initialize_gp_p () ? "#" : ""; }
|
{ return mips_must_initialize_gp_p () ? "#" : ""; }
|
"&& mips_must_initialize_gp_p ()"
|
"&& mips_must_initialize_gp_p ()"
|
[(const_int 0)]
|
[(const_int 0)]
|
{
|
{
|
mips_emit_move (operands[0], operands[1]);
|
mips_emit_move (operands[0], operands[1]);
|
DONE;
|
DONE;
|
}
|
}
|
[(set_attr "type" "ghost")])
|
[(set_attr "type" "ghost")])
|
|
|
;; This blockage instruction prevents the gp load from being
|
;; This blockage instruction prevents the gp load from being
|
;; scheduled after an implicit use of gp. It also prevents
|
;; scheduled after an implicit use of gp. It also prevents
|
;; the load from being deleted as dead.
|
;; the load from being deleted as dead.
|
(define_insn "loadgp_blockage"
|
(define_insn "loadgp_blockage"
|
[(unspec_volatile [(reg:SI 28)] UNSPEC_BLOCKAGE)]
|
[(unspec_volatile [(reg:SI 28)] UNSPEC_BLOCKAGE)]
|
""
|
""
|
""
|
""
|
[(set_attr "type" "ghost")])
|
[(set_attr "type" "ghost")])
|
|
|
;; Initialize $gp for RTP PIC. Operand 0 is the __GOTT_BASE__ symbol
|
;; Initialize $gp for RTP PIC. Operand 0 is the __GOTT_BASE__ symbol
|
;; and operand 1 is the __GOTT_INDEX__ symbol.
|
;; and operand 1 is the __GOTT_INDEX__ symbol.
|
(define_insn_and_split "loadgp_rtp_"
|
(define_insn_and_split "loadgp_rtp_"
|
[(set (match_operand:P 0 "register_operand" "=d")
|
[(set (match_operand:P 0 "register_operand" "=d")
|
(unspec:P [(match_operand:P 1 "symbol_ref_operand")
|
(unspec:P [(match_operand:P 1 "symbol_ref_operand")
|
(match_operand:P 2 "symbol_ref_operand")]
|
(match_operand:P 2 "symbol_ref_operand")]
|
UNSPEC_LOADGP))]
|
UNSPEC_LOADGP))]
|
"mips_current_loadgp_style () == LOADGP_RTP"
|
"mips_current_loadgp_style () == LOADGP_RTP"
|
{ return mips_must_initialize_gp_p () ? "#" : ""; }
|
{ return mips_must_initialize_gp_p () ? "#" : ""; }
|
"&& mips_must_initialize_gp_p ()"
|
"&& mips_must_initialize_gp_p ()"
|
[(set (match_dup 0) (high:P (match_dup 3)))
|
[(set (match_dup 0) (high:P (match_dup 3)))
|
(set (match_dup 0) (unspec:P [(match_dup 0)
|
(set (match_dup 0) (unspec:P [(match_dup 0)
|
(match_dup 3)] UNSPEC_LOAD_GOT))
|
(match_dup 3)] UNSPEC_LOAD_GOT))
|
(set (match_dup 0) (unspec:P [(match_dup 0)
|
(set (match_dup 0) (unspec:P [(match_dup 0)
|
(match_dup 4)] UNSPEC_LOAD_GOT))]
|
(match_dup 4)] UNSPEC_LOAD_GOT))]
|
{
|
{
|
operands[3] = mips_unspec_address (operands[1], SYMBOL_ABSOLUTE);
|
operands[3] = mips_unspec_address (operands[1], SYMBOL_ABSOLUTE);
|
operands[4] = mips_unspec_address (operands[2], SYMBOL_HALF);
|
operands[4] = mips_unspec_address (operands[2], SYMBOL_HALF);
|
}
|
}
|
[(set_attr "type" "ghost")])
|
[(set_attr "type" "ghost")])
|
|
|
;; Initialize the global pointer for MIPS16 code. Operand 0 is the
|
;; Initialize the global pointer for MIPS16 code. Operand 0 is the
|
;; global pointer and operand 1 is the MIPS16 register that holds
|
;; global pointer and operand 1 is the MIPS16 register that holds
|
;; the required value.
|
;; the required value.
|
(define_insn_and_split "copygp_mips16"
|
(define_insn_and_split "copygp_mips16"
|
[(set (match_operand:SI 0 "register_operand" "=y")
|
[(set (match_operand:SI 0 "register_operand" "=y")
|
(unspec:SI [(match_operand:SI 1 "register_operand" "d")]
|
(unspec:SI [(match_operand:SI 1 "register_operand" "d")]
|
UNSPEC_COPYGP))]
|
UNSPEC_COPYGP))]
|
"TARGET_MIPS16"
|
"TARGET_MIPS16"
|
{ return mips_must_initialize_gp_p () ? "#" : ""; }
|
{ return mips_must_initialize_gp_p () ? "#" : ""; }
|
"&& mips_must_initialize_gp_p ()"
|
"&& mips_must_initialize_gp_p ()"
|
[(set (match_dup 0) (match_dup 1))]
|
[(set (match_dup 0) (match_dup 1))]
|
""
|
""
|
[(set_attr "type" "ghost")])
|
[(set_attr "type" "ghost")])
|
|
|
;; A placeholder for where the cprestore instruction should go,
|
;; A placeholder for where the cprestore instruction should go,
|
;; if we decide we need one. Operand 0 and operand 1 are as for
|
;; if we decide we need one. Operand 0 and operand 1 are as for
|
;; "cprestore". Operand 2 is a register that holds the gp value.
|
;; "cprestore". Operand 2 is a register that holds the gp value.
|
;;
|
;;
|
;; The "cprestore" pattern requires operand 2 to be pic_offset_table_rtx,
|
;; The "cprestore" pattern requires operand 2 to be pic_offset_table_rtx,
|
;; otherwise any register that holds the correct value will do.
|
;; otherwise any register that holds the correct value will do.
|
(define_insn_and_split "potential_cprestore"
|
(define_insn_and_split "potential_cprestore"
|
[(set (match_operand:SI 0 "cprestore_save_slot_operand" "=X,X")
|
[(set (match_operand:SI 0 "cprestore_save_slot_operand" "=X,X")
|
(unspec:SI [(match_operand:SI 1 "const_int_operand" "I,i")
|
(unspec:SI [(match_operand:SI 1 "const_int_operand" "I,i")
|
(match_operand:SI 2 "register_operand" "d,d")]
|
(match_operand:SI 2 "register_operand" "d,d")]
|
UNSPEC_POTENTIAL_CPRESTORE))
|
UNSPEC_POTENTIAL_CPRESTORE))
|
(clobber (match_operand:SI 3 "scratch_operand" "=X,&d"))]
|
(clobber (match_operand:SI 3 "scratch_operand" "=X,&d"))]
|
"!TARGET_CPRESTORE_DIRECTIVE || operands[2] == pic_offset_table_rtx"
|
"!TARGET_CPRESTORE_DIRECTIVE || operands[2] == pic_offset_table_rtx"
|
{ return mips_must_initialize_gp_p () ? "#" : ""; }
|
{ return mips_must_initialize_gp_p () ? "#" : ""; }
|
"mips_must_initialize_gp_p ()"
|
"mips_must_initialize_gp_p ()"
|
[(const_int 0)]
|
[(const_int 0)]
|
{
|
{
|
mips_save_gp_to_cprestore_slot (operands[0], operands[1],
|
mips_save_gp_to_cprestore_slot (operands[0], operands[1],
|
operands[2], operands[3]);
|
operands[2], operands[3]);
|
DONE;
|
DONE;
|
}
|
}
|
[(set_attr "type" "ghost")])
|
[(set_attr "type" "ghost")])
|
|
|
;; Emit a .cprestore directive, which normally expands to a single store
|
;; Emit a .cprestore directive, which normally expands to a single store
|
;; instruction. Operand 0 is a (possibly illegitimate) sp-based MEM
|
;; instruction. Operand 0 is a (possibly illegitimate) sp-based MEM
|
;; for the cprestore slot. Operand 1 is the offset of the slot from
|
;; for the cprestore slot. Operand 1 is the offset of the slot from
|
;; the stack pointer. (This is redundant with operand 0, but it makes
|
;; the stack pointer. (This is redundant with operand 0, but it makes
|
;; things a little simpler.)
|
;; things a little simpler.)
|
(define_insn "cprestore"
|
(define_insn "cprestore"
|
[(set (match_operand:SI 0 "cprestore_save_slot_operand" "=X,X")
|
[(set (match_operand:SI 0 "cprestore_save_slot_operand" "=X,X")
|
(unspec:SI [(match_operand:SI 1 "const_int_operand" "I,i")
|
(unspec:SI [(match_operand:SI 1 "const_int_operand" "I,i")
|
(reg:SI 28)]
|
(reg:SI 28)]
|
UNSPEC_CPRESTORE))]
|
UNSPEC_CPRESTORE))]
|
"TARGET_CPRESTORE_DIRECTIVE"
|
"TARGET_CPRESTORE_DIRECTIVE"
|
{
|
{
|
if (mips_nomacro.nesting_level > 0 && which_alternative == 1)
|
if (mips_nomacro.nesting_level > 0 && which_alternative == 1)
|
return ".set\tmacro\;.cprestore\t%1\;.set\tnomacro";
|
return ".set\tmacro\;.cprestore\t%1\;.set\tnomacro";
|
else
|
else
|
return ".cprestore\t%1";
|
return ".cprestore\t%1";
|
}
|
}
|
[(set_attr "type" "store")
|
[(set_attr "type" "store")
|
(set_attr "length" "4,12")])
|
(set_attr "length" "4,12")])
|
|
|
(define_insn "use_cprestore"
|
(define_insn "use_cprestore"
|
[(set (reg:SI CPRESTORE_SLOT_REGNUM)
|
[(set (reg:SI CPRESTORE_SLOT_REGNUM)
|
(match_operand:SI 0 "cprestore_load_slot_operand"))]
|
(match_operand:SI 0 "cprestore_load_slot_operand"))]
|
""
|
""
|
""
|
""
|
[(set_attr "type" "ghost")])
|
[(set_attr "type" "ghost")])
|
|
|
;; Expand in-line code to clear the instruction cache between operand[0] and
|
;; Expand in-line code to clear the instruction cache between operand[0] and
|
;; operand[1].
|
;; operand[1].
|
(define_expand "clear_cache"
|
(define_expand "clear_cache"
|
[(match_operand 0 "pmode_register_operand")
|
[(match_operand 0 "pmode_register_operand")
|
(match_operand 1 "pmode_register_operand")]
|
(match_operand 1 "pmode_register_operand")]
|
""
|
""
|
"
|
"
|
{
|
{
|
if (TARGET_SYNCI)
|
if (TARGET_SYNCI)
|
{
|
{
|
mips_expand_synci_loop (operands[0], operands[1]);
|
mips_expand_synci_loop (operands[0], operands[1]);
|
emit_insn (gen_sync ());
|
emit_insn (gen_sync ());
|
emit_insn (Pmode == SImode
|
emit_insn (Pmode == SImode
|
? gen_clear_hazard_si ()
|
? gen_clear_hazard_si ()
|
: gen_clear_hazard_di ());
|
: gen_clear_hazard_di ());
|
}
|
}
|
else if (mips_cache_flush_func && mips_cache_flush_func[0])
|
else if (mips_cache_flush_func && mips_cache_flush_func[0])
|
{
|
{
|
rtx len = gen_reg_rtx (Pmode);
|
rtx len = gen_reg_rtx (Pmode);
|
emit_insn (gen_sub3_insn (len, operands[1], operands[0]));
|
emit_insn (gen_sub3_insn (len, operands[1], operands[0]));
|
MIPS_ICACHE_SYNC (operands[0], len);
|
MIPS_ICACHE_SYNC (operands[0], len);
|
}
|
}
|
DONE;
|
DONE;
|
}")
|
}")
|
|
|
(define_insn "sync"
|
(define_insn "sync"
|
[(unspec_volatile [(const_int 0)] UNSPEC_SYNC)]
|
[(unspec_volatile [(const_int 0)] UNSPEC_SYNC)]
|
"GENERATE_SYNC"
|
"GENERATE_SYNC"
|
{ return mips_output_sync (); })
|
{ return mips_output_sync (); })
|
|
|
(define_insn "synci"
|
(define_insn "synci"
|
[(unspec_volatile [(match_operand 0 "pmode_register_operand" "d")]
|
[(unspec_volatile [(match_operand 0 "pmode_register_operand" "d")]
|
UNSPEC_SYNCI)]
|
UNSPEC_SYNCI)]
|
"TARGET_SYNCI"
|
"TARGET_SYNCI"
|
"synci\t0(%0)")
|
"synci\t0(%0)")
|
|
|
(define_insn "rdhwr_synci_step_"
|
(define_insn "rdhwr_synci_step_"
|
[(set (match_operand:P 0 "register_operand" "=d")
|
[(set (match_operand:P 0 "register_operand" "=d")
|
(unspec_volatile [(const_int 1)]
|
(unspec_volatile [(const_int 1)]
|
UNSPEC_RDHWR))]
|
UNSPEC_RDHWR))]
|
"ISA_HAS_SYNCI"
|
"ISA_HAS_SYNCI"
|
"rdhwr\t%0,$1")
|
"rdhwr\t%0,$1")
|
|
|
(define_insn "clear_hazard_"
|
(define_insn "clear_hazard_"
|
[(unspec_volatile [(const_int 0)] UNSPEC_CLEAR_HAZARD)
|
[(unspec_volatile [(const_int 0)] UNSPEC_CLEAR_HAZARD)
|
(clobber (reg:P RETURN_ADDR_REGNUM))]
|
(clobber (reg:P RETURN_ADDR_REGNUM))]
|
"ISA_HAS_SYNCI"
|
"ISA_HAS_SYNCI"
|
{
|
{
|
return "%(%
|
return "%(%
|
"\tnop\n"
|
"\tnop\n"
|
"1:\taddiu\t$31,$31,12\n"
|
"1:\taddiu\t$31,$31,12\n"
|
"\tjr.hb\t$31\n"
|
"\tjr.hb\t$31\n"
|
"\tnop%>%)";
|
"\tnop%>%)";
|
}
|
}
|
[(set_attr "length" "20")])
|
[(set_attr "length" "20")])
|
|
|
;; Cache operations for R4000-style caches.
|
;; Cache operations for R4000-style caches.
|
(define_insn "mips_cache"
|
(define_insn "mips_cache"
|
[(set (mem:BLK (scratch))
|
[(set (mem:BLK (scratch))
|
(unspec:BLK [(match_operand:SI 0 "const_int_operand")
|
(unspec:BLK [(match_operand:SI 0 "const_int_operand")
|
(match_operand:QI 1 "address_operand" "p")]
|
(match_operand:QI 1 "address_operand" "p")]
|
UNSPEC_MIPS_CACHE))]
|
UNSPEC_MIPS_CACHE))]
|
"ISA_HAS_CACHE"
|
"ISA_HAS_CACHE"
|
"cache\t%X0,%a1")
|
"cache\t%X0,%a1")
|
|
|
;; Similar, but with the operands hard-coded to an R10K cache barrier
|
;; Similar, but with the operands hard-coded to an R10K cache barrier
|
;; operation. We keep the pattern distinct so that we can identify
|
;; operation. We keep the pattern distinct so that we can identify
|
;; cache operations inserted by -mr10k-cache-barrier=, and so that
|
;; cache operations inserted by -mr10k-cache-barrier=, and so that
|
;; the operation is never inserted into a delay slot.
|
;; the operation is never inserted into a delay slot.
|
(define_insn "r10k_cache_barrier"
|
(define_insn "r10k_cache_barrier"
|
[(set (mem:BLK (scratch))
|
[(set (mem:BLK (scratch))
|
(unspec:BLK [(const_int 0)] UNSPEC_R10K_CACHE_BARRIER))]
|
(unspec:BLK [(const_int 0)] UNSPEC_R10K_CACHE_BARRIER))]
|
"ISA_HAS_CACHE"
|
"ISA_HAS_CACHE"
|
"cache\t0x14,0(%$)"
|
"cache\t0x14,0(%$)"
|
[(set_attr "can_delay" "no")])
|
[(set_attr "can_delay" "no")])
|
|
|
;; Block moves, see mips.c for more details.
|
;; Block moves, see mips.c for more details.
|
;; Argument 0 is the destination
|
;; Argument 0 is the destination
|
;; Argument 1 is the source
|
;; Argument 1 is the source
|
;; Argument 2 is the length
|
;; Argument 2 is the length
|
;; Argument 3 is the alignment
|
;; Argument 3 is the alignment
|
|
|
(define_expand "movmemsi"
|
(define_expand "movmemsi"
|
[(parallel [(set (match_operand:BLK 0 "general_operand")
|
[(parallel [(set (match_operand:BLK 0 "general_operand")
|
(match_operand:BLK 1 "general_operand"))
|
(match_operand:BLK 1 "general_operand"))
|
(use (match_operand:SI 2 ""))
|
(use (match_operand:SI 2 ""))
|
(use (match_operand:SI 3 "const_int_operand"))])]
|
(use (match_operand:SI 3 "const_int_operand"))])]
|
"!TARGET_MIPS16 && !TARGET_MEMCPY"
|
"!TARGET_MIPS16 && !TARGET_MEMCPY"
|
{
|
{
|
if (mips_expand_block_move (operands[0], operands[1], operands[2]))
|
if (mips_expand_block_move (operands[0], operands[1], operands[2]))
|
DONE;
|
DONE;
|
else
|
else
|
FAIL;
|
FAIL;
|
})
|
})
|
|
|
;;
|
;;
|
;; ....................
|
;; ....................
|
;;
|
;;
|
;; SHIFTS
|
;; SHIFTS
|
;;
|
;;
|
;; ....................
|
;; ....................
|
|
|
(define_expand "3"
|
(define_expand "3"
|
[(set (match_operand:GPR 0 "register_operand")
|
[(set (match_operand:GPR 0 "register_operand")
|
(any_shift:GPR (match_operand:GPR 1 "register_operand")
|
(any_shift:GPR (match_operand:GPR 1 "register_operand")
|
(match_operand:SI 2 "arith_operand")))]
|
(match_operand:SI 2 "arith_operand")))]
|
""
|
""
|
{
|
{
|
/* On the mips16, a shift of more than 8 is a four byte instruction,
|
/* On the mips16, a shift of more than 8 is a four byte instruction,
|
so, for a shift between 8 and 16, it is just as fast to do two
|
so, for a shift between 8 and 16, it is just as fast to do two
|
shifts of 8 or less. If there is a lot of shifting going on, we
|
shifts of 8 or less. If there is a lot of shifting going on, we
|
may win in CSE. Otherwise combine will put the shifts back
|
may win in CSE. Otherwise combine will put the shifts back
|
together again. This can be called by mips_function_arg, so we must
|
together again. This can be called by mips_function_arg, so we must
|
be careful not to allocate a new register if we've reached the
|
be careful not to allocate a new register if we've reached the
|
reload pass. */
|
reload pass. */
|
if (TARGET_MIPS16
|
if (TARGET_MIPS16
|
&& optimize
|
&& optimize
|
&& CONST_INT_P (operands[2])
|
&& CONST_INT_P (operands[2])
|
&& INTVAL (operands[2]) > 8
|
&& INTVAL (operands[2]) > 8
|
&& INTVAL (operands[2]) <= 16
|
&& INTVAL (operands[2]) <= 16
|
&& !reload_in_progress
|
&& !reload_in_progress
|
&& !reload_completed)
|
&& !reload_completed)
|
{
|
{
|
rtx temp = gen_reg_rtx (mode);
|
rtx temp = gen_reg_rtx (mode);
|
|
|
emit_insn (gen_3 (temp, operands[1], GEN_INT (8)));
|
emit_insn (gen_3 (temp, operands[1], GEN_INT (8)));
|
emit_insn (gen_3 (operands[0], temp,
|
emit_insn (gen_3 (operands[0], temp,
|
GEN_INT (INTVAL (operands[2]) - 8)));
|
GEN_INT (INTVAL (operands[2]) - 8)));
|
DONE;
|
DONE;
|
}
|
}
|
})
|
})
|
|
|
(define_insn "*3"
|
(define_insn "*3"
|
[(set (match_operand:GPR 0 "register_operand" "=d")
|
[(set (match_operand:GPR 0 "register_operand" "=d")
|
(any_shift:GPR (match_operand:GPR 1 "register_operand" "d")
|
(any_shift:GPR (match_operand:GPR 1 "register_operand" "d")
|
(match_operand:SI 2 "arith_operand" "dI")))]
|
(match_operand:SI 2 "arith_operand" "dI")))]
|
"!TARGET_MIPS16"
|
"!TARGET_MIPS16"
|
{
|
{
|
if (CONST_INT_P (operands[2]))
|
if (CONST_INT_P (operands[2]))
|
operands[2] = GEN_INT (INTVAL (operands[2])
|
operands[2] = GEN_INT (INTVAL (operands[2])
|
& (GET_MODE_BITSIZE (mode) - 1));
|
& (GET_MODE_BITSIZE (mode) - 1));
|
|
|
return "\t%0,%1,%2";
|
return "\t%0,%1,%2";
|
}
|
}
|
[(set_attr "type" "shift")
|
[(set_attr "type" "shift")
|
(set_attr "mode" "")])
|
(set_attr "mode" "")])
|
|
|
(define_insn "*si3_extend"
|
(define_insn "*si3_extend"
|
[(set (match_operand:DI 0 "register_operand" "=d")
|
[(set (match_operand:DI 0 "register_operand" "=d")
|
(sign_extend:DI
|
(sign_extend:DI
|
(any_shift:SI (match_operand:SI 1 "register_operand" "d")
|
(any_shift:SI (match_operand:SI 1 "register_operand" "d")
|
(match_operand:SI 2 "arith_operand" "dI"))))]
|
(match_operand:SI 2 "arith_operand" "dI"))))]
|
"TARGET_64BIT && !TARGET_MIPS16"
|
"TARGET_64BIT && !TARGET_MIPS16"
|
{
|
{
|
if (CONST_INT_P (operands[2]))
|
if (CONST_INT_P (operands[2]))
|
operands[2] = GEN_INT (INTVAL (operands[2]) & 0x1f);
|
operands[2] = GEN_INT (INTVAL (operands[2]) & 0x1f);
|
|
|
return "\t%0,%1,%2";
|
return "\t%0,%1,%2";
|
}
|
}
|
[(set_attr "type" "shift")
|
[(set_attr "type" "shift")
|
(set_attr "mode" "SI")])
|
(set_attr "mode" "SI")])
|
|
|
(define_insn "*si3_mips16"
|
(define_insn "*si3_mips16"
|
[(set (match_operand:SI 0 "register_operand" "=d,d")
|
[(set (match_operand:SI 0 "register_operand" "=d,d")
|
(any_shift:SI (match_operand:SI 1 "register_operand" "0,d")
|
(any_shift:SI (match_operand:SI 1 "register_operand" "0,d")
|
(match_operand:SI 2 "arith_operand" "d,I")))]
|
(match_operand:SI 2 "arith_operand" "d,I")))]
|
"TARGET_MIPS16"
|
"TARGET_MIPS16"
|
{
|
{
|
if (which_alternative == 0)
|
if (which_alternative == 0)
|
return "\t%0,%2";
|
return "\t%0,%2";
|
|
|
operands[2] = GEN_INT (INTVAL (operands[2]) & 0x1f);
|
operands[2] = GEN_INT (INTVAL (operands[2]) & 0x1f);
|
return "\t%0,%1,%2";
|
return "\t%0,%1,%2";
|
}
|
}
|
[(set_attr "type" "shift")
|
[(set_attr "type" "shift")
|
(set_attr "mode" "SI")
|
(set_attr "mode" "SI")
|
(set_attr_alternative "length"
|
(set_attr_alternative "length"
|
[(const_int 4)
|
[(const_int 4)
|
(if_then_else (match_operand 2 "m16_uimm3_b")
|
(if_then_else (match_operand 2 "m16_uimm3_b")
|
(const_int 4)
|
(const_int 4)
|
(const_int 8))])])
|
(const_int 8))])])
|
|
|
;; We need separate DImode MIPS16 patterns because of the irregularity
|
;; We need separate DImode MIPS16 patterns because of the irregularity
|
;; of right shifts.
|
;; of right shifts.
|
(define_insn "*ashldi3_mips16"
|
(define_insn "*ashldi3_mips16"
|
[(set (match_operand:DI 0 "register_operand" "=d,d")
|
[(set (match_operand:DI 0 "register_operand" "=d,d")
|
(ashift:DI (match_operand:DI 1 "register_operand" "0,d")
|
(ashift:DI (match_operand:DI 1 "register_operand" "0,d")
|
(match_operand:SI 2 "arith_operand" "d,I")))]
|
(match_operand:SI 2 "arith_operand" "d,I")))]
|
"TARGET_64BIT && TARGET_MIPS16"
|
"TARGET_64BIT && TARGET_MIPS16"
|
{
|
{
|
if (which_alternative == 0)
|
if (which_alternative == 0)
|
return "dsll\t%0,%2";
|
return "dsll\t%0,%2";
|
|
|
operands[2] = GEN_INT (INTVAL (operands[2]) & 0x3f);
|
operands[2] = GEN_INT (INTVAL (operands[2]) & 0x3f);
|
return "dsll\t%0,%1,%2";
|
return "dsll\t%0,%1,%2";
|
}
|
}
|
[(set_attr "type" "shift")
|
[(set_attr "type" "shift")
|
(set_attr "mode" "DI")
|
(set_attr "mode" "DI")
|
(set_attr_alternative "length"
|
(set_attr_alternative "length"
|
[(const_int 4)
|
[(const_int 4)
|
(if_then_else (match_operand 2 "m16_uimm3_b")
|
(if_then_else (match_operand 2 "m16_uimm3_b")
|
(const_int 4)
|
(const_int 4)
|
(const_int 8))])])
|
(const_int 8))])])
|
|
|
(define_insn "*ashrdi3_mips16"
|
(define_insn "*ashrdi3_mips16"
|
[(set (match_operand:DI 0 "register_operand" "=d,d")
|
[(set (match_operand:DI 0 "register_operand" "=d,d")
|
(ashiftrt:DI (match_operand:DI 1 "register_operand" "0,0")
|
(ashiftrt:DI (match_operand:DI 1 "register_operand" "0,0")
|
(match_operand:SI 2 "arith_operand" "d,I")))]
|
(match_operand:SI 2 "arith_operand" "d,I")))]
|
"TARGET_64BIT && TARGET_MIPS16"
|
"TARGET_64BIT && TARGET_MIPS16"
|
{
|
{
|
if (CONST_INT_P (operands[2]))
|
if (CONST_INT_P (operands[2]))
|
operands[2] = GEN_INT (INTVAL (operands[2]) & 0x3f);
|
operands[2] = GEN_INT (INTVAL (operands[2]) & 0x3f);
|
|
|
return "dsra\t%0,%2";
|
return "dsra\t%0,%2";
|
}
|
}
|
[(set_attr "type" "shift")
|
[(set_attr "type" "shift")
|
(set_attr "mode" "DI")
|
(set_attr "mode" "DI")
|
(set_attr_alternative "length"
|
(set_attr_alternative "length"
|
[(const_int 4)
|
[(const_int 4)
|
(if_then_else (match_operand 2 "m16_uimm3_b")
|
(if_then_else (match_operand 2 "m16_uimm3_b")
|
(const_int 4)
|
(const_int 4)
|
(const_int 8))])])
|
(const_int 8))])])
|
|
|
(define_insn "*lshrdi3_mips16"
|
(define_insn "*lshrdi3_mips16"
|
[(set (match_operand:DI 0 "register_operand" "=d,d")
|
[(set (match_operand:DI 0 "register_operand" "=d,d")
|
(lshiftrt:DI (match_operand:DI 1 "register_operand" "0,0")
|
(lshiftrt:DI (match_operand:DI 1 "register_operand" "0,0")
|
(match_operand:SI 2 "arith_operand" "d,I")))]
|
(match_operand:SI 2 "arith_operand" "d,I")))]
|
"TARGET_64BIT && TARGET_MIPS16"
|
"TARGET_64BIT && TARGET_MIPS16"
|
{
|
{
|
if (CONST_INT_P (operands[2]))
|
if (CONST_INT_P (operands[2]))
|
operands[2] = GEN_INT (INTVAL (operands[2]) & 0x3f);
|
operands[2] = GEN_INT (INTVAL (operands[2]) & 0x3f);
|
|
|
return "dsrl\t%0,%2";
|
return "dsrl\t%0,%2";
|
}
|
}
|
[(set_attr "type" "shift")
|
[(set_attr "type" "shift")
|
(set_attr "mode" "DI")
|
(set_attr "mode" "DI")
|
(set_attr_alternative "length"
|
(set_attr_alternative "length"
|
[(const_int 4)
|
[(const_int 4)
|
(if_then_else (match_operand 2 "m16_uimm3_b")
|
(if_then_else (match_operand 2 "m16_uimm3_b")
|
(const_int 4)
|
(const_int 4)
|
(const_int 8))])])
|
(const_int 8))])])
|
|
|
;; On the mips16, we can split a 4 byte shift into 2 2 byte shifts.
|
;; On the mips16, we can split a 4 byte shift into 2 2 byte shifts.
|
|
|
(define_split
|
(define_split
|
[(set (match_operand:GPR 0 "d_operand")
|
[(set (match_operand:GPR 0 "d_operand")
|
(any_shift:GPR (match_operand:GPR 1 "d_operand")
|
(any_shift:GPR (match_operand:GPR 1 "d_operand")
|
(match_operand:GPR 2 "const_int_operand")))]
|
(match_operand:GPR 2 "const_int_operand")))]
|
"TARGET_MIPS16 && reload_completed && !TARGET_DEBUG_D_MODE
|
"TARGET_MIPS16 && reload_completed && !TARGET_DEBUG_D_MODE
|
&& INTVAL (operands[2]) > 8
|
&& INTVAL (operands[2]) > 8
|
&& INTVAL (operands[2]) <= 16"
|
&& INTVAL (operands[2]) <= 16"
|
[(set (match_dup 0) (any_shift:GPR (match_dup 1) (const_int 8)))
|
[(set (match_dup 0) (any_shift:GPR (match_dup 1) (const_int 8)))
|
(set (match_dup 0) (any_shift:GPR (match_dup 0) (match_dup 2)))]
|
(set (match_dup 0) (any_shift:GPR (match_dup 0) (match_dup 2)))]
|
{ operands[2] = GEN_INT (INTVAL (operands[2]) - 8); })
|
{ operands[2] = GEN_INT (INTVAL (operands[2]) - 8); })
|
|
|
;; If we load a byte on the mips16 as a bitfield, the resulting
|
;; If we load a byte on the mips16 as a bitfield, the resulting
|
;; sequence of instructions is too complicated for combine, because it
|
;; sequence of instructions is too complicated for combine, because it
|
;; involves four instructions: a load, a shift, a constant load into a
|
;; involves four instructions: a load, a shift, a constant load into a
|
;; register, and an and (the key problem here is that the mips16 does
|
;; register, and an and (the key problem here is that the mips16 does
|
;; not have and immediate). We recognize a shift of a load in order
|
;; not have and immediate). We recognize a shift of a load in order
|
;; to make it simple enough for combine to understand.
|
;; to make it simple enough for combine to understand.
|
;;
|
;;
|
;; The length here is the worst case: the length of the split version
|
;; The length here is the worst case: the length of the split version
|
;; will be more accurate.
|
;; will be more accurate.
|
(define_insn_and_split ""
|
(define_insn_and_split ""
|
[(set (match_operand:SI 0 "register_operand" "=d")
|
[(set (match_operand:SI 0 "register_operand" "=d")
|
(lshiftrt:SI (match_operand:SI 1 "memory_operand" "m")
|
(lshiftrt:SI (match_operand:SI 1 "memory_operand" "m")
|
(match_operand:SI 2 "immediate_operand" "I")))]
|
(match_operand:SI 2 "immediate_operand" "I")))]
|
"TARGET_MIPS16"
|
"TARGET_MIPS16"
|
"#"
|
"#"
|
""
|
""
|
[(set (match_dup 0) (match_dup 1))
|
[(set (match_dup 0) (match_dup 1))
|
(set (match_dup 0) (lshiftrt:SI (match_dup 0) (match_dup 2)))]
|
(set (match_dup 0) (lshiftrt:SI (match_dup 0) (match_dup 2)))]
|
""
|
""
|
[(set_attr "type" "load")
|
[(set_attr "type" "load")
|
(set_attr "mode" "SI")
|
(set_attr "mode" "SI")
|
(set_attr "length" "16")])
|
(set_attr "length" "16")])
|
|
|
(define_insn "rotr3"
|
(define_insn "rotr3"
|
[(set (match_operand:GPR 0 "register_operand" "=d")
|
[(set (match_operand:GPR 0 "register_operand" "=d")
|
(rotatert:GPR (match_operand:GPR 1 "register_operand" "d")
|
(rotatert:GPR (match_operand:GPR 1 "register_operand" "d")
|
(match_operand:SI 2 "arith_operand" "dI")))]
|
(match_operand:SI 2 "arith_operand" "dI")))]
|
"ISA_HAS_ROR"
|
"ISA_HAS_ROR"
|
{
|
{
|
if (CONST_INT_P (operands[2]))
|
if (CONST_INT_P (operands[2]))
|
gcc_assert (INTVAL (operands[2]) >= 0
|
gcc_assert (INTVAL (operands[2]) >= 0
|
&& INTVAL (operands[2]) < GET_MODE_BITSIZE (mode));
|
&& INTVAL (operands[2]) < GET_MODE_BITSIZE (mode));
|
|
|
return "ror\t%0,%1,%2";
|
return "ror\t%0,%1,%2";
|
}
|
}
|
[(set_attr "type" "shift")
|
[(set_attr "type" "shift")
|
(set_attr "mode" "")])
|
(set_attr "mode" "")])
|
|
|
;;
|
;;
|
;; ....................
|
;; ....................
|
;;
|
;;
|
;; CONDITIONAL BRANCHES
|
;; CONDITIONAL BRANCHES
|
;;
|
;;
|
;; ....................
|
;; ....................
|
|
|
;; Conditional branches on floating-point equality tests.
|
;; Conditional branches on floating-point equality tests.
|
|
|
(define_insn "*branch_fp"
|
(define_insn "*branch_fp"
|
[(set (pc)
|
[(set (pc)
|
(if_then_else
|
(if_then_else
|
(match_operator 1 "equality_operator"
|
(match_operator 1 "equality_operator"
|
[(match_operand:CC 2 "register_operand" "z")
|
[(match_operand:CC 2 "register_operand" "z")
|
(const_int 0)])
|
(const_int 0)])
|
(label_ref (match_operand 0 "" ""))
|
(label_ref (match_operand 0 "" ""))
|
(pc)))]
|
(pc)))]
|
"TARGET_HARD_FLOAT"
|
"TARGET_HARD_FLOAT"
|
{
|
{
|
return mips_output_conditional_branch (insn, operands,
|
return mips_output_conditional_branch (insn, operands,
|
MIPS_BRANCH ("b%F1", "%Z2%0"),
|
MIPS_BRANCH ("b%F1", "%Z2%0"),
|
MIPS_BRANCH ("b%W1", "%Z2%0"));
|
MIPS_BRANCH ("b%W1", "%Z2%0"));
|
}
|
}
|
[(set_attr "type" "branch")])
|
[(set_attr "type" "branch")])
|
|
|
(define_insn "*branch_fp_inverted"
|
(define_insn "*branch_fp_inverted"
|
[(set (pc)
|
[(set (pc)
|
(if_then_else
|
(if_then_else
|
(match_operator 1 "equality_operator"
|
(match_operator 1 "equality_operator"
|
[(match_operand:CC 2 "register_operand" "z")
|
[(match_operand:CC 2 "register_operand" "z")
|
(const_int 0)])
|
(const_int 0)])
|
(pc)
|
(pc)
|
(label_ref (match_operand 0 "" ""))))]
|
(label_ref (match_operand 0 "" ""))))]
|
"TARGET_HARD_FLOAT"
|
"TARGET_HARD_FLOAT"
|
{
|
{
|
return mips_output_conditional_branch (insn, operands,
|
return mips_output_conditional_branch (insn, operands,
|
MIPS_BRANCH ("b%W1", "%Z2%0"),
|
MIPS_BRANCH ("b%W1", "%Z2%0"),
|
MIPS_BRANCH ("b%F1", "%Z2%0"));
|
MIPS_BRANCH ("b%F1", "%Z2%0"));
|
}
|
}
|
[(set_attr "type" "branch")])
|
[(set_attr "type" "branch")])
|
|
|
;; Conditional branches on ordered comparisons with zero.
|
;; Conditional branches on ordered comparisons with zero.
|
|
|
(define_insn "*branch_order"
|
(define_insn "*branch_order"
|
[(set (pc)
|
[(set (pc)
|
(if_then_else
|
(if_then_else
|
(match_operator 1 "order_operator"
|
(match_operator 1 "order_operator"
|
[(match_operand:GPR 2 "register_operand" "d")
|
[(match_operand:GPR 2 "register_operand" "d")
|
(const_int 0)])
|
(const_int 0)])
|
(label_ref (match_operand 0 "" ""))
|
(label_ref (match_operand 0 "" ""))
|
(pc)))]
|
(pc)))]
|
"!TARGET_MIPS16"
|
"!TARGET_MIPS16"
|
{ return mips_output_order_conditional_branch (insn, operands, false); }
|
{ return mips_output_order_conditional_branch (insn, operands, false); }
|
[(set_attr "type" "branch")])
|
[(set_attr "type" "branch")])
|
|
|
(define_insn "*branch_order_inverted"
|
(define_insn "*branch_order_inverted"
|
[(set (pc)
|
[(set (pc)
|
(if_then_else
|
(if_then_else
|
(match_operator 1 "order_operator"
|
(match_operator 1 "order_operator"
|
[(match_operand:GPR 2 "register_operand" "d")
|
[(match_operand:GPR 2 "register_operand" "d")
|
(const_int 0)])
|
(const_int 0)])
|
(pc)
|
(pc)
|
(label_ref (match_operand 0 "" ""))))]
|
(label_ref (match_operand 0 "" ""))))]
|
"!TARGET_MIPS16"
|
"!TARGET_MIPS16"
|
{ return mips_output_order_conditional_branch (insn, operands, true); }
|
{ return mips_output_order_conditional_branch (insn, operands, true); }
|
[(set_attr "type" "branch")])
|
[(set_attr "type" "branch")])
|
|
|
;; Conditional branch on equality comparison.
|
;; Conditional branch on equality comparison.
|
|
|
(define_insn "*branch_equality"
|
(define_insn "*branch_equality"
|
[(set (pc)
|
[(set (pc)
|
(if_then_else
|
(if_then_else
|
(match_operator 1 "equality_operator"
|
(match_operator 1 "equality_operator"
|
[(match_operand:GPR 2 "register_operand" "d")
|
[(match_operand:GPR 2 "register_operand" "d")
|
(match_operand:GPR 3 "reg_or_0_operand" "dJ")])
|
(match_operand:GPR 3 "reg_or_0_operand" "dJ")])
|
(label_ref (match_operand 0 "" ""))
|
(label_ref (match_operand 0 "" ""))
|
(pc)))]
|
(pc)))]
|
"!TARGET_MIPS16"
|
"!TARGET_MIPS16"
|
{
|
{
|
return mips_output_conditional_branch (insn, operands,
|
return mips_output_conditional_branch (insn, operands,
|
MIPS_BRANCH ("b%C1", "%2,%z3,%0"),
|
MIPS_BRANCH ("b%C1", "%2,%z3,%0"),
|
MIPS_BRANCH ("b%N1", "%2,%z3,%0"));
|
MIPS_BRANCH ("b%N1", "%2,%z3,%0"));
|
}
|
}
|
[(set_attr "type" "branch")])
|
[(set_attr "type" "branch")])
|
|
|
(define_insn "*branch_equality_inverted"
|
(define_insn "*branch_equality_inverted"
|
[(set (pc)
|
[(set (pc)
|
(if_then_else
|
(if_then_else
|
(match_operator 1 "equality_operator"
|
(match_operator 1 "equality_operator"
|
[(match_operand:GPR 2 "register_operand" "d")
|
[(match_operand:GPR 2 "register_operand" "d")
|
(match_operand:GPR 3 "reg_or_0_operand" "dJ")])
|
(match_operand:GPR 3 "reg_or_0_operand" "dJ")])
|
(pc)
|
(pc)
|
(label_ref (match_operand 0 "" ""))))]
|
(label_ref (match_operand 0 "" ""))))]
|
"!TARGET_MIPS16"
|
"!TARGET_MIPS16"
|
{
|
{
|
return mips_output_conditional_branch (insn, operands,
|
return mips_output_conditional_branch (insn, operands,
|
MIPS_BRANCH ("b%N1", "%2,%z3,%0"),
|
MIPS_BRANCH ("b%N1", "%2,%z3,%0"),
|
MIPS_BRANCH ("b%C1", "%2,%z3,%0"));
|
MIPS_BRANCH ("b%C1", "%2,%z3,%0"));
|
}
|
}
|
[(set_attr "type" "branch")])
|
[(set_attr "type" "branch")])
|
|
|
;; MIPS16 branches
|
;; MIPS16 branches
|
|
|
(define_insn "*branch_equality_mips16"
|
(define_insn "*branch_equality_mips16"
|
[(set (pc)
|
[(set (pc)
|
(if_then_else
|
(if_then_else
|
(match_operator 0 "equality_operator"
|
(match_operator 0 "equality_operator"
|
[(match_operand:GPR 1 "register_operand" "d,t")
|
[(match_operand:GPR 1 "register_operand" "d,t")
|
(const_int 0)])
|
(const_int 0)])
|
(match_operand 2 "pc_or_label_operand" "")
|
(match_operand 2 "pc_or_label_operand" "")
|
(match_operand 3 "pc_or_label_operand" "")))]
|
(match_operand 3 "pc_or_label_operand" "")))]
|
"TARGET_MIPS16"
|
"TARGET_MIPS16"
|
{
|
{
|
if (operands[2] != pc_rtx)
|
if (operands[2] != pc_rtx)
|
{
|
{
|
if (which_alternative == 0)
|
if (which_alternative == 0)
|
return "b%C0z\t%1,%2";
|
return "b%C0z\t%1,%2";
|
else
|
else
|
return "bt%C0z\t%2";
|
return "bt%C0z\t%2";
|
}
|
}
|
else
|
else
|
{
|
{
|
if (which_alternative == 0)
|
if (which_alternative == 0)
|
return "b%N0z\t%1,%3";
|
return "b%N0z\t%1,%3";
|
else
|
else
|
return "bt%N0z\t%3";
|
return "bt%N0z\t%3";
|
}
|
}
|
}
|
}
|
[(set_attr "type" "branch")])
|
[(set_attr "type" "branch")])
|
|
|
(define_expand "cbranch4"
|
(define_expand "cbranch4"
|
[(set (pc)
|
[(set (pc)
|
(if_then_else (match_operator 0 "comparison_operator"
|
(if_then_else (match_operator 0 "comparison_operator"
|
[(match_operand:GPR 1 "register_operand")
|
[(match_operand:GPR 1 "register_operand")
|
(match_operand:GPR 2 "nonmemory_operand")])
|
(match_operand:GPR 2 "nonmemory_operand")])
|
(label_ref (match_operand 3 ""))
|
(label_ref (match_operand 3 ""))
|
(pc)))]
|
(pc)))]
|
""
|
""
|
{
|
{
|
mips_expand_conditional_branch (operands);
|
mips_expand_conditional_branch (operands);
|
DONE;
|
DONE;
|
})
|
})
|
|
|
(define_expand "cbranch4"
|
(define_expand "cbranch4"
|
[(set (pc)
|
[(set (pc)
|
(if_then_else (match_operator 0 "comparison_operator"
|
(if_then_else (match_operator 0 "comparison_operator"
|
[(match_operand:SCALARF 1 "register_operand")
|
[(match_operand:SCALARF 1 "register_operand")
|
(match_operand:SCALARF 2 "register_operand")])
|
(match_operand:SCALARF 2 "register_operand")])
|
(label_ref (match_operand 3 ""))
|
(label_ref (match_operand 3 ""))
|
(pc)))]
|
(pc)))]
|
""
|
""
|
{
|
{
|
mips_expand_conditional_branch (operands);
|
mips_expand_conditional_branch (operands);
|
DONE;
|
DONE;
|
})
|
})
|
|
|
;; Used to implement built-in functions.
|
;; Used to implement built-in functions.
|
(define_expand "condjump"
|
(define_expand "condjump"
|
[(set (pc)
|
[(set (pc)
|
(if_then_else (match_operand 0)
|
(if_then_else (match_operand 0)
|
(label_ref (match_operand 1))
|
(label_ref (match_operand 1))
|
(pc)))])
|
(pc)))])
|
|
|
;; Branch if bit is set/clear.
|
;; Branch if bit is set/clear.
|
|
|
(define_insn "*branch_bit"
|
(define_insn "*branch_bit"
|
[(set (pc)
|
[(set (pc)
|
(if_then_else
|
(if_then_else
|
(equality_op (zero_extract:GPR
|
(equality_op (zero_extract:GPR
|
(match_operand:GPR 1 "register_operand" "d")
|
(match_operand:GPR 1 "register_operand" "d")
|
(const_int 1)
|
(const_int 1)
|
(match_operand 2 "const_int_operand" ""))
|
(match_operand 2 "const_int_operand" ""))
|
(const_int 0))
|
(const_int 0))
|
(label_ref (match_operand 0 ""))
|
(label_ref (match_operand 0 ""))
|
(pc)))]
|
(pc)))]
|
"ISA_HAS_BBIT && UINTVAL (operands[2]) < GET_MODE_BITSIZE (mode)"
|
"ISA_HAS_BBIT && UINTVAL (operands[2]) < GET_MODE_BITSIZE (mode)"
|
{
|
{
|
return
|
return
|
mips_output_conditional_branch (insn, operands,
|
mips_output_conditional_branch (insn, operands,
|
MIPS_BRANCH ("bbit", "%1,%2,%0"),
|
MIPS_BRANCH ("bbit", "%1,%2,%0"),
|
MIPS_BRANCH ("bbit", "%1,%2,%0"));
|
MIPS_BRANCH ("bbit", "%1,%2,%0"));
|
}
|
}
|
[(set_attr "type" "branch")
|
[(set_attr "type" "branch")
|
(set_attr "branch_likely" "no")])
|
(set_attr "branch_likely" "no")])
|
|
|
(define_insn "*branch_bit_inverted"
|
(define_insn "*branch_bit_inverted"
|
[(set (pc)
|
[(set (pc)
|
(if_then_else
|
(if_then_else
|
(equality_op (zero_extract:GPR
|
(equality_op (zero_extract:GPR
|
(match_operand:GPR 1 "register_operand" "d")
|
(match_operand:GPR 1 "register_operand" "d")
|
(const_int 1)
|
(const_int 1)
|
(match_operand 2 "const_int_operand" ""))
|
(match_operand 2 "const_int_operand" ""))
|
(const_int 0))
|
(const_int 0))
|
(pc)
|
(pc)
|
(label_ref (match_operand 0 ""))))]
|
(label_ref (match_operand 0 ""))))]
|
"ISA_HAS_BBIT && UINTVAL (operands[2]) < GET_MODE_BITSIZE (mode)"
|
"ISA_HAS_BBIT && UINTVAL (operands[2]) < GET_MODE_BITSIZE (mode)"
|
{
|
{
|
return
|
return
|
mips_output_conditional_branch (insn, operands,
|
mips_output_conditional_branch (insn, operands,
|
MIPS_BRANCH ("bbit", "%1,%2,%0"),
|
MIPS_BRANCH ("bbit", "%1,%2,%0"),
|
MIPS_BRANCH ("bbit", "%1,%2,%0"));
|
MIPS_BRANCH ("bbit", "%1,%2,%0"));
|
}
|
}
|
[(set_attr "type" "branch")
|
[(set_attr "type" "branch")
|
(set_attr "branch_likely" "no")])
|
(set_attr "branch_likely" "no")])
|
|
|
;;
|
;;
|
;; ....................
|
;; ....................
|
;;
|
;;
|
;; SETTING A REGISTER FROM A COMPARISON
|
;; SETTING A REGISTER FROM A COMPARISON
|
;;
|
;;
|
;; ....................
|
;; ....................
|
|
|
;; Destination is always set in SI mode.
|
;; Destination is always set in SI mode.
|
|
|
(define_expand "cstore4"
|
(define_expand "cstore4"
|
[(set (match_operand:SI 0 "register_operand")
|
[(set (match_operand:SI 0 "register_operand")
|
(match_operator:SI 1 "mips_cstore_operator"
|
(match_operator:SI 1 "mips_cstore_operator"
|
[(match_operand:GPR 2 "register_operand")
|
[(match_operand:GPR 2 "register_operand")
|
(match_operand:GPR 3 "nonmemory_operand")]))]
|
(match_operand:GPR 3 "nonmemory_operand")]))]
|
""
|
""
|
{
|
{
|
mips_expand_scc (operands);
|
mips_expand_scc (operands);
|
DONE;
|
DONE;
|
})
|
})
|
|
|
(define_insn "*seq_zero_"
|
(define_insn "*seq_zero_"
|
[(set (match_operand:GPR2 0 "register_operand" "=d")
|
[(set (match_operand:GPR2 0 "register_operand" "=d")
|
(eq:GPR2 (match_operand:GPR 1 "register_operand" "d")
|
(eq:GPR2 (match_operand:GPR 1 "register_operand" "d")
|
(const_int 0)))]
|
(const_int 0)))]
|
"!TARGET_MIPS16 && !ISA_HAS_SEQ_SNE"
|
"!TARGET_MIPS16 && !ISA_HAS_SEQ_SNE"
|
"sltu\t%0,%1,1"
|
"sltu\t%0,%1,1"
|
[(set_attr "type" "slt")
|
[(set_attr "type" "slt")
|
(set_attr "mode" "")])
|
(set_attr "mode" "")])
|
|
|
(define_insn "*seq_zero__mips16"
|
(define_insn "*seq_zero__mips16"
|
[(set (match_operand:GPR2 0 "register_operand" "=t")
|
[(set (match_operand:GPR2 0 "register_operand" "=t")
|
(eq:GPR2 (match_operand:GPR 1 "register_operand" "d")
|
(eq:GPR2 (match_operand:GPR 1 "register_operand" "d")
|
(const_int 0)))]
|
(const_int 0)))]
|
"TARGET_MIPS16 && !ISA_HAS_SEQ_SNE"
|
"TARGET_MIPS16 && !ISA_HAS_SEQ_SNE"
|
"sltu\t%1,1"
|
"sltu\t%1,1"
|
[(set_attr "type" "slt")
|
[(set_attr "type" "slt")
|
(set_attr "mode" "")])
|
(set_attr "mode" "")])
|
|
|
;; Generate sltiu unless using seq results in better code.
|
;; Generate sltiu unless using seq results in better code.
|
(define_insn "*seq__seq"
|
(define_insn "*seq__seq"
|
[(set (match_operand:GPR2 0 "register_operand" "=d,d,d")
|
[(set (match_operand:GPR2 0 "register_operand" "=d,d,d")
|
(eq:GPR2 (match_operand:GPR 1 "register_operand" "%d,d,d")
|
(eq:GPR2 (match_operand:GPR 1 "register_operand" "%d,d,d")
|
(match_operand:GPR 2 "reg_imm10_operand" "d,J,YB")))]
|
(match_operand:GPR 2 "reg_imm10_operand" "d,J,YB")))]
|
"ISA_HAS_SEQ_SNE"
|
"ISA_HAS_SEQ_SNE"
|
"@
|
"@
|
seq\t%0,%1,%2
|
seq\t%0,%1,%2
|
sltiu\t%0,%1,1
|
sltiu\t%0,%1,1
|
seqi\t%0,%1,%2"
|
seqi\t%0,%1,%2"
|
[(set_attr "type" "slt")
|
[(set_attr "type" "slt")
|
(set_attr "mode" "")])
|
(set_attr "mode" "")])
|
|
|
(define_insn "*sne_zero_"
|
(define_insn "*sne_zero_"
|
[(set (match_operand:GPR2 0 "register_operand" "=d")
|
[(set (match_operand:GPR2 0 "register_operand" "=d")
|
(ne:GPR2 (match_operand:GPR 1 "register_operand" "d")
|
(ne:GPR2 (match_operand:GPR 1 "register_operand" "d")
|
(const_int 0)))]
|
(const_int 0)))]
|
"!TARGET_MIPS16 && !ISA_HAS_SEQ_SNE"
|
"!TARGET_MIPS16 && !ISA_HAS_SEQ_SNE"
|
"sltu\t%0,%.,%1"
|
"sltu\t%0,%.,%1"
|
[(set_attr "type" "slt")
|
[(set_attr "type" "slt")
|
(set_attr "mode" "")])
|
(set_attr "mode" "")])
|
|
|
;; Generate sltu unless using sne results in better code.
|
;; Generate sltu unless using sne results in better code.
|
(define_insn "*sne__sne"
|
(define_insn "*sne__sne"
|
[(set (match_operand:GPR2 0 "register_operand" "=d,d,d")
|
[(set (match_operand:GPR2 0 "register_operand" "=d,d,d")
|
(ne:GPR2 (match_operand:GPR 1 "register_operand" "%d,d,d")
|
(ne:GPR2 (match_operand:GPR 1 "register_operand" "%d,d,d")
|
(match_operand:GPR 2 "reg_imm10_operand" "d,J,YB")))]
|
(match_operand:GPR 2 "reg_imm10_operand" "d,J,YB")))]
|
"ISA_HAS_SEQ_SNE"
|
"ISA_HAS_SEQ_SNE"
|
"@
|
"@
|
sne\t%0,%1,%2
|
sne\t%0,%1,%2
|
sltu\t%0,%.,%1
|
sltu\t%0,%.,%1
|
snei\t%0,%1,%2"
|
snei\t%0,%1,%2"
|
[(set_attr "type" "slt")
|
[(set_attr "type" "slt")
|
(set_attr "mode" "")])
|
(set_attr "mode" "")])
|
|
|
(define_insn "*sgt_"
|
(define_insn "*sgt_"
|
[(set (match_operand:GPR2 0 "register_operand" "=d")
|
[(set (match_operand:GPR2 0 "register_operand" "=d")
|
(any_gt:GPR2 (match_operand:GPR 1 "register_operand" "d")
|
(any_gt:GPR2 (match_operand:GPR 1 "register_operand" "d")
|
(match_operand:GPR 2 "reg_or_0_operand" "dJ")))]
|
(match_operand:GPR 2 "reg_or_0_operand" "dJ")))]
|
"!TARGET_MIPS16"
|
"!TARGET_MIPS16"
|
"slt\t%0,%z2,%1"
|
"slt\t%0,%z2,%1"
|
[(set_attr "type" "slt")
|
[(set_attr "type" "slt")
|
(set_attr "mode" "")])
|
(set_attr "mode" "")])
|
|
|
(define_insn "*sgt__mips16"
|
(define_insn "*sgt__mips16"
|
[(set (match_operand:GPR2 0 "register_operand" "=t")
|
[(set (match_operand:GPR2 0 "register_operand" "=t")
|
(any_gt:GPR2 (match_operand:GPR 1 "register_operand" "d")
|
(any_gt:GPR2 (match_operand:GPR 1 "register_operand" "d")
|
(match_operand:GPR 2 "register_operand" "d")))]
|
(match_operand:GPR 2 "register_operand" "d")))]
|
"TARGET_MIPS16"
|
"TARGET_MIPS16"
|
"slt\t%2,%1"
|
"slt\t%2,%1"
|
[(set_attr "type" "slt")
|
[(set_attr "type" "slt")
|
(set_attr "mode" "")])
|
(set_attr "mode" "")])
|
|
|
(define_insn "*sge_"
|
(define_insn "*sge_"
|
[(set (match_operand:GPR2 0 "register_operand" "=d")
|
[(set (match_operand:GPR2 0 "register_operand" "=d")
|
(any_ge:GPR2 (match_operand:GPR 1 "register_operand" "d")
|
(any_ge:GPR2 (match_operand:GPR 1 "register_operand" "d")
|
(const_int 1)))]
|
(const_int 1)))]
|
"!TARGET_MIPS16"
|
"!TARGET_MIPS16"
|
"slt\t%0,%.,%1"
|
"slt\t%0,%.,%1"
|
[(set_attr "type" "slt")
|
[(set_attr "type" "slt")
|
(set_attr "mode" "")])
|
(set_attr "mode" "")])
|
|
|
(define_insn "*slt_"
|
(define_insn "*slt_"
|
[(set (match_operand:GPR2 0 "register_operand" "=d")
|
[(set (match_operand:GPR2 0 "register_operand" "=d")
|
(any_lt:GPR2 (match_operand:GPR 1 "register_operand" "d")
|
(any_lt:GPR2 (match_operand:GPR 1 "register_operand" "d")
|
(match_operand:GPR 2 "arith_operand" "dI")))]
|
(match_operand:GPR 2 "arith_operand" "dI")))]
|
"!TARGET_MIPS16"
|
"!TARGET_MIPS16"
|
"slt\t%0,%1,%2"
|
"slt\t%0,%1,%2"
|
[(set_attr "type" "slt")
|
[(set_attr "type" "slt")
|
(set_attr "mode" "")])
|
(set_attr "mode" "")])
|
|
|
(define_insn "*slt__mips16"
|
(define_insn "*slt__mips16"
|
[(set (match_operand:GPR2 0 "register_operand" "=t,t")
|
[(set (match_operand:GPR2 0 "register_operand" "=t,t")
|
(any_lt:GPR2 (match_operand:GPR 1 "register_operand" "d,d")
|
(any_lt:GPR2 (match_operand:GPR 1 "register_operand" "d,d")
|
(match_operand:GPR 2 "arith_operand" "d,I")))]
|
(match_operand:GPR 2 "arith_operand" "d,I")))]
|
"TARGET_MIPS16"
|
"TARGET_MIPS16"
|
"slt\t%1,%2"
|
"slt\t%1,%2"
|
[(set_attr "type" "slt")
|
[(set_attr "type" "slt")
|
(set_attr "mode" "")
|
(set_attr "mode" "")
|
(set_attr_alternative "length"
|
(set_attr_alternative "length"
|
[(const_int 4)
|
[(const_int 4)
|
(if_then_else (match_operand 2 "m16_uimm8_1")
|
(if_then_else (match_operand 2 "m16_uimm8_1")
|
(const_int 4)
|
(const_int 4)
|
(const_int 8))])])
|
(const_int 8))])])
|
|
|
(define_insn "*sle_"
|
(define_insn "*sle_"
|
[(set (match_operand:GPR2 0 "register_operand" "=d")
|
[(set (match_operand:GPR2 0 "register_operand" "=d")
|
(any_le:GPR2 (match_operand:GPR 1 "register_operand" "d")
|
(any_le:GPR2 (match_operand:GPR 1 "register_operand" "d")
|
(match_operand:GPR 2 "sle_operand" "")))]
|
(match_operand:GPR 2 "sle_operand" "")))]
|
"!TARGET_MIPS16"
|
"!TARGET_MIPS16"
|
{
|
{
|
operands[2] = GEN_INT (INTVAL (operands[2]) + 1);
|
operands[2] = GEN_INT (INTVAL (operands[2]) + 1);
|
return "slt\t%0,%1,%2";
|
return "slt\t%0,%1,%2";
|
}
|
}
|
[(set_attr "type" "slt")
|
[(set_attr "type" "slt")
|
(set_attr "mode" "")])
|
(set_attr "mode" "")])
|
|
|
(define_insn "*sle__mips16"
|
(define_insn "*sle__mips16"
|
[(set (match_operand:GPR2 0 "register_operand" "=t")
|
[(set (match_operand:GPR2 0 "register_operand" "=t")
|
(any_le:GPR2 (match_operand:GPR 1 "register_operand" "d")
|
(any_le:GPR2 (match_operand:GPR 1 "register_operand" "d")
|
(match_operand:GPR 2 "sle_operand" "")))]
|
(match_operand:GPR 2 "sle_operand" "")))]
|
"TARGET_MIPS16"
|
"TARGET_MIPS16"
|
{
|
{
|
operands[2] = GEN_INT (INTVAL (operands[2]) + 1);
|
operands[2] = GEN_INT (INTVAL (operands[2]) + 1);
|
return "slt\t%1,%2";
|
return "slt\t%1,%2";
|
}
|
}
|
[(set_attr "type" "slt")
|
[(set_attr "type" "slt")
|
(set_attr "mode" "")
|
(set_attr "mode" "")
|
(set (attr "length") (if_then_else (match_operand 2 "m16_uimm8_m1_1")
|
(set (attr "length") (if_then_else (match_operand 2 "m16_uimm8_m1_1")
|
(const_int 4)
|
(const_int 4)
|
(const_int 8)))])
|
(const_int 8)))])
|
|
|
;;
|
;;
|
;; ....................
|
;; ....................
|
;;
|
;;
|
;; FLOATING POINT COMPARISONS
|
;; FLOATING POINT COMPARISONS
|
;;
|
;;
|
;; ....................
|
;; ....................
|
|
|
(define_insn "s_"
|
(define_insn "s_"
|
[(set (match_operand:CC 0 "register_operand" "=z")
|
[(set (match_operand:CC 0 "register_operand" "=z")
|
(fcond:CC (match_operand:SCALARF 1 "register_operand" "f")
|
(fcond:CC (match_operand:SCALARF 1 "register_operand" "f")
|
(match_operand:SCALARF 2 "register_operand" "f")))]
|
(match_operand:SCALARF 2 "register_operand" "f")))]
|
""
|
""
|
"c..\t%Z0%1,%2"
|
"c..\t%Z0%1,%2"
|
[(set_attr "type" "fcmp")
|
[(set_attr "type" "fcmp")
|
(set_attr "mode" "FPSW")])
|
(set_attr "mode" "FPSW")])
|
|
|
(define_insn "s_"
|
(define_insn "s_"
|
[(set (match_operand:CC 0 "register_operand" "=z")
|
[(set (match_operand:CC 0 "register_operand" "=z")
|
(swapped_fcond:CC (match_operand:SCALARF 1 "register_operand" "f")
|
(swapped_fcond:CC (match_operand:SCALARF 1 "register_operand" "f")
|
(match_operand:SCALARF 2 "register_operand" "f")))]
|
(match_operand:SCALARF 2 "register_operand" "f")))]
|
""
|
""
|
"c..\t%Z0%2,%1"
|
"c..\t%Z0%2,%1"
|
[(set_attr "type" "fcmp")
|
[(set_attr "type" "fcmp")
|
(set_attr "mode" "FPSW")])
|
(set_attr "mode" "FPSW")])
|
|
|
;;
|
;;
|
;; ....................
|
;; ....................
|
;;
|
;;
|
;; UNCONDITIONAL BRANCHES
|
;; UNCONDITIONAL BRANCHES
|
;;
|
;;
|
;; ....................
|
;; ....................
|
|
|
;; Unconditional branches.
|
;; Unconditional branches.
|
|
|
(define_expand "jump"
|
(define_expand "jump"
|
[(set (pc)
|
[(set (pc)
|
(label_ref (match_operand 0)))])
|
(label_ref (match_operand 0)))])
|
|
|
(define_insn "*jump_absolute"
|
(define_insn "*jump_absolute"
|
[(set (pc)
|
[(set (pc)
|
(label_ref (match_operand 0)))]
|
(label_ref (match_operand 0)))]
|
"!TARGET_MIPS16 && TARGET_ABSOLUTE_JUMPS"
|
"!TARGET_MIPS16 && TARGET_ABSOLUTE_JUMPS"
|
{ return MIPS_ABSOLUTE_JUMP ("%*j\t%l0%/"); }
|
{ return MIPS_ABSOLUTE_JUMP ("%*j\t%l0%/"); }
|
[(set_attr "type" "jump")])
|
[(set_attr "type" "jump")])
|
|
|
(define_insn "*jump_pic"
|
(define_insn "*jump_pic"
|
[(set (pc)
|
[(set (pc)
|
(label_ref (match_operand 0)))]
|
(label_ref (match_operand 0)))]
|
"!TARGET_MIPS16 && !TARGET_ABSOLUTE_JUMPS"
|
"!TARGET_MIPS16 && !TARGET_ABSOLUTE_JUMPS"
|
{
|
{
|
if (get_attr_length (insn) <= 8)
|
if (get_attr_length (insn) <= 8)
|
return "%*b\t%l0%/";
|
return "%*b\t%l0%/";
|
else
|
else
|
{
|
{
|
mips_output_load_label (operands[0]);
|
mips_output_load_label (operands[0]);
|
return "%*jr\t%@%/%]";
|
return "%*jr\t%@%/%]";
|
}
|
}
|
}
|
}
|
[(set_attr "type" "branch")])
|
[(set_attr "type" "branch")])
|
|
|
;; We need a different insn for the mips16, because a mips16 branch
|
;; We need a different insn for the mips16, because a mips16 branch
|
;; does not have a delay slot.
|
;; does not have a delay slot.
|
|
|
(define_insn "*jump_mips16"
|
(define_insn "*jump_mips16"
|
[(set (pc)
|
[(set (pc)
|
(label_ref (match_operand 0 "" "")))]
|
(label_ref (match_operand 0 "" "")))]
|
"TARGET_MIPS16"
|
"TARGET_MIPS16"
|
"b\t%l0"
|
"b\t%l0"
|
[(set_attr "type" "branch")])
|
[(set_attr "type" "branch")])
|
|
|
(define_expand "indirect_jump"
|
(define_expand "indirect_jump"
|
[(set (pc) (match_operand 0 "register_operand"))]
|
[(set (pc) (match_operand 0 "register_operand"))]
|
""
|
""
|
{
|
{
|
operands[0] = force_reg (Pmode, operands[0]);
|
operands[0] = force_reg (Pmode, operands[0]);
|
if (Pmode == SImode)
|
if (Pmode == SImode)
|
emit_jump_insn (gen_indirect_jumpsi (operands[0]));
|
emit_jump_insn (gen_indirect_jumpsi (operands[0]));
|
else
|
else
|
emit_jump_insn (gen_indirect_jumpdi (operands[0]));
|
emit_jump_insn (gen_indirect_jumpdi (operands[0]));
|
DONE;
|
DONE;
|
})
|
})
|
|
|
(define_insn "indirect_jump"
|
(define_insn "indirect_jump"
|
[(set (pc) (match_operand:P 0 "register_operand" "d"))]
|
[(set (pc) (match_operand:P 0 "register_operand" "d"))]
|
""
|
""
|
"%*j\t%0%/"
|
"%*j\t%0%/"
|
[(set_attr "type" "jump")
|
[(set_attr "type" "jump")
|
(set_attr "mode" "none")])
|
(set_attr "mode" "none")])
|
|
|
(define_expand "tablejump"
|
(define_expand "tablejump"
|
[(set (pc)
|
[(set (pc)
|
(match_operand 0 "register_operand"))
|
(match_operand 0 "register_operand"))
|
(use (label_ref (match_operand 1 "")))]
|
(use (label_ref (match_operand 1 "")))]
|
""
|
""
|
{
|
{
|
if (TARGET_MIPS16_SHORT_JUMP_TABLES)
|
if (TARGET_MIPS16_SHORT_JUMP_TABLES)
|
operands[0] = expand_binop (Pmode, add_optab,
|
operands[0] = expand_binop (Pmode, add_optab,
|
convert_to_mode (Pmode, operands[0], false),
|
convert_to_mode (Pmode, operands[0], false),
|
gen_rtx_LABEL_REF (Pmode, operands[1]),
|
gen_rtx_LABEL_REF (Pmode, operands[1]),
|
0, 0, OPTAB_WIDEN);
|
0, 0, OPTAB_WIDEN);
|
else if (TARGET_GPWORD)
|
else if (TARGET_GPWORD)
|
operands[0] = expand_binop (Pmode, add_optab, operands[0],
|
operands[0] = expand_binop (Pmode, add_optab, operands[0],
|
pic_offset_table_rtx, 0, 0, OPTAB_WIDEN);
|
pic_offset_table_rtx, 0, 0, OPTAB_WIDEN);
|
else if (TARGET_RTP_PIC)
|
else if (TARGET_RTP_PIC)
|
{
|
{
|
/* When generating RTP PIC, we use case table entries that are relative
|
/* When generating RTP PIC, we use case table entries that are relative
|
to the start of the function. Add the function's address to the
|
to the start of the function. Add the function's address to the
|
value we loaded. */
|
value we loaded. */
|
rtx start = get_hard_reg_initial_val (Pmode, PIC_FUNCTION_ADDR_REGNUM);
|
rtx start = get_hard_reg_initial_val (Pmode, PIC_FUNCTION_ADDR_REGNUM);
|
operands[0] = expand_binop (ptr_mode, add_optab, operands[0],
|
operands[0] = expand_binop (ptr_mode, add_optab, operands[0],
|
start, 0, 0, OPTAB_WIDEN);
|
start, 0, 0, OPTAB_WIDEN);
|
}
|
}
|
|
|
if (Pmode == SImode)
|
if (Pmode == SImode)
|
emit_jump_insn (gen_tablejumpsi (operands[0], operands[1]));
|
emit_jump_insn (gen_tablejumpsi (operands[0], operands[1]));
|
else
|
else
|
emit_jump_insn (gen_tablejumpdi (operands[0], operands[1]));
|
emit_jump_insn (gen_tablejumpdi (operands[0], operands[1]));
|
DONE;
|
DONE;
|
})
|
})
|
|
|
(define_insn "tablejump"
|
(define_insn "tablejump"
|
[(set (pc)
|
[(set (pc)
|
(match_operand:P 0 "register_operand" "d"))
|
(match_operand:P 0 "register_operand" "d"))
|
(use (label_ref (match_operand 1 "" "")))]
|
(use (label_ref (match_operand 1 "" "")))]
|
""
|
""
|
"%*j\t%0%/"
|
"%*j\t%0%/"
|
[(set_attr "type" "jump")
|
[(set_attr "type" "jump")
|
(set_attr "mode" "none")])
|
(set_attr "mode" "none")])
|
|
|
;; For TARGET_USE_GOT, we save the gp in the jmp_buf as well.
|
;; For TARGET_USE_GOT, we save the gp in the jmp_buf as well.
|
;; While it is possible to either pull it off the stack (in the
|
;; While it is possible to either pull it off the stack (in the
|
;; o32 case) or recalculate it given t9 and our target label,
|
;; o32 case) or recalculate it given t9 and our target label,
|
;; it takes 3 or 4 insns to do so.
|
;; it takes 3 or 4 insns to do so.
|
|
|
(define_expand "builtin_setjmp_setup"
|
(define_expand "builtin_setjmp_setup"
|
[(use (match_operand 0 "register_operand"))]
|
[(use (match_operand 0 "register_operand"))]
|
"TARGET_USE_GOT"
|
"TARGET_USE_GOT"
|
{
|
{
|
rtx addr;
|
rtx addr;
|
|
|
addr = plus_constant (operands[0], GET_MODE_SIZE (Pmode) * 3);
|
addr = plus_constant (operands[0], GET_MODE_SIZE (Pmode) * 3);
|
mips_emit_move (gen_rtx_MEM (Pmode, addr), pic_offset_table_rtx);
|
mips_emit_move (gen_rtx_MEM (Pmode, addr), pic_offset_table_rtx);
|
DONE;
|
DONE;
|
})
|
})
|
|
|
;; Restore the gp that we saved above. Despite the earlier comment, it seems
|
;; Restore the gp that we saved above. Despite the earlier comment, it seems
|
;; that older code did recalculate the gp from $25. Continue to jump through
|
;; that older code did recalculate the gp from $25. Continue to jump through
|
;; $25 for compatibility (we lose nothing by doing so).
|
;; $25 for compatibility (we lose nothing by doing so).
|
|
|
(define_expand "builtin_longjmp"
|
(define_expand "builtin_longjmp"
|
[(use (match_operand 0 "register_operand"))]
|
[(use (match_operand 0 "register_operand"))]
|
"TARGET_USE_GOT"
|
"TARGET_USE_GOT"
|
{
|
{
|
/* The elements of the buffer are, in order: */
|
/* The elements of the buffer are, in order: */
|
int W = GET_MODE_SIZE (Pmode);
|
int W = GET_MODE_SIZE (Pmode);
|
rtx fp = gen_rtx_MEM (Pmode, operands[0]);
|
rtx fp = gen_rtx_MEM (Pmode, operands[0]);
|
rtx lab = gen_rtx_MEM (Pmode, plus_constant (operands[0], 1*W));
|
rtx lab = gen_rtx_MEM (Pmode, plus_constant (operands[0], 1*W));
|
rtx stack = gen_rtx_MEM (Pmode, plus_constant (operands[0], 2*W));
|
rtx stack = gen_rtx_MEM (Pmode, plus_constant (operands[0], 2*W));
|
rtx gpv = gen_rtx_MEM (Pmode, plus_constant (operands[0], 3*W));
|
rtx gpv = gen_rtx_MEM (Pmode, plus_constant (operands[0], 3*W));
|
rtx pv = gen_rtx_REG (Pmode, PIC_FUNCTION_ADDR_REGNUM);
|
rtx pv = gen_rtx_REG (Pmode, PIC_FUNCTION_ADDR_REGNUM);
|
/* Use gen_raw_REG to avoid being given pic_offset_table_rtx.
|
/* Use gen_raw_REG to avoid being given pic_offset_table_rtx.
|
The target is bound to be using $28 as the global pointer
|
The target is bound to be using $28 as the global pointer
|
but the current function might not be. */
|
but the current function might not be. */
|
rtx gp = gen_raw_REG (Pmode, GLOBAL_POINTER_REGNUM);
|
rtx gp = gen_raw_REG (Pmode, GLOBAL_POINTER_REGNUM);
|
|
|
/* This bit is similar to expand_builtin_longjmp except that it
|
/* This bit is similar to expand_builtin_longjmp except that it
|
restores $gp as well. */
|
restores $gp as well. */
|
mips_emit_move (hard_frame_pointer_rtx, fp);
|
mips_emit_move (hard_frame_pointer_rtx, fp);
|
mips_emit_move (pv, lab);
|
mips_emit_move (pv, lab);
|
emit_stack_restore (SAVE_NONLOCAL, stack, NULL_RTX);
|
emit_stack_restore (SAVE_NONLOCAL, stack, NULL_RTX);
|
mips_emit_move (gp, gpv);
|
mips_emit_move (gp, gpv);
|
emit_use (hard_frame_pointer_rtx);
|
emit_use (hard_frame_pointer_rtx);
|
emit_use (stack_pointer_rtx);
|
emit_use (stack_pointer_rtx);
|
emit_use (gp);
|
emit_use (gp);
|
emit_indirect_jump (pv);
|
emit_indirect_jump (pv);
|
DONE;
|
DONE;
|
})
|
})
|
|
|
;;
|
;;
|
;; ....................
|
;; ....................
|
;;
|
;;
|
;; Function prologue/epilogue
|
;; Function prologue/epilogue
|
;;
|
;;
|
;; ....................
|
;; ....................
|
;;
|
;;
|
|
|
(define_expand "prologue"
|
(define_expand "prologue"
|
[(const_int 1)]
|
[(const_int 1)]
|
""
|
""
|
{
|
{
|
mips_expand_prologue ();
|
mips_expand_prologue ();
|
DONE;
|
DONE;
|
})
|
})
|
|
|
;; Block any insns from being moved before this point, since the
|
;; Block any insns from being moved before this point, since the
|
;; profiling call to mcount can use various registers that aren't
|
;; profiling call to mcount can use various registers that aren't
|
;; saved or used to pass arguments.
|
;; saved or used to pass arguments.
|
|
|
(define_insn "blockage"
|
(define_insn "blockage"
|
[(unspec_volatile [(const_int 0)] UNSPEC_BLOCKAGE)]
|
[(unspec_volatile [(const_int 0)] UNSPEC_BLOCKAGE)]
|
""
|
""
|
""
|
""
|
[(set_attr "type" "ghost")
|
[(set_attr "type" "ghost")
|
(set_attr "mode" "none")])
|
(set_attr "mode" "none")])
|
|
|
(define_expand "epilogue"
|
(define_expand "epilogue"
|
[(const_int 2)]
|
[(const_int 2)]
|
""
|
""
|
{
|
{
|
mips_expand_epilogue (false);
|
mips_expand_epilogue (false);
|
DONE;
|
DONE;
|
})
|
})
|
|
|
(define_expand "sibcall_epilogue"
|
(define_expand "sibcall_epilogue"
|
[(const_int 2)]
|
[(const_int 2)]
|
""
|
""
|
{
|
{
|
mips_expand_epilogue (true);
|
mips_expand_epilogue (true);
|
DONE;
|
DONE;
|
})
|
})
|
|
|
;; Trivial return. Make it look like a normal return insn as that
|
;; Trivial return. Make it look like a normal return insn as that
|
;; allows jump optimizations to work better.
|
;; allows jump optimizations to work better.
|
|
|
(define_expand "return"
|
(define_expand "return"
|
[(return)]
|
[(return)]
|
"mips_can_use_return_insn ()"
|
"mips_can_use_return_insn ()"
|
{ mips_expand_before_return (); })
|
{ mips_expand_before_return (); })
|
|
|
(define_insn "*return"
|
(define_insn "*return"
|
[(return)]
|
[(return)]
|
"mips_can_use_return_insn ()"
|
"mips_can_use_return_insn ()"
|
"%*j\t$31%/"
|
"%*j\t$31%/"
|
[(set_attr "type" "jump")
|
[(set_attr "type" "jump")
|
(set_attr "mode" "none")])
|
(set_attr "mode" "none")])
|
|
|
;; Normal return.
|
;; Normal return.
|
|
|
(define_insn "return_internal"
|
(define_insn "return_internal"
|
[(return)
|
[(return)
|
(use (match_operand 0 "pmode_register_operand" ""))]
|
(use (match_operand 0 "pmode_register_operand" ""))]
|
""
|
""
|
"%*j\t%0%/"
|
"%*j\t%0%/"
|
[(set_attr "type" "jump")
|
[(set_attr "type" "jump")
|
(set_attr "mode" "none")])
|
(set_attr "mode" "none")])
|
|
|
;; Exception return.
|
;; Exception return.
|
(define_insn "mips_eret"
|
(define_insn "mips_eret"
|
[(return)
|
[(return)
|
(unspec_volatile [(const_int 0)] UNSPEC_ERET)]
|
(unspec_volatile [(const_int 0)] UNSPEC_ERET)]
|
""
|
""
|
"eret"
|
"eret"
|
[(set_attr "type" "trap")
|
[(set_attr "type" "trap")
|
(set_attr "mode" "none")])
|
(set_attr "mode" "none")])
|
|
|
;; Debug exception return.
|
;; Debug exception return.
|
(define_insn "mips_deret"
|
(define_insn "mips_deret"
|
[(return)
|
[(return)
|
(unspec_volatile [(const_int 0)] UNSPEC_DERET)]
|
(unspec_volatile [(const_int 0)] UNSPEC_DERET)]
|
""
|
""
|
"deret"
|
"deret"
|
[(set_attr "type" "trap")
|
[(set_attr "type" "trap")
|
(set_attr "mode" "none")])
|
(set_attr "mode" "none")])
|
|
|
;; Disable interrupts.
|
;; Disable interrupts.
|
(define_insn "mips_di"
|
(define_insn "mips_di"
|
[(unspec_volatile [(const_int 0)] UNSPEC_DI)]
|
[(unspec_volatile [(const_int 0)] UNSPEC_DI)]
|
""
|
""
|
"di"
|
"di"
|
[(set_attr "type" "trap")
|
[(set_attr "type" "trap")
|
(set_attr "mode" "none")])
|
(set_attr "mode" "none")])
|
|
|
;; Execution hazard barrier.
|
;; Execution hazard barrier.
|
(define_insn "mips_ehb"
|
(define_insn "mips_ehb"
|
[(unspec_volatile [(const_int 0)] UNSPEC_EHB)]
|
[(unspec_volatile [(const_int 0)] UNSPEC_EHB)]
|
""
|
""
|
"ehb"
|
"ehb"
|
[(set_attr "type" "trap")
|
[(set_attr "type" "trap")
|
(set_attr "mode" "none")])
|
(set_attr "mode" "none")])
|
|
|
;; Read GPR from previous shadow register set.
|
;; Read GPR from previous shadow register set.
|
(define_insn "mips_rdpgpr"
|
(define_insn "mips_rdpgpr"
|
[(set (match_operand:SI 0 "register_operand" "=d")
|
[(set (match_operand:SI 0 "register_operand" "=d")
|
(unspec_volatile:SI [(match_operand:SI 1 "register_operand" "d")]
|
(unspec_volatile:SI [(match_operand:SI 1 "register_operand" "d")]
|
UNSPEC_RDPGPR))]
|
UNSPEC_RDPGPR))]
|
""
|
""
|
"rdpgpr\t%0,%1"
|
"rdpgpr\t%0,%1"
|
[(set_attr "type" "move")
|
[(set_attr "type" "move")
|
(set_attr "mode" "SI")])
|
(set_attr "mode" "SI")])
|
|
|
;; Move involving COP0 registers.
|
;; Move involving COP0 registers.
|
(define_insn "cop0_move"
|
(define_insn "cop0_move"
|
[(set (match_operand:SI 0 "register_operand" "=B,d")
|
[(set (match_operand:SI 0 "register_operand" "=B,d")
|
(unspec_volatile:SI [(match_operand:SI 1 "register_operand" "d,B")]
|
(unspec_volatile:SI [(match_operand:SI 1 "register_operand" "d,B")]
|
UNSPEC_COP0))]
|
UNSPEC_COP0))]
|
""
|
""
|
{ return mips_output_move (operands[0], operands[1]); }
|
{ return mips_output_move (operands[0], operands[1]); }
|
[(set_attr "type" "mtc,mfc")
|
[(set_attr "type" "mtc,mfc")
|
(set_attr "mode" "SI")])
|
(set_attr "mode" "SI")])
|
|
|
;; This is used in compiling the unwind routines.
|
;; This is used in compiling the unwind routines.
|
(define_expand "eh_return"
|
(define_expand "eh_return"
|
[(use (match_operand 0 "general_operand"))]
|
[(use (match_operand 0 "general_operand"))]
|
""
|
""
|
{
|
{
|
if (GET_MODE (operands[0]) != word_mode)
|
if (GET_MODE (operands[0]) != word_mode)
|
operands[0] = convert_to_mode (word_mode, operands[0], 0);
|
operands[0] = convert_to_mode (word_mode, operands[0], 0);
|
if (TARGET_64BIT)
|
if (TARGET_64BIT)
|
emit_insn (gen_eh_set_lr_di (operands[0]));
|
emit_insn (gen_eh_set_lr_di (operands[0]));
|
else
|
else
|
emit_insn (gen_eh_set_lr_si (operands[0]));
|
emit_insn (gen_eh_set_lr_si (operands[0]));
|
DONE;
|
DONE;
|
})
|
})
|
|
|
;; Clobber the return address on the stack. We can't expand this
|
;; Clobber the return address on the stack. We can't expand this
|
;; until we know where it will be put in the stack frame.
|
;; until we know where it will be put in the stack frame.
|
|
|
(define_insn "eh_set_lr_si"
|
(define_insn "eh_set_lr_si"
|
[(unspec [(match_operand:SI 0 "register_operand" "d")] UNSPEC_EH_RETURN)
|
[(unspec [(match_operand:SI 0 "register_operand" "d")] UNSPEC_EH_RETURN)
|
(clobber (match_scratch:SI 1 "=&d"))]
|
(clobber (match_scratch:SI 1 "=&d"))]
|
"! TARGET_64BIT"
|
"! TARGET_64BIT"
|
"#")
|
"#")
|
|
|
(define_insn "eh_set_lr_di"
|
(define_insn "eh_set_lr_di"
|
[(unspec [(match_operand:DI 0 "register_operand" "d")] UNSPEC_EH_RETURN)
|
[(unspec [(match_operand:DI 0 "register_operand" "d")] UNSPEC_EH_RETURN)
|
(clobber (match_scratch:DI 1 "=&d"))]
|
(clobber (match_scratch:DI 1 "=&d"))]
|
"TARGET_64BIT"
|
"TARGET_64BIT"
|
"#")
|
"#")
|
|
|
(define_split
|
(define_split
|
[(unspec [(match_operand 0 "register_operand")] UNSPEC_EH_RETURN)
|
[(unspec [(match_operand 0 "register_operand")] UNSPEC_EH_RETURN)
|
(clobber (match_scratch 1))]
|
(clobber (match_scratch 1))]
|
"reload_completed"
|
"reload_completed"
|
[(const_int 0)]
|
[(const_int 0)]
|
{
|
{
|
mips_set_return_address (operands[0], operands[1]);
|
mips_set_return_address (operands[0], operands[1]);
|
DONE;
|
DONE;
|
})
|
})
|
|
|
(define_expand "exception_receiver"
|
(define_expand "exception_receiver"
|
[(const_int 0)]
|
[(const_int 0)]
|
"TARGET_USE_GOT"
|
"TARGET_USE_GOT"
|
{
|
{
|
/* See the comment above load_call for details. */
|
/* See the comment above load_call for details. */
|
emit_insn (gen_set_got_version ());
|
emit_insn (gen_set_got_version ());
|
|
|
/* If we have a call-clobbered $gp, restore it from its save slot. */
|
/* If we have a call-clobbered $gp, restore it from its save slot. */
|
if (HAVE_restore_gp)
|
if (HAVE_restore_gp)
|
emit_insn (gen_restore_gp ());
|
emit_insn (gen_restore_gp ());
|
DONE;
|
DONE;
|
})
|
})
|
|
|
(define_expand "nonlocal_goto_receiver"
|
(define_expand "nonlocal_goto_receiver"
|
[(const_int 0)]
|
[(const_int 0)]
|
"TARGET_USE_GOT"
|
"TARGET_USE_GOT"
|
{
|
{
|
/* See the comment above load_call for details. */
|
/* See the comment above load_call for details. */
|
emit_insn (gen_set_got_version ());
|
emit_insn (gen_set_got_version ());
|
DONE;
|
DONE;
|
})
|
})
|
|
|
;; Restore $gp from its .cprestore stack slot. The instruction remains
|
;; Restore $gp from its .cprestore stack slot. The instruction remains
|
;; volatile until all uses of $28 are exposed.
|
;; volatile until all uses of $28 are exposed.
|
(define_insn_and_split "restore_gp"
|
(define_insn_and_split "restore_gp"
|
[(set (reg:SI 28)
|
[(set (reg:SI 28)
|
(unspec_volatile:SI [(const_int 0)] UNSPEC_RESTORE_GP))
|
(unspec_volatile:SI [(const_int 0)] UNSPEC_RESTORE_GP))
|
(clobber (match_scratch:SI 0 "=&d"))]
|
(clobber (match_scratch:SI 0 "=&d"))]
|
"TARGET_CALL_CLOBBERED_GP"
|
"TARGET_CALL_CLOBBERED_GP"
|
"#"
|
"#"
|
"&& epilogue_completed"
|
"&& epilogue_completed"
|
[(const_int 0)]
|
[(const_int 0)]
|
{
|
{
|
mips_restore_gp_from_cprestore_slot (operands[0]);
|
mips_restore_gp_from_cprestore_slot (operands[0]);
|
DONE;
|
DONE;
|
}
|
}
|
[(set_attr "type" "ghost")])
|
[(set_attr "type" "ghost")])
|
|
|
;; Move between $gp and its register save slot.
|
;; Move between $gp and its register save slot.
|
(define_insn_and_split "move_gp"
|
(define_insn_and_split "move_gp"
|
[(set (match_operand:GPR 0 "nonimmediate_operand" "=d,m")
|
[(set (match_operand:GPR 0 "nonimmediate_operand" "=d,m")
|
(unspec:GPR [(match_operand:GPR 1 "move_operand" "m,d")]
|
(unspec:GPR [(match_operand:GPR 1 "move_operand" "m,d")]
|
UNSPEC_MOVE_GP))]
|
UNSPEC_MOVE_GP))]
|
""
|
""
|
{ return mips_must_initialize_gp_p () ? "#" : ""; }
|
{ return mips_must_initialize_gp_p () ? "#" : ""; }
|
"mips_must_initialize_gp_p ()"
|
"mips_must_initialize_gp_p ()"
|
[(const_int 0)]
|
[(const_int 0)]
|
{
|
{
|
mips_emit_move (operands[0], operands[1]);
|
mips_emit_move (operands[0], operands[1]);
|
DONE;
|
DONE;
|
}
|
}
|
[(set_attr "type" "ghost")])
|
[(set_attr "type" "ghost")])
|
|
|
;;
|
;;
|
;; ....................
|
;; ....................
|
;;
|
;;
|
;; FUNCTION CALLS
|
;; FUNCTION CALLS
|
;;
|
;;
|
;; ....................
|
;; ....................
|
|
|
;; Instructions to load a call address from the GOT. The address might
|
;; Instructions to load a call address from the GOT. The address might
|
;; point to a function or to a lazy binding stub. In the latter case,
|
;; point to a function or to a lazy binding stub. In the latter case,
|
;; the stub will use the dynamic linker to resolve the function, which
|
;; the stub will use the dynamic linker to resolve the function, which
|
;; in turn will change the GOT entry to point to the function's real
|
;; in turn will change the GOT entry to point to the function's real
|
;; address.
|
;; address.
|
;;
|
;;
|
;; This means that every call, even pure and constant ones, can
|
;; This means that every call, even pure and constant ones, can
|
;; potentially modify the GOT entry. And once a stub has been called,
|
;; potentially modify the GOT entry. And once a stub has been called,
|
;; we must not call it again.
|
;; we must not call it again.
|
;;
|
;;
|
;; We represent this restriction using an imaginary, fixed, call-saved
|
;; We represent this restriction using an imaginary, fixed, call-saved
|
;; register called GOT_VERSION_REGNUM. The idea is to make the register
|
;; register called GOT_VERSION_REGNUM. The idea is to make the register
|
;; live throughout the function and to change its value after every
|
;; live throughout the function and to change its value after every
|
;; potential call site. This stops any rtx value that uses the register
|
;; potential call site. This stops any rtx value that uses the register
|
;; from being computed before an earlier call. To do this, we:
|
;; from being computed before an earlier call. To do this, we:
|
;;
|
;;
|
;; - Ensure that the register is live on entry to the function,
|
;; - Ensure that the register is live on entry to the function,
|
;; so that it is never thought to be used uninitalized.
|
;; so that it is never thought to be used uninitalized.
|
;;
|
;;
|
;; - Ensure that the register is live on exit from the function,
|
;; - Ensure that the register is live on exit from the function,
|
;; so that it is live throughout.
|
;; so that it is live throughout.
|
;;
|
;;
|
;; - Make each call (lazily-bound or not) use the current value
|
;; - Make each call (lazily-bound or not) use the current value
|
;; of GOT_VERSION_REGNUM, so that updates of the register are
|
;; of GOT_VERSION_REGNUM, so that updates of the register are
|
;; not moved across call boundaries.
|
;; not moved across call boundaries.
|
;;
|
;;
|
;; - Add "ghost" definitions of the register to the beginning of
|
;; - Add "ghost" definitions of the register to the beginning of
|
;; blocks reached by EH and ABNORMAL_CALL edges, because those
|
;; blocks reached by EH and ABNORMAL_CALL edges, because those
|
;; edges may involve calls that normal paths don't. (E.g. the
|
;; edges may involve calls that normal paths don't. (E.g. the
|
;; unwinding code that handles a non-call exception may change
|
;; unwinding code that handles a non-call exception may change
|
;; lazily-bound GOT entries.) We do this by making the
|
;; lazily-bound GOT entries.) We do this by making the
|
;; exception_receiver and nonlocal_goto_receiver expanders emit
|
;; exception_receiver and nonlocal_goto_receiver expanders emit
|
;; a set_got_version instruction.
|
;; a set_got_version instruction.
|
;;
|
;;
|
;; - After each call (lazily-bound or not), use a "ghost"
|
;; - After each call (lazily-bound or not), use a "ghost"
|
;; update_got_version instruction to change the register's value.
|
;; update_got_version instruction to change the register's value.
|
;; This instruction mimics the _possible_ effect of the dynamic
|
;; This instruction mimics the _possible_ effect of the dynamic
|
;; resolver during the call and it remains live even if the call
|
;; resolver during the call and it remains live even if the call
|
;; itself becomes dead.
|
;; itself becomes dead.
|
;;
|
;;
|
;; - Leave GOT_VERSION_REGNUM out of all register classes.
|
;; - Leave GOT_VERSION_REGNUM out of all register classes.
|
;; The register is therefore not a valid register_operand
|
;; The register is therefore not a valid register_operand
|
;; and cannot be moved to or from other registers.
|
;; and cannot be moved to or from other registers.
|
|
|
(define_insn "load_call"
|
(define_insn "load_call"
|
[(set (match_operand:P 0 "register_operand" "=d")
|
[(set (match_operand:P 0 "register_operand" "=d")
|
(unspec:P [(match_operand:P 1 "register_operand" "d")
|
(unspec:P [(match_operand:P 1 "register_operand" "d")
|
(match_operand:P 2 "immediate_operand" "")
|
(match_operand:P 2 "immediate_operand" "")
|
(reg:SI GOT_VERSION_REGNUM)] UNSPEC_LOAD_CALL))]
|
(reg:SI GOT_VERSION_REGNUM)] UNSPEC_LOAD_CALL))]
|
"TARGET_USE_GOT"
|
"TARGET_USE_GOT"
|
"\t%0,%R2(%1)"
|
"\t%0,%R2(%1)"
|
[(set_attr "got" "load")
|
[(set_attr "got" "load")
|
(set_attr "mode" "")])
|
(set_attr "mode" "")])
|
|
|
(define_insn "set_got_version"
|
(define_insn "set_got_version"
|
[(set (reg:SI GOT_VERSION_REGNUM)
|
[(set (reg:SI GOT_VERSION_REGNUM)
|
(unspec_volatile:SI [(const_int 0)] UNSPEC_SET_GOT_VERSION))]
|
(unspec_volatile:SI [(const_int 0)] UNSPEC_SET_GOT_VERSION))]
|
"TARGET_USE_GOT"
|
"TARGET_USE_GOT"
|
""
|
""
|
[(set_attr "type" "ghost")])
|
[(set_attr "type" "ghost")])
|
|
|
(define_insn "update_got_version"
|
(define_insn "update_got_version"
|
[(set (reg:SI GOT_VERSION_REGNUM)
|
[(set (reg:SI GOT_VERSION_REGNUM)
|
(unspec:SI [(reg:SI GOT_VERSION_REGNUM)] UNSPEC_UPDATE_GOT_VERSION))]
|
(unspec:SI [(reg:SI GOT_VERSION_REGNUM)] UNSPEC_UPDATE_GOT_VERSION))]
|
"TARGET_USE_GOT"
|
"TARGET_USE_GOT"
|
""
|
""
|
[(set_attr "type" "ghost")])
|
[(set_attr "type" "ghost")])
|
|
|
;; Sibling calls. All these patterns use jump instructions.
|
;; Sibling calls. All these patterns use jump instructions.
|
|
|
;; If TARGET_SIBCALLS, call_insn_operand will only accept constant
|
;; If TARGET_SIBCALLS, call_insn_operand will only accept constant
|
;; addresses if a direct jump is acceptable. Since the 'S' constraint
|
;; addresses if a direct jump is acceptable. Since the 'S' constraint
|
;; is defined in terms of call_insn_operand, the same is true of the
|
;; is defined in terms of call_insn_operand, the same is true of the
|
;; constraints.
|
;; constraints.
|
|
|
;; When we use an indirect jump, we need a register that will be
|
;; When we use an indirect jump, we need a register that will be
|
;; preserved by the epilogue. Since TARGET_USE_PIC_FN_ADDR_REG forces
|
;; preserved by the epilogue. Since TARGET_USE_PIC_FN_ADDR_REG forces
|
;; us to use $25 for this purpose -- and $25 is never clobbered by the
|
;; us to use $25 for this purpose -- and $25 is never clobbered by the
|
;; epilogue -- we might as well use it for !TARGET_USE_PIC_FN_ADDR_REG
|
;; epilogue -- we might as well use it for !TARGET_USE_PIC_FN_ADDR_REG
|
;; as well.
|
;; as well.
|
|
|
(define_expand "sibcall"
|
(define_expand "sibcall"
|
[(parallel [(call (match_operand 0 "")
|
[(parallel [(call (match_operand 0 "")
|
(match_operand 1 ""))
|
(match_operand 1 ""))
|
(use (match_operand 2 "")) ;; next_arg_reg
|
(use (match_operand 2 "")) ;; next_arg_reg
|
(use (match_operand 3 ""))])] ;; struct_value_size_rtx
|
(use (match_operand 3 ""))])] ;; struct_value_size_rtx
|
"TARGET_SIBCALLS"
|
"TARGET_SIBCALLS"
|
{
|
{
|
mips_expand_call (MIPS_CALL_SIBCALL, NULL_RTX, XEXP (operands[0], 0),
|
mips_expand_call (MIPS_CALL_SIBCALL, NULL_RTX, XEXP (operands[0], 0),
|
operands[1], operands[2], false);
|
operands[1], operands[2], false);
|
DONE;
|
DONE;
|
})
|
})
|
|
|
(define_insn "sibcall_internal"
|
(define_insn "sibcall_internal"
|
[(call (mem:SI (match_operand 0 "call_insn_operand" "j,S"))
|
[(call (mem:SI (match_operand 0 "call_insn_operand" "j,S"))
|
(match_operand 1 "" ""))]
|
(match_operand 1 "" ""))]
|
"TARGET_SIBCALLS && SIBLING_CALL_P (insn)"
|
"TARGET_SIBCALLS && SIBLING_CALL_P (insn)"
|
{ return MIPS_CALL ("j", operands, 0, 1); }
|
{ return MIPS_CALL ("j", operands, 0, 1); }
|
[(set_attr "type" "call")])
|
[(set_attr "type" "call")])
|
|
|
(define_expand "sibcall_value"
|
(define_expand "sibcall_value"
|
[(parallel [(set (match_operand 0 "")
|
[(parallel [(set (match_operand 0 "")
|
(call (match_operand 1 "")
|
(call (match_operand 1 "")
|
(match_operand 2 "")))
|
(match_operand 2 "")))
|
(use (match_operand 3 ""))])] ;; next_arg_reg
|
(use (match_operand 3 ""))])] ;; next_arg_reg
|
"TARGET_SIBCALLS"
|
"TARGET_SIBCALLS"
|
{
|
{
|
mips_expand_call (MIPS_CALL_SIBCALL, operands[0], XEXP (operands[1], 0),
|
mips_expand_call (MIPS_CALL_SIBCALL, operands[0], XEXP (operands[1], 0),
|
operands[2], operands[3], false);
|
operands[2], operands[3], false);
|
DONE;
|
DONE;
|
})
|
})
|
|
|
(define_insn "sibcall_value_internal"
|
(define_insn "sibcall_value_internal"
|
[(set (match_operand 0 "register_operand" "")
|
[(set (match_operand 0 "register_operand" "")
|
(call (mem:SI (match_operand 1 "call_insn_operand" "j,S"))
|
(call (mem:SI (match_operand 1 "call_insn_operand" "j,S"))
|
(match_operand 2 "" "")))]
|
(match_operand 2 "" "")))]
|
"TARGET_SIBCALLS && SIBLING_CALL_P (insn)"
|
"TARGET_SIBCALLS && SIBLING_CALL_P (insn)"
|
{ return MIPS_CALL ("j", operands, 1, 2); }
|
{ return MIPS_CALL ("j", operands, 1, 2); }
|
[(set_attr "type" "call")])
|
[(set_attr "type" "call")])
|
|
|
(define_insn "sibcall_value_multiple_internal"
|
(define_insn "sibcall_value_multiple_internal"
|
[(set (match_operand 0 "register_operand" "")
|
[(set (match_operand 0 "register_operand" "")
|
(call (mem:SI (match_operand 1 "call_insn_operand" "j,S"))
|
(call (mem:SI (match_operand 1 "call_insn_operand" "j,S"))
|
(match_operand 2 "" "")))
|
(match_operand 2 "" "")))
|
(set (match_operand 3 "register_operand" "")
|
(set (match_operand 3 "register_operand" "")
|
(call (mem:SI (match_dup 1))
|
(call (mem:SI (match_dup 1))
|
(match_dup 2)))]
|
(match_dup 2)))]
|
"TARGET_SIBCALLS && SIBLING_CALL_P (insn)"
|
"TARGET_SIBCALLS && SIBLING_CALL_P (insn)"
|
{ return MIPS_CALL ("j", operands, 1, 2); }
|
{ return MIPS_CALL ("j", operands, 1, 2); }
|
[(set_attr "type" "call")])
|
[(set_attr "type" "call")])
|
|
|
(define_expand "call"
|
(define_expand "call"
|
[(parallel [(call (match_operand 0 "")
|
[(parallel [(call (match_operand 0 "")
|
(match_operand 1 ""))
|
(match_operand 1 ""))
|
(use (match_operand 2 "")) ;; next_arg_reg
|
(use (match_operand 2 "")) ;; next_arg_reg
|
(use (match_operand 3 ""))])] ;; struct_value_size_rtx
|
(use (match_operand 3 ""))])] ;; struct_value_size_rtx
|
""
|
""
|
{
|
{
|
mips_expand_call (MIPS_CALL_NORMAL, NULL_RTX, XEXP (operands[0], 0),
|
mips_expand_call (MIPS_CALL_NORMAL, NULL_RTX, XEXP (operands[0], 0),
|
operands[1], operands[2], false);
|
operands[1], operands[2], false);
|
DONE;
|
DONE;
|
})
|
})
|
|
|
;; This instruction directly corresponds to an assembly-language "jal".
|
;; This instruction directly corresponds to an assembly-language "jal".
|
;; There are four cases:
|
;; There are four cases:
|
;;
|
;;
|
;; - -mno-abicalls:
|
;; - -mno-abicalls:
|
;; Both symbolic and register destinations are OK. The pattern
|
;; Both symbolic and register destinations are OK. The pattern
|
;; always expands to a single mips instruction.
|
;; always expands to a single mips instruction.
|
;;
|
;;
|
;; - -mabicalls/-mno-explicit-relocs:
|
;; - -mabicalls/-mno-explicit-relocs:
|
;; Again, both symbolic and register destinations are OK.
|
;; Again, both symbolic and register destinations are OK.
|
;; The call is treated as a multi-instruction black box.
|
;; The call is treated as a multi-instruction black box.
|
;;
|
;;
|
;; - -mabicalls/-mexplicit-relocs with n32 or n64:
|
;; - -mabicalls/-mexplicit-relocs with n32 or n64:
|
;; Only "jal $25" is allowed. This expands to a single "jalr $25"
|
;; Only "jal $25" is allowed. This expands to a single "jalr $25"
|
;; instruction.
|
;; instruction.
|
;;
|
;;
|
;; - -mabicalls/-mexplicit-relocs with o32 or o64:
|
;; - -mabicalls/-mexplicit-relocs with o32 or o64:
|
;; Only "jal $25" is allowed. The call is actually two instructions:
|
;; Only "jal $25" is allowed. The call is actually two instructions:
|
;; "jalr $25" followed by an insn to reload $gp.
|
;; "jalr $25" followed by an insn to reload $gp.
|
;;
|
;;
|
;; In the last case, we can generate the individual instructions with
|
;; In the last case, we can generate the individual instructions with
|
;; a define_split. There are several things to be wary of:
|
;; a define_split. There are several things to be wary of:
|
;;
|
;;
|
;; - We can't expose the load of $gp before reload. If we did,
|
;; - We can't expose the load of $gp before reload. If we did,
|
;; it might get removed as dead, but reload can introduce new
|
;; it might get removed as dead, but reload can introduce new
|
;; uses of $gp by rematerializing constants.
|
;; uses of $gp by rematerializing constants.
|
;;
|
;;
|
;; - We shouldn't restore $gp after calls that never return.
|
;; - We shouldn't restore $gp after calls that never return.
|
;; It isn't valid to insert instructions between a noreturn
|
;; It isn't valid to insert instructions between a noreturn
|
;; call and the following barrier.
|
;; call and the following barrier.
|
;;
|
;;
|
;; - The splitter deliberately changes the liveness of $gp. The unsplit
|
;; - The splitter deliberately changes the liveness of $gp. The unsplit
|
;; instruction preserves $gp and so have no effect on its liveness.
|
;; instruction preserves $gp and so have no effect on its liveness.
|
;; But once we generate the separate insns, it becomes obvious that
|
;; But once we generate the separate insns, it becomes obvious that
|
;; $gp is not live on entry to the call.
|
;; $gp is not live on entry to the call.
|
;;
|
;;
|
;; ??? The operands[2] = insn check is a hack to make the original insn
|
;; ??? The operands[2] = insn check is a hack to make the original insn
|
;; available to the splitter.
|
;; available to the splitter.
|
(define_insn_and_split "call_internal"
|
(define_insn_and_split "call_internal"
|
[(call (mem:SI (match_operand 0 "call_insn_operand" "c,S"))
|
[(call (mem:SI (match_operand 0 "call_insn_operand" "c,S"))
|
(match_operand 1 "" ""))
|
(match_operand 1 "" ""))
|
(clobber (reg:SI RETURN_ADDR_REGNUM))]
|
(clobber (reg:SI RETURN_ADDR_REGNUM))]
|
""
|
""
|
{ return TARGET_SPLIT_CALLS ? "#" : MIPS_CALL ("jal", operands, 0, 1); }
|
{ return TARGET_SPLIT_CALLS ? "#" : MIPS_CALL ("jal", operands, 0, 1); }
|
"reload_completed && TARGET_SPLIT_CALLS && (operands[2] = insn)"
|
"reload_completed && TARGET_SPLIT_CALLS && (operands[2] = insn)"
|
[(const_int 0)]
|
[(const_int 0)]
|
{
|
{
|
mips_split_call (operands[2], gen_call_split (operands[0], operands[1]));
|
mips_split_call (operands[2], gen_call_split (operands[0], operands[1]));
|
DONE;
|
DONE;
|
}
|
}
|
[(set_attr "jal" "indirect,direct")])
|
[(set_attr "jal" "indirect,direct")])
|
|
|
(define_insn "call_split"
|
(define_insn "call_split"
|
[(call (mem:SI (match_operand 0 "call_insn_operand" "cS"))
|
[(call (mem:SI (match_operand 0 "call_insn_operand" "cS"))
|
(match_operand 1 "" ""))
|
(match_operand 1 "" ""))
|
(clobber (reg:SI RETURN_ADDR_REGNUM))
|
(clobber (reg:SI RETURN_ADDR_REGNUM))
|
(clobber (reg:SI 28))]
|
(clobber (reg:SI 28))]
|
"TARGET_SPLIT_CALLS"
|
"TARGET_SPLIT_CALLS"
|
{ return MIPS_CALL ("jal", operands, 0, 1); }
|
{ return MIPS_CALL ("jal", operands, 0, 1); }
|
[(set_attr "type" "call")])
|
[(set_attr "type" "call")])
|
|
|
;; A pattern for calls that must be made directly. It is used for
|
;; A pattern for calls that must be made directly. It is used for
|
;; MIPS16 calls that the linker may need to redirect to a hard-float
|
;; MIPS16 calls that the linker may need to redirect to a hard-float
|
;; stub; the linker relies on the call relocation type to detect when
|
;; stub; the linker relies on the call relocation type to detect when
|
;; such redirection is needed.
|
;; such redirection is needed.
|
(define_insn_and_split "call_internal_direct"
|
(define_insn_and_split "call_internal_direct"
|
[(call (mem:SI (match_operand 0 "const_call_insn_operand"))
|
[(call (mem:SI (match_operand 0 "const_call_insn_operand"))
|
(match_operand 1))
|
(match_operand 1))
|
(const_int 1)
|
(const_int 1)
|
(clobber (reg:SI RETURN_ADDR_REGNUM))]
|
(clobber (reg:SI RETURN_ADDR_REGNUM))]
|
""
|
""
|
{ return TARGET_SPLIT_CALLS ? "#" : MIPS_CALL ("jal", operands, 0, -1); }
|
{ return TARGET_SPLIT_CALLS ? "#" : MIPS_CALL ("jal", operands, 0, -1); }
|
"reload_completed && TARGET_SPLIT_CALLS && (operands[2] = insn)"
|
"reload_completed && TARGET_SPLIT_CALLS && (operands[2] = insn)"
|
[(const_int 0)]
|
[(const_int 0)]
|
{
|
{
|
mips_split_call (operands[2],
|
mips_split_call (operands[2],
|
gen_call_direct_split (operands[0], operands[1]));
|
gen_call_direct_split (operands[0], operands[1]));
|
DONE;
|
DONE;
|
}
|
}
|
[(set_attr "type" "call")])
|
[(set_attr "type" "call")])
|
|
|
(define_insn "call_direct_split"
|
(define_insn "call_direct_split"
|
[(call (mem:SI (match_operand 0 "const_call_insn_operand"))
|
[(call (mem:SI (match_operand 0 "const_call_insn_operand"))
|
(match_operand 1))
|
(match_operand 1))
|
(const_int 1)
|
(const_int 1)
|
(clobber (reg:SI RETURN_ADDR_REGNUM))
|
(clobber (reg:SI RETURN_ADDR_REGNUM))
|
(clobber (reg:SI 28))]
|
(clobber (reg:SI 28))]
|
"TARGET_SPLIT_CALLS"
|
"TARGET_SPLIT_CALLS"
|
{ return MIPS_CALL ("jal", operands, 0, -1); }
|
{ return MIPS_CALL ("jal", operands, 0, -1); }
|
[(set_attr "type" "call")])
|
[(set_attr "type" "call")])
|
|
|
(define_expand "call_value"
|
(define_expand "call_value"
|
[(parallel [(set (match_operand 0 "")
|
[(parallel [(set (match_operand 0 "")
|
(call (match_operand 1 "")
|
(call (match_operand 1 "")
|
(match_operand 2 "")))
|
(match_operand 2 "")))
|
(use (match_operand 3 ""))])] ;; next_arg_reg
|
(use (match_operand 3 ""))])] ;; next_arg_reg
|
""
|
""
|
{
|
{
|
mips_expand_call (MIPS_CALL_NORMAL, operands[0], XEXP (operands[1], 0),
|
mips_expand_call (MIPS_CALL_NORMAL, operands[0], XEXP (operands[1], 0),
|
operands[2], operands[3], false);
|
operands[2], operands[3], false);
|
DONE;
|
DONE;
|
})
|
})
|
|
|
;; See comment for call_internal.
|
;; See comment for call_internal.
|
(define_insn_and_split "call_value_internal"
|
(define_insn_and_split "call_value_internal"
|
[(set (match_operand 0 "register_operand" "")
|
[(set (match_operand 0 "register_operand" "")
|
(call (mem:SI (match_operand 1 "call_insn_operand" "c,S"))
|
(call (mem:SI (match_operand 1 "call_insn_operand" "c,S"))
|
(match_operand 2 "" "")))
|
(match_operand 2 "" "")))
|
(clobber (reg:SI RETURN_ADDR_REGNUM))]
|
(clobber (reg:SI RETURN_ADDR_REGNUM))]
|
""
|
""
|
{ return TARGET_SPLIT_CALLS ? "#" : MIPS_CALL ("jal", operands, 1, 2); }
|
{ return TARGET_SPLIT_CALLS ? "#" : MIPS_CALL ("jal", operands, 1, 2); }
|
"reload_completed && TARGET_SPLIT_CALLS && (operands[3] = insn)"
|
"reload_completed && TARGET_SPLIT_CALLS && (operands[3] = insn)"
|
[(const_int 0)]
|
[(const_int 0)]
|
{
|
{
|
mips_split_call (operands[3],
|
mips_split_call (operands[3],
|
gen_call_value_split (operands[0], operands[1],
|
gen_call_value_split (operands[0], operands[1],
|
operands[2]));
|
operands[2]));
|
DONE;
|
DONE;
|
}
|
}
|
[(set_attr "jal" "indirect,direct")])
|
[(set_attr "jal" "indirect,direct")])
|
|
|
(define_insn "call_value_split"
|
(define_insn "call_value_split"
|
[(set (match_operand 0 "register_operand" "")
|
[(set (match_operand 0 "register_operand" "")
|
(call (mem:SI (match_operand 1 "call_insn_operand" "cS"))
|
(call (mem:SI (match_operand 1 "call_insn_operand" "cS"))
|
(match_operand 2 "" "")))
|
(match_operand 2 "" "")))
|
(clobber (reg:SI RETURN_ADDR_REGNUM))
|
(clobber (reg:SI RETURN_ADDR_REGNUM))
|
(clobber (reg:SI 28))]
|
(clobber (reg:SI 28))]
|
"TARGET_SPLIT_CALLS"
|
"TARGET_SPLIT_CALLS"
|
{ return MIPS_CALL ("jal", operands, 1, 2); }
|
{ return MIPS_CALL ("jal", operands, 1, 2); }
|
[(set_attr "type" "call")])
|
[(set_attr "type" "call")])
|
|
|
;; See call_internal_direct.
|
;; See call_internal_direct.
|
(define_insn_and_split "call_value_internal_direct"
|
(define_insn_and_split "call_value_internal_direct"
|
[(set (match_operand 0 "register_operand")
|
[(set (match_operand 0 "register_operand")
|
(call (mem:SI (match_operand 1 "const_call_insn_operand"))
|
(call (mem:SI (match_operand 1 "const_call_insn_operand"))
|
(match_operand 2)))
|
(match_operand 2)))
|
(const_int 1)
|
(const_int 1)
|
(clobber (reg:SI RETURN_ADDR_REGNUM))]
|
(clobber (reg:SI RETURN_ADDR_REGNUM))]
|
""
|
""
|
{ return TARGET_SPLIT_CALLS ? "#" : MIPS_CALL ("jal", operands, 1, -1); }
|
{ return TARGET_SPLIT_CALLS ? "#" : MIPS_CALL ("jal", operands, 1, -1); }
|
"reload_completed && TARGET_SPLIT_CALLS && (operands[3] = insn)"
|
"reload_completed && TARGET_SPLIT_CALLS && (operands[3] = insn)"
|
[(const_int 0)]
|
[(const_int 0)]
|
{
|
{
|
mips_split_call (operands[3],
|
mips_split_call (operands[3],
|
gen_call_value_direct_split (operands[0], operands[1],
|
gen_call_value_direct_split (operands[0], operands[1],
|
operands[2]));
|
operands[2]));
|
DONE;
|
DONE;
|
}
|
}
|
[(set_attr "type" "call")])
|
[(set_attr "type" "call")])
|
|
|
(define_insn "call_value_direct_split"
|
(define_insn "call_value_direct_split"
|
[(set (match_operand 0 "register_operand")
|
[(set (match_operand 0 "register_operand")
|
(call (mem:SI (match_operand 1 "const_call_insn_operand"))
|
(call (mem:SI (match_operand 1 "const_call_insn_operand"))
|
(match_operand 2)))
|
(match_operand 2)))
|
(const_int 1)
|
(const_int 1)
|
(clobber (reg:SI RETURN_ADDR_REGNUM))
|
(clobber (reg:SI RETURN_ADDR_REGNUM))
|
(clobber (reg:SI 28))]
|
(clobber (reg:SI 28))]
|
"TARGET_SPLIT_CALLS"
|
"TARGET_SPLIT_CALLS"
|
{ return MIPS_CALL ("jal", operands, 1, -1); }
|
{ return MIPS_CALL ("jal", operands, 1, -1); }
|
[(set_attr "type" "call")])
|
[(set_attr "type" "call")])
|
|
|
;; See comment for call_internal.
|
;; See comment for call_internal.
|
(define_insn_and_split "call_value_multiple_internal"
|
(define_insn_and_split "call_value_multiple_internal"
|
[(set (match_operand 0 "register_operand" "")
|
[(set (match_operand 0 "register_operand" "")
|
(call (mem:SI (match_operand 1 "call_insn_operand" "c,S"))
|
(call (mem:SI (match_operand 1 "call_insn_operand" "c,S"))
|
(match_operand 2 "" "")))
|
(match_operand 2 "" "")))
|
(set (match_operand 3 "register_operand" "")
|
(set (match_operand 3 "register_operand" "")
|
(call (mem:SI (match_dup 1))
|
(call (mem:SI (match_dup 1))
|
(match_dup 2)))
|
(match_dup 2)))
|
(clobber (reg:SI RETURN_ADDR_REGNUM))]
|
(clobber (reg:SI RETURN_ADDR_REGNUM))]
|
""
|
""
|
{ return TARGET_SPLIT_CALLS ? "#" : MIPS_CALL ("jal", operands, 1, 2); }
|
{ return TARGET_SPLIT_CALLS ? "#" : MIPS_CALL ("jal", operands, 1, 2); }
|
"reload_completed && TARGET_SPLIT_CALLS && (operands[4] = insn)"
|
"reload_completed && TARGET_SPLIT_CALLS && (operands[4] = insn)"
|
[(const_int 0)]
|
[(const_int 0)]
|
{
|
{
|
mips_split_call (operands[4],
|
mips_split_call (operands[4],
|
gen_call_value_multiple_split (operands[0], operands[1],
|
gen_call_value_multiple_split (operands[0], operands[1],
|
operands[2], operands[3]));
|
operands[2], operands[3]));
|
DONE;
|
DONE;
|
}
|
}
|
[(set_attr "jal" "indirect,direct")])
|
[(set_attr "jal" "indirect,direct")])
|
|
|
(define_insn "call_value_multiple_split"
|
(define_insn "call_value_multiple_split"
|
[(set (match_operand 0 "register_operand" "")
|
[(set (match_operand 0 "register_operand" "")
|
(call (mem:SI (match_operand 1 "call_insn_operand" "cS"))
|
(call (mem:SI (match_operand 1 "call_insn_operand" "cS"))
|
(match_operand 2 "" "")))
|
(match_operand 2 "" "")))
|
(set (match_operand 3 "register_operand" "")
|
(set (match_operand 3 "register_operand" "")
|
(call (mem:SI (match_dup 1))
|
(call (mem:SI (match_dup 1))
|
(match_dup 2)))
|
(match_dup 2)))
|
(clobber (reg:SI RETURN_ADDR_REGNUM))
|
(clobber (reg:SI RETURN_ADDR_REGNUM))
|
(clobber (reg:SI 28))]
|
(clobber (reg:SI 28))]
|
"TARGET_SPLIT_CALLS"
|
"TARGET_SPLIT_CALLS"
|
{ return MIPS_CALL ("jal", operands, 1, 2); }
|
{ return MIPS_CALL ("jal", operands, 1, 2); }
|
[(set_attr "type" "call")])
|
[(set_attr "type" "call")])
|
|
|
;; Call subroutine returning any type.
|
;; Call subroutine returning any type.
|
|
|
(define_expand "untyped_call"
|
(define_expand "untyped_call"
|
[(parallel [(call (match_operand 0 "")
|
[(parallel [(call (match_operand 0 "")
|
(const_int 0))
|
(const_int 0))
|
(match_operand 1 "")
|
(match_operand 1 "")
|
(match_operand 2 "")])]
|
(match_operand 2 "")])]
|
""
|
""
|
{
|
{
|
int i;
|
int i;
|
|
|
emit_call_insn (GEN_CALL (operands[0], const0_rtx, NULL, const0_rtx));
|
emit_call_insn (GEN_CALL (operands[0], const0_rtx, NULL, const0_rtx));
|
|
|
for (i = 0; i < XVECLEN (operands[2], 0); i++)
|
for (i = 0; i < XVECLEN (operands[2], 0); i++)
|
{
|
{
|
rtx set = XVECEXP (operands[2], 0, i);
|
rtx set = XVECEXP (operands[2], 0, i);
|
mips_emit_move (SET_DEST (set), SET_SRC (set));
|
mips_emit_move (SET_DEST (set), SET_SRC (set));
|
}
|
}
|
|
|
emit_insn (gen_blockage ());
|
emit_insn (gen_blockage ());
|
DONE;
|
DONE;
|
})
|
})
|
|
|
;;
|
;;
|
;; ....................
|
;; ....................
|
;;
|
;;
|
;; MISC.
|
;; MISC.
|
;;
|
;;
|
;; ....................
|
;; ....................
|
;;
|
;;
|
|
|
|
|
(define_insn "prefetch"
|
(define_insn "prefetch"
|
[(prefetch (match_operand:QI 0 "address_operand" "p")
|
[(prefetch (match_operand:QI 0 "address_operand" "p")
|
(match_operand 1 "const_int_operand" "n")
|
(match_operand 1 "const_int_operand" "n")
|
(match_operand 2 "const_int_operand" "n"))]
|
(match_operand 2 "const_int_operand" "n"))]
|
"ISA_HAS_PREFETCH && TARGET_EXPLICIT_RELOCS"
|
"ISA_HAS_PREFETCH && TARGET_EXPLICIT_RELOCS"
|
{
|
{
|
if (TARGET_LOONGSON_2EF)
|
if (TARGET_LOONGSON_2EF)
|
/* Loongson 2[ef] use load to $0 to perform prefetching. */
|
/* Loongson 2[ef] use load to $0 to perform prefetching. */
|
return "ld\t$0,%a0";
|
return "ld\t$0,%a0";
|
operands[1] = mips_prefetch_cookie (operands[1], operands[2]);
|
operands[1] = mips_prefetch_cookie (operands[1], operands[2]);
|
return "pref\t%1,%a0";
|
return "pref\t%1,%a0";
|
}
|
}
|
[(set_attr "type" "prefetch")])
|
[(set_attr "type" "prefetch")])
|
|
|
(define_insn "*prefetch_indexed_"
|
(define_insn "*prefetch_indexed_"
|
[(prefetch (plus:P (match_operand:P 0 "register_operand" "d")
|
[(prefetch (plus:P (match_operand:P 0 "register_operand" "d")
|
(match_operand:P 1 "register_operand" "d"))
|
(match_operand:P 1 "register_operand" "d"))
|
(match_operand 2 "const_int_operand" "n")
|
(match_operand 2 "const_int_operand" "n")
|
(match_operand 3 "const_int_operand" "n"))]
|
(match_operand 3 "const_int_operand" "n"))]
|
"ISA_HAS_PREFETCHX && TARGET_HARD_FLOAT && TARGET_DOUBLE_FLOAT"
|
"ISA_HAS_PREFETCHX && TARGET_HARD_FLOAT && TARGET_DOUBLE_FLOAT"
|
{
|
{
|
operands[2] = mips_prefetch_cookie (operands[2], operands[3]);
|
operands[2] = mips_prefetch_cookie (operands[2], operands[3]);
|
return "prefx\t%2,%1(%0)";
|
return "prefx\t%2,%1(%0)";
|
}
|
}
|
[(set_attr "type" "prefetchx")])
|
[(set_attr "type" "prefetchx")])
|
|
|
(define_insn "nop"
|
(define_insn "nop"
|
[(const_int 0)]
|
[(const_int 0)]
|
""
|
""
|
"%(nop%)"
|
"%(nop%)"
|
[(set_attr "type" "nop")
|
[(set_attr "type" "nop")
|
(set_attr "mode" "none")])
|
(set_attr "mode" "none")])
|
|
|
;; Like nop, but commented out when outside a .set noreorder block.
|
;; Like nop, but commented out when outside a .set noreorder block.
|
(define_insn "hazard_nop"
|
(define_insn "hazard_nop"
|
[(const_int 1)]
|
[(const_int 1)]
|
""
|
""
|
{
|
{
|
if (mips_noreorder.nesting_level > 0)
|
if (mips_noreorder.nesting_level > 0)
|
return "nop";
|
return "nop";
|
else
|
else
|
return "#nop";
|
return "#nop";
|
}
|
}
|
[(set_attr "type" "nop")])
|
[(set_attr "type" "nop")])
|
|
|
;; MIPS4 Conditional move instructions.
|
;; MIPS4 Conditional move instructions.
|
|
|
(define_insn "*mov_on_"
|
(define_insn "*mov_on_"
|
[(set (match_operand:GPR 0 "register_operand" "=d,d")
|
[(set (match_operand:GPR 0 "register_operand" "=d,d")
|
(if_then_else:GPR
|
(if_then_else:GPR
|
(match_operator:MOVECC 4 "equality_operator"
|
(match_operator:MOVECC 4 "equality_operator"
|
[(match_operand:MOVECC 1 "register_operand" ",")
|
[(match_operand:MOVECC 1 "register_operand" ",")
|
(const_int 0)])
|
(const_int 0)])
|
(match_operand:GPR 2 "reg_or_0_operand" "dJ,0")
|
(match_operand:GPR 2 "reg_or_0_operand" "dJ,0")
|
(match_operand:GPR 3 "reg_or_0_operand" "0,dJ")))]
|
(match_operand:GPR 3 "reg_or_0_operand" "0,dJ")))]
|
"ISA_HAS_CONDMOVE"
|
"ISA_HAS_CONDMOVE"
|
"@
|
"@
|
mov%T4\t%0,%z2,%1
|
mov%T4\t%0,%z2,%1
|
mov%t4\t%0,%z3,%1"
|
mov%t4\t%0,%z3,%1"
|
[(set_attr "type" "condmove")
|
[(set_attr "type" "condmove")
|
(set_attr "mode" "")])
|
(set_attr "mode" "")])
|
|
|
(define_insn "*mov_on_"
|
(define_insn "*mov_on_"
|
[(set (match_operand:SCALARF 0 "register_operand" "=f,f")
|
[(set (match_operand:SCALARF 0 "register_operand" "=f,f")
|
(if_then_else:SCALARF
|
(if_then_else:SCALARF
|
(match_operator:MOVECC 4 "equality_operator"
|
(match_operator:MOVECC 4 "equality_operator"
|
[(match_operand:MOVECC 1 "register_operand" ",")
|
[(match_operand:MOVECC 1 "register_operand" ",")
|
(const_int 0)])
|
(const_int 0)])
|
(match_operand:SCALARF 2 "register_operand" "f,0")
|
(match_operand:SCALARF 2 "register_operand" "f,0")
|
(match_operand:SCALARF 3 "register_operand" "0,f")))]
|
(match_operand:SCALARF 3 "register_operand" "0,f")))]
|
"ISA_HAS_FP_CONDMOVE"
|
"ISA_HAS_FP_CONDMOVE"
|
"@
|
"@
|
mov%T4.\t%0,%2,%1
|
mov%T4.\t%0,%2,%1
|
mov%t4.\t%0,%3,%1"
|
mov%t4.\t%0,%3,%1"
|
[(set_attr "type" "condmove")
|
[(set_attr "type" "condmove")
|
(set_attr "mode" "")])
|
(set_attr "mode" "")])
|
|
|
;; These are the main define_expand's used to make conditional moves.
|
;; These are the main define_expand's used to make conditional moves.
|
|
|
(define_expand "movcc"
|
(define_expand "movcc"
|
[(set (match_dup 4) (match_operand 1 "comparison_operator"))
|
[(set (match_dup 4) (match_operand 1 "comparison_operator"))
|
(set (match_operand:GPR 0 "register_operand")
|
(set (match_operand:GPR 0 "register_operand")
|
(if_then_else:GPR (match_dup 5)
|
(if_then_else:GPR (match_dup 5)
|
(match_operand:GPR 2 "reg_or_0_operand")
|
(match_operand:GPR 2 "reg_or_0_operand")
|
(match_operand:GPR 3 "reg_or_0_operand")))]
|
(match_operand:GPR 3 "reg_or_0_operand")))]
|
"ISA_HAS_CONDMOVE"
|
"ISA_HAS_CONDMOVE"
|
{
|
{
|
mips_expand_conditional_move (operands);
|
mips_expand_conditional_move (operands);
|
DONE;
|
DONE;
|
})
|
})
|
|
|
(define_expand "movcc"
|
(define_expand "movcc"
|
[(set (match_dup 4) (match_operand 1 "comparison_operator"))
|
[(set (match_dup 4) (match_operand 1 "comparison_operator"))
|
(set (match_operand:SCALARF 0 "register_operand")
|
(set (match_operand:SCALARF 0 "register_operand")
|
(if_then_else:SCALARF (match_dup 5)
|
(if_then_else:SCALARF (match_dup 5)
|
(match_operand:SCALARF 2 "register_operand")
|
(match_operand:SCALARF 2 "register_operand")
|
(match_operand:SCALARF 3 "register_operand")))]
|
(match_operand:SCALARF 3 "register_operand")))]
|
"ISA_HAS_FP_CONDMOVE"
|
"ISA_HAS_FP_CONDMOVE"
|
{
|
{
|
mips_expand_conditional_move (operands);
|
mips_expand_conditional_move (operands);
|
DONE;
|
DONE;
|
})
|
})
|
|
|
;;
|
;;
|
;; ....................
|
;; ....................
|
;;
|
;;
|
;; mips16 inline constant tables
|
;; mips16 inline constant tables
|
;;
|
;;
|
;; ....................
|
;; ....................
|
;;
|
;;
|
|
|
(define_insn "consttable_int"
|
(define_insn "consttable_int"
|
[(unspec_volatile [(match_operand 0 "consttable_operand" "")
|
[(unspec_volatile [(match_operand 0 "consttable_operand" "")
|
(match_operand 1 "const_int_operand" "")]
|
(match_operand 1 "const_int_operand" "")]
|
UNSPEC_CONSTTABLE_INT)]
|
UNSPEC_CONSTTABLE_INT)]
|
"TARGET_MIPS16"
|
"TARGET_MIPS16"
|
{
|
{
|
assemble_integer (operands[0], INTVAL (operands[1]),
|
assemble_integer (operands[0], INTVAL (operands[1]),
|
BITS_PER_UNIT * INTVAL (operands[1]), 1);
|
BITS_PER_UNIT * INTVAL (operands[1]), 1);
|
return "";
|
return "";
|
}
|
}
|
[(set (attr "length") (symbol_ref "INTVAL (operands[1])"))])
|
[(set (attr "length") (symbol_ref "INTVAL (operands[1])"))])
|
|
|
(define_insn "consttable_float"
|
(define_insn "consttable_float"
|
[(unspec_volatile [(match_operand 0 "consttable_operand" "")]
|
[(unspec_volatile [(match_operand 0 "consttable_operand" "")]
|
UNSPEC_CONSTTABLE_FLOAT)]
|
UNSPEC_CONSTTABLE_FLOAT)]
|
"TARGET_MIPS16"
|
"TARGET_MIPS16"
|
{
|
{
|
REAL_VALUE_TYPE d;
|
REAL_VALUE_TYPE d;
|
|
|
gcc_assert (GET_CODE (operands[0]) == CONST_DOUBLE);
|
gcc_assert (GET_CODE (operands[0]) == CONST_DOUBLE);
|
REAL_VALUE_FROM_CONST_DOUBLE (d, operands[0]);
|
REAL_VALUE_FROM_CONST_DOUBLE (d, operands[0]);
|
assemble_real (d, GET_MODE (operands[0]),
|
assemble_real (d, GET_MODE (operands[0]),
|
GET_MODE_BITSIZE (GET_MODE (operands[0])));
|
GET_MODE_BITSIZE (GET_MODE (operands[0])));
|
return "";
|
return "";
|
}
|
}
|
[(set (attr "length")
|
[(set (attr "length")
|
(symbol_ref "GET_MODE_SIZE (GET_MODE (operands[0]))"))])
|
(symbol_ref "GET_MODE_SIZE (GET_MODE (operands[0]))"))])
|
|
|
(define_insn "align"
|
(define_insn "align"
|
[(unspec_volatile [(match_operand 0 "const_int_operand" "")] UNSPEC_ALIGN)]
|
[(unspec_volatile [(match_operand 0 "const_int_operand" "")] UNSPEC_ALIGN)]
|
""
|
""
|
".align\t%0"
|
".align\t%0"
|
[(set (attr "length") (symbol_ref "(1 << INTVAL (operands[0])) - 1"))])
|
[(set (attr "length") (symbol_ref "(1 << INTVAL (operands[0])) - 1"))])
|
|
|
(define_split
|
(define_split
|
[(match_operand 0 "small_data_pattern")]
|
[(match_operand 0 "small_data_pattern")]
|
"reload_completed"
|
"reload_completed"
|
[(match_dup 0)]
|
[(match_dup 0)]
|
{ operands[0] = mips_rewrite_small_data (operands[0]); })
|
{ operands[0] = mips_rewrite_small_data (operands[0]); })
|
|
|
;;
|
;;
|
;; ....................
|
;; ....................
|
;;
|
;;
|
;; MIPS16e Save/Restore
|
;; MIPS16e Save/Restore
|
;;
|
;;
|
;; ....................
|
;; ....................
|
;;
|
;;
|
|
|
(define_insn "*mips16e_save_restore"
|
(define_insn "*mips16e_save_restore"
|
[(match_parallel 0 ""
|
[(match_parallel 0 ""
|
[(set (match_operand:SI 1 "register_operand")
|
[(set (match_operand:SI 1 "register_operand")
|
(plus:SI (match_dup 1)
|
(plus:SI (match_dup 1)
|
(match_operand:SI 2 "const_int_operand")))])]
|
(match_operand:SI 2 "const_int_operand")))])]
|
"operands[1] == stack_pointer_rtx
|
"operands[1] == stack_pointer_rtx
|
&& mips16e_save_restore_pattern_p (operands[0], INTVAL (operands[2]), NULL)"
|
&& mips16e_save_restore_pattern_p (operands[0], INTVAL (operands[2]), NULL)"
|
{ return mips16e_output_save_restore (operands[0], INTVAL (operands[2])); }
|
{ return mips16e_output_save_restore (operands[0], INTVAL (operands[2])); }
|
[(set_attr "type" "arith")
|
[(set_attr "type" "arith")
|
(set_attr "extended_mips16" "yes")])
|
(set_attr "extended_mips16" "yes")])
|
|
|
;; Thread-Local Storage
|
;; Thread-Local Storage
|
|
|
;; The TLS base pointer is accessed via "rdhwr $3, $29". No current
|
;; The TLS base pointer is accessed via "rdhwr $3, $29". No current
|
;; MIPS architecture defines this register, and no current
|
;; MIPS architecture defines this register, and no current
|
;; implementation provides it; instead, any OS which supports TLS is
|
;; implementation provides it; instead, any OS which supports TLS is
|
;; expected to trap and emulate this instruction. rdhwr is part of the
|
;; expected to trap and emulate this instruction. rdhwr is part of the
|
;; MIPS 32r2 specification, but we use it on any architecture because
|
;; MIPS 32r2 specification, but we use it on any architecture because
|
;; we expect it to be emulated. Use .set to force the assembler to
|
;; we expect it to be emulated. Use .set to force the assembler to
|
;; accept it.
|
;; accept it.
|
;;
|
;;
|
;; We do not use a constraint to force the destination to be $3
|
;; We do not use a constraint to force the destination to be $3
|
;; because $3 can appear explicitly as a function return value.
|
;; because $3 can appear explicitly as a function return value.
|
;; If we leave the use of $3 implicit in the constraints until
|
;; If we leave the use of $3 implicit in the constraints until
|
;; reload, we may end up making a $3 return value live across
|
;; reload, we may end up making a $3 return value live across
|
;; the instruction, leading to a spill failure when reloading it.
|
;; the instruction, leading to a spill failure when reloading it.
|
(define_insn_and_split "tls_get_tp_"
|
(define_insn_and_split "tls_get_tp_"
|
[(set (match_operand:P 0 "register_operand" "=d")
|
[(set (match_operand:P 0 "register_operand" "=d")
|
(unspec:P [(const_int 0)] UNSPEC_TLS_GET_TP))
|
(unspec:P [(const_int 0)] UNSPEC_TLS_GET_TP))
|
(clobber (reg:P TLS_GET_TP_REGNUM))]
|
(clobber (reg:P TLS_GET_TP_REGNUM))]
|
"HAVE_AS_TLS && !TARGET_MIPS16"
|
"HAVE_AS_TLS && !TARGET_MIPS16"
|
"#"
|
"#"
|
"&& reload_completed"
|
"&& reload_completed"
|
[(set (reg:P TLS_GET_TP_REGNUM)
|
[(set (reg:P TLS_GET_TP_REGNUM)
|
(unspec:P [(const_int 0)] UNSPEC_TLS_GET_TP))
|
(unspec:P [(const_int 0)] UNSPEC_TLS_GET_TP))
|
(set (match_dup 0) (reg:P TLS_GET_TP_REGNUM))]
|
(set (match_dup 0) (reg:P TLS_GET_TP_REGNUM))]
|
""
|
""
|
[(set_attr "type" "unknown")
|
[(set_attr "type" "unknown")
|
; Since rdhwr always generates a trap for now, putting it in a delay
|
; Since rdhwr always generates a trap for now, putting it in a delay
|
; slot would make the kernel's emulation of it much slower.
|
; slot would make the kernel's emulation of it much slower.
|
(set_attr "can_delay" "no")
|
(set_attr "can_delay" "no")
|
(set_attr "mode" "")
|
(set_attr "mode" "")
|
(set_attr "length" "8")])
|
(set_attr "length" "8")])
|
|
|
(define_insn "*tls_get_tp__split"
|
(define_insn "*tls_get_tp__split"
|
[(set (reg:P TLS_GET_TP_REGNUM)
|
[(set (reg:P TLS_GET_TP_REGNUM)
|
(unspec:P [(const_int 0)] UNSPEC_TLS_GET_TP))]
|
(unspec:P [(const_int 0)] UNSPEC_TLS_GET_TP))]
|
"HAVE_AS_TLS && !TARGET_MIPS16"
|
"HAVE_AS_TLS && !TARGET_MIPS16"
|
".set\tpush\;.set\tmips32r2\t\;rdhwr\t$3,$29\;.set\tpop"
|
".set\tpush\;.set\tmips32r2\t\;rdhwr\t$3,$29\;.set\tpop"
|
[(set_attr "type" "unknown")
|
[(set_attr "type" "unknown")
|
; See tls_get_tp_
|
; See tls_get_tp_
|
(set_attr "can_delay" "no")
|
(set_attr "can_delay" "no")
|
(set_attr "mode" "")])
|
(set_attr "mode" "")])
|
|
|
;; Synchronization instructions.
|
;; Synchronization instructions.
|
|
|
(include "sync.md")
|
(include "sync.md")
|
|
|
; The MIPS Paired-Single Floating Point and MIPS-3D Instructions.
|
; The MIPS Paired-Single Floating Point and MIPS-3D Instructions.
|
|
|
(include "mips-ps-3d.md")
|
(include "mips-ps-3d.md")
|
|
|
; The MIPS DSP Instructions.
|
; The MIPS DSP Instructions.
|
|
|
(include "mips-dsp.md")
|
(include "mips-dsp.md")
|
|
|
; The MIPS DSP REV 2 Instructions.
|
; The MIPS DSP REV 2 Instructions.
|
|
|
(include "mips-dspr2.md")
|
(include "mips-dspr2.md")
|
|
|
; MIPS fixed-point instructions.
|
; MIPS fixed-point instructions.
|
(include "mips-fixed.md")
|
(include "mips-fixed.md")
|
|
|
; ST-Microelectronics Loongson-2E/2F-specific patterns.
|
; ST-Microelectronics Loongson-2E/2F-specific patterns.
|
(include "loongson.md")
|
(include "loongson.md")
|
|
|