;; ;; dlx.md ;; ;; Aaron Sawdey ;; ;; 1994-1995 ;; ;; A DLX Machine Description for GCC 2.x ;; ;; Possible improvements: ;; * add define_splits for common multi-instruction sequences ;; * add peephole optimizations ;; * add functional unit descriptions and scheduling information ;; ;; Since parts of this come from mips.md: ;; ;; This file is part of GNU CC. ;; ;; GNU CC is free software; you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation; either version 2, or (at your option) ;; any later version. ;; ;; GNU CC is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; ;; You should have received a copy of the GNU General Public License ;; along with GNU CC; see the file COPYING. If not, write to ;; the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. ;; ;; ;; Instruction types. Keep it simple for now; these categories ;; correspond (roughly) with the things on the back cover of H&P. ;; ;; ;; unknown ;; load mem load ;; store mem store ;; move reg-reg move ;; alu alu ops or int compares ;; branch conditional branch ;; jump unconditional branch ;; fp floating point op or fp compare ;; multi multiple different types ;; (define_attr "type" "unknown,load,store,move,alu,branch,jump,fp,multi" (const_string "unknown")) ; ; Define a memory unit that can process one load at a time ; and does not come back for 2 cycles. ; (define_function_unit "memory" 1 1 (or (eq_attr "type" "load") ; (eq_attr "type" "store")) 2 0) ; (define_attr "mode" "unknown,none,QI,HI,SI,DI,SF,DF" (const_string "unknown")) ;; # instructions (4 bytes each) (define_attr "length" "" (const_int 1)) (define_delay (eq_attr "type" "branch,jump") [(and (eq_attr "type" "!branch,jump") (eq_attr "length" "1")) (nil) (nil)]) (define_insn "addsf3" [(set (match_operand:SF 0 "register_operand" "=f") (plus:SF (match_operand:SF 1 "register_operand" "%f") (match_operand:SF 2 "register_operand" "f")))] "" "addf\\t%0,%1,%2" [(set_attr "type" "fp") (set_attr "mode" "SF")]) (define_insn "adddf3" [(set (match_operand:DF 0 "register_operand" "=f") (plus:DF (match_operand:DF 1 "register_operand" "%f") (match_operand:DF 2 "register_operand" "f")))] "" "addd\\t%0,%1,%2" [(set_attr "type" "fp") (set_attr "mode" "DF")]) (define_insn "subsf3" [(set (match_operand:SF 0 "register_operand" "=f") (minus:SF (match_operand:SF 1 "register_operand" "f") (match_operand:SF 2 "register_operand" "f")))] "" "subf\\t%0,%1,%2" [(set_attr "type" "fp") (set_attr "mode" "SF")]) (define_insn "subdf3" [(set (match_operand:DF 0 "register_operand" "=f") (minus:DF (match_operand:DF 1 "register_operand" "f") (match_operand:DF 2 "register_operand" "f")))] "" "subd\\t%0,%1,%2" [(set_attr "type" "fp") (set_attr "mode" "DF")]) (define_insn "mulsf3" [(set (match_operand:SF 0 "register_operand" "=f") (mult:SF (match_operand:SF 1 "register_operand" "%f") (match_operand:SF 2 "register_operand" "f")))] "" "multf\\t%0,%1,%2" [(set_attr "type" "fp") (set_attr "mode" "SF")]) (define_insn "muldf3" [(set (match_operand:DF 0 "register_operand" "=f") (mult:DF (match_operand:DF 1 "register_operand" "%f") (match_operand:DF 2 "register_operand" "f")))] "" "multd\\t%0,%1,%2" [(set_attr "type" "fp") (set_attr "mode" "DF")]) (define_insn "divsf3" [(set (match_operand:SF 0 "register_operand" "=f") (div:SF (match_operand:SF 1 "register_operand" "f") (match_operand:SF 2 "register_operand" "f")))] "" "divf\\t%0,%1,%2" [(set_attr "type" "fp") (set_attr "mode" "SF")]) (define_insn "divdf3" [(set (match_operand:DF 0 "register_operand" "=f") (div:DF (match_operand:DF 1 "register_operand" "f") (match_operand:DF 2 "register_operand" "f")))] "" "divd\\t%0,%1,%2" [(set_attr "type" "fp") (set_attr "mode" "DF")]) (define_insn "addsi3" [(set (match_operand:SI 0 "register_operand" "=d,d,d") (plus:SI (match_operand:SI 1 "register_operand" "%d,d,d") (match_operand:SI 2 "nonmemory_operand" "d,I,L")))] "" "@ add\\t%0,%1,%2 addi\\t%0,%1,%G2 addui\\t%0,%1,%U2" [(set_attr "type" "alu") (set_attr "mode" "SI")]) (define_insn "subsi3" [(set (match_operand:SI 0 "register_operand" "=d,d,d") (minus:SI (match_operand:SI 1 "register_operand" "d,d,d") (match_operand:SI 2 "nonmemory_operand" "d,I,L")))] "" "@ sub\\t%0,%1,%2 subi\\t%0,%1,%G2 subui\\t%0,%1,%U2" [(set_attr "type" "alu") (set_attr "mode" "SI")]) (define_insn "andsi3" [(set (match_operand:SI 0 "register_operand" "=d,d") (and:SI (match_operand:SI 1 "register_operand" "%d,d") (match_operand:SI 2 "nonmemory_operand" "d,L")))] "" "@ and\\t%0,%1,%2 andi\\t%0,%1,%U2" [(set_attr "type" "alu") (set_attr "mode" "SI")]) (define_insn "iorsi3" [(set (match_operand:SI 0 "register_operand" "=d,d") (ior:SI (match_operand:SI 1 "register_operand" "%d,d") (match_operand:SI 2 "nonmemory_operand" "d,L")))] "" "@ or\\t%0,%1,%2 ori\\t%0,%1,%U2" [(set_attr "type" "alu") (set_attr "mode" "SI")]) (define_insn "xorsi3" [(set (match_operand:SI 0 "register_operand" "=d,d") (xor:SI (match_operand:SI 1 "register_operand" "%d,d") (match_operand:SI 2 "nonmemory_operand" "d,L")))] "" "@ xor\\t%0,%1,%2 xori\\t%0,%1,%U2" [(set_attr "type" "alu") (set_attr "mode" "SI")]) ;; ;; -x = 0-x ;; This is ok for integers. ;; (define_insn "negsi2" [(set (match_operand:SI 0 "register_operand" "=d") (neg:SI (match_operand:SI 1 "register_operand" "d")))] "" "sub\\t%0,r0,%1" [(set_attr "type" "alu") (set_attr "mode" "SI")]) ;; ;; -x = 0-x ;; Alarm bells should be going off because this isn't ;; true for floating point numbers! Unfortunately DLX ;; doesn't have a "neg" instruction and the only better ;; solution is to multiply by -1 which is very painful. ;; (define_insn "negsf2" [(set (match_operand:SF 0 "register_operand" "=f") (neg:SF (match_operand:SF 1 "register_operand" "f"))) (clobber (match_scratch:SF 2 "=&f"))] "" "movi2fp\\t%2,r0\\n\\tcvti2f\\t%2,%2\\n\\tsubf\\t%0,%2,%1" [(set_attr "type" "alu") (set_attr "mode" "SF") (set_attr "length" "3")]) (define_insn "negdf2" [(set (match_operand:DF 0 "register_operand" "=f") (neg:DF (match_operand:DF 1 "register_operand" "f"))) (clobber (match_scratch:DF 2 "=&f"))] "" "movi2fp\\t%2,r0\\n\\tcvti2d\\t%2,%2\\n\\tsubd\\t%0,%2,%1" [(set_attr "type" "alu") (set_attr "mode" "DF") (set_attr "length" "3")]) (define_insn "one_cmplqi2" [(set (match_operand:QI 0 "register_operand" "=d") (not:QI (match_operand:QI 1 "register_operand" "d")))] "" "xori\\t%0,%1,#0x00ff" [(set_attr "type" "alu") (set_attr "mode" "SI") (set_attr "length" "1")]) (define_insn "one_cmplhi2" [(set (match_operand:HI 0 "register_operand" "=d") (not:HI (match_operand:HI 1 "register_operand" "d")))] "" "xori\\t%0,%1,#0xffff" [(set_attr "type" "alu") (set_attr "mode" "SI")]) (define_insn "one_cmplsi2" [(set (match_operand:SI 0 "register_operand" "=d") (not:SI (match_operand:SI 1 "register_operand" "d")))] "" "sub\\t%0,r0,%1\\n\\tsubi\\t%0,%0,#1" [(set_attr "type" "alu") (set_attr "mode" "SI") (set_attr "length" "2")]) (define_insn "ashlsi3" [(set (match_operand:SI 0 "register_operand" "=d,d") (ashift:SI (match_operand:SI 1 "register_operand" "d,d") (match_operand:SI 2 "nonmemory_operand" "d,I")))] "" "@ sll\\t%0,%1,%2 slli\\t%0,%1,%2" [(set_attr "type" "alu") (set_attr "mode" "SI")]) ;(define_insn "lshlsi3" ; [(set (match_operand:SI 0 "register_operand" "=d,d") ; (lshift:SI (match_operand:SI 1 "register_operand" "d,d") ; (match_operand:SI 2 "nonmemory_operand" "d,I")))] ; "" ; "@ ; sll\\t%0,%1,%2 ; slli\\t%0,%1,%2" ; [(set_attr "type" "alu") ; (set_attr "mode" "SI")]) (define_insn "ashrsi3" [(set (match_operand:SI 0 "register_operand" "=d,d") (ashiftrt:SI (match_operand:SI 1 "register_operand" "d,d") (match_operand:SI 2 "nonmemory_operand" "d,I")))] "" "@ sra\\t%0,%1,%2 srai\\t%0,%1,%2" [(set_attr "type" "alu") (set_attr "mode" "SI")]) (define_insn "lshrsi3" [(set (match_operand:SI 0 "register_operand" "=d,d") (lshiftrt:SI (match_operand:SI 1 "register_operand" "d,d") (match_operand:SI 2 "nonmemory_operand" "d,I")))] "" "@ srl\\t%0,%1,%2 srli\\t%0,%1,%2" [(set_attr "type" "alu") (set_attr "mode" "SI")]) (define_insn "mulsi3" [(set (match_operand:SI 0 "register_operand" "=d") (mult:SI (match_operand:SI 1 "register_operand" "d") (match_operand:SI 2 "register_operand" "d"))) (clobber (match_scratch:SF 3 "=&f")) (clobber (match_scratch:SF 4 "=&f"))] "" "movi2fp\\t%3,%1\\n\\ \\tmovi2fp\\t%4,%2\\n\\ \\tmult\\t%3,%3,%4\\n\\ \\tmovfp2i\\t%0,%3" [(set_attr "type" "fp") (set_attr "mode" "SI") (set_attr "length" "4")]) (define_insn "divsi3" [(set (match_operand:SI 0 "register_operand" "=d") (div:SI (match_operand:SI 1 "register_operand" "d") (match_operand:SI 2 "register_operand" "d"))) (clobber (match_scratch:SF 3 "=&f")) (clobber (match_scratch:SF 4 "=&f"))] "" "movi2fp\\t%3,%1\\n\\ \\tmovi2fp\\t%4,%2\\n\\ \\tdiv\\t%3,%3,%4\\n\\ \\tmovfp2i\\t%0,%3" [(set_attr "type" "fp") (set_attr "mode" "SI") (set_attr "length" "4")]) (define_insn "udivsi3" [(set (match_operand:SI 0 "register_operand" "=d") (udiv:SI (match_operand:SI 1 "register_operand" "d") (match_operand:SI 2 "register_operand" "d"))) (clobber (match_scratch:SF 3 "=&f")) (clobber (match_scratch:SF 4 "=&f"))] "" "movi2fp\\t%3,%1\\n\\ \\tmovi2fp\\t%4,%2\\n\\ \\tdivu\\t%3,%3,%4\\n\\ \\tmovfp2i\\t%0,%3" [(set_attr "type" "fp") (set_attr "mode" "SI") (set_attr "length" "4")]) ;; ;; Conversion patterns ;; (define_insn "floatsisf2" [(set (match_operand:SF 0 "register_operand" "=f") (float:SF (match_operand:SI 1 "register_operand" "d")))] "" "movi2fp\\t%0,%1\\n\\tcvti2f\\t%0,%0" [(set_attr "type" "fp") (set_attr "mode" "SF") (set_attr "length" "2")]) (define_insn "floatsidf2" [(set (match_operand:DF 0 "register_operand" "=f") (float:DF (match_operand:SI 1 "register_operand" "d")))] "" "movi2fp\\t%0,%1\\n\\tcvti2d\\t%0,%0" [(set_attr "type" "fp") (set_attr "mode" "DF") (set_attr "length" "2")]) (define_insn "fix_truncsfsi2" [(set (match_operand:SI 0 "register_operand" "=d") (fix:SI (match_operand:SF 1 "register_operand" "+f"))) (clobber (match_scratch:SF 2 "=&f"))] "" "cvtf2i\\t%2,%1\\n\\tmovfp2i\\t%0,%2\\n" [(set_attr "type" "fp") (set_attr "mode" "SF") (set_attr "length" "2")]) (define_insn "fix_truncdfsi2" [(set (match_operand:SI 0 "register_operand" "=d") (fix:SI (match_operand:DF 1 "register_operand" "+f"))) (clobber (match_scratch:DF 2 "=&f"))] "" "cvtd2i\\t%2,%1\\n\\tmovfp2i\\t%0,%2\\n" [(set_attr "type" "fp") (set_attr "mode" "DF") (set_attr "length" "2")]) (define_insn "truncdfsf2" [(set (match_operand:SF 0 "register_operand" "=f") (float_truncate:SF (match_operand:DF 1 "register_operand" "f")))] "" "cvtd2f\\t%0,%1" [(set_attr "type" "fp") (set_attr "mode" "SF")]) (define_insn "truncsihi2" [(set (match_operand:HI 0 "general_operand" "=d,m") (truncate:HI (match_operand:SI 1 "register_operand" "d,d")))] "" "@ andi\\t%0,%1,#0xffff sh\\t%0,%1" [(set_attr "type" "alu,store") (set_attr "mode" "HI") (set_attr "length" "2")]) (define_insn "truncsiqi2" [(set (match_operand:QI 0 "general_operand" "=d,m") (truncate:QI (match_operand:SI 1 "register_operand" "d,d")))] "" "@ andi\\t%0,%1,#0x00ff sb\\t%0,%1" [(set_attr "type" "alu,store") (set_attr "mode" "QI")]) (define_insn "trunchiqi2" [(set (match_operand:QI 0 "general_operand" "=d,m") (truncate:QI (match_operand:HI 1 "register_operand" "d,d")))] "" "@ andi\\t%0,%1,#0x00ff sb\\t%0,%1" [(set_attr "type" "alu,store") (set_attr "mode" "QI")]) (define_insn "zero_extendqihi2" [(set (match_operand:HI 0 "register_operand" "=d,d") (zero_extend:HI (match_operand:QI 1 "general_operand" "d,m")))] "" "@ andi\\t%0,%1,#0x00ff lbu\\t%0,%1" [(set_attr "type" "alu,load") (set_attr "mode" "HI")]) (define_insn "zero_extendhisi2" [(set (match_operand:SI 0 "register_operand" "=d,d") (zero_extend:SI (match_operand:HI 1 "general_operand" "d,m")))] "" "@ andi\\t%0,%1,#0xffff lhu\\t%0,%1" [(set_attr "type" "alu,load") (set_attr "mode" "SI")]) (define_insn "zero_extendqisi2" [(set (match_operand:SI 0 "register_operand" "=d,d") (zero_extend:SI (match_operand:QI 1 "general_operand" "d,m")))] "" "@ andi\\t%0,%1,#0x00ff lbu\\t%0,%1" [(set_attr "type" "alu,load") (set_attr "mode" "SI")]) (define_insn "extendqisi2" [(set (match_operand:SI 0 "register_operand" "=d,d") (sign_extend:SI (match_operand:QI 1 "general_operand" "d,m")))] "" "@ slli\\t%0,%1,#24\\n\\tsrai\\t%0,%0,#24 lb\\t%0,%1" [(set_attr "type" "alu,load") (set_attr "mode" "SI") (set_attr "length" "2,1")]) (define_insn "extendhisi2" [(set (match_operand:SI 0 "register_operand" "=d,d") (sign_extend:SI (match_operand:HI 1 "general_operand" "d,m")))] "" "@ slli\\t%0,%1,#16\\n\\tsrai\\t%0,%0,#16 lh\\t%0,%1" [(set_attr "type" "alu,load") (set_attr "mode" "SI") (set_attr "length" "2,1")]) (define_insn "extendqihi2" [(set (match_operand:HI 0 "register_operand" "=d") (sign_extend:HI (match_operand:QI 1 "register_operand" "d")))] "" "slli\\t%0,%1,#24\\n\\tsrai\\t%0,%0,#24\\n\\tandi\\t%0,%0,#0xffff" [(set_attr "type" "alu") (set_attr "mode" "HI") (set_attr "length" "3")]) (define_insn "extendsfdf2" [(set (match_operand:DF 0 "register_operand" "=f") (float_extend:DF (match_operand:SF 1 "register_operand" "f")))] "" "cvtf2d\\t%0,%1" [(set_attr "type" "fp") (set_attr "mode" "DF")]) ;; ;; move instructions: ;; mem-reg, reg-mem, imm-reg ;; ;; The standard "movsi" pattern for RTL generation. It ;; makes sure one of the operands is in a register, but ;; avoids trying to do this later during compilation when ;; the register allocation is complete. ;; ;; This pattern was lifted almost verbatim from the MIPS machine ;; description. ;; (define_expand "movsi" [(set (match_operand:SI 0 "nonimmediate_operand" "") (match_operand:SI 1 "general_operand" ""))] "" " { if ((reload_in_progress | reload_completed) == 0 && !register_operand (operands[0], SImode) && !register_operand (operands[1], SImode)) { rtx temp = force_reg (SImode, operands[1]); temp = emit_move_insn (operands[0], temp); DONE; } }") ;; ;; This is used to match against RTL during assembly code ;; generation. It knows how to move floats in and out of ;; integer registers. ;; ;; We have to be sure to set the length correctly. Otherwise, ;; the delay slot filler will try to move something into a delay ;; slot that produces more than one DLX instruction, which would ;; produce incorrect code. So when we generate an addui/lhi sequence ;; to load a constant, we have to make sure the length is set to 2. ;; (define_insn "movsi_general" [(set (match_operand:SI 0 "general_operand" "=d,d,d,d,m,df") (match_operand:SI 1 "general_operand" "I,L,i,m,d,df"))] "" "* { switch(which_alternative) { case 0: return \"addi\\t%0,r0,%G1\"; case 1: return \"addui\\t%0,r0,%U1\"; case 2: if(GET_CODE(operands[1]) == CONST_INT) { return \"lhi\\t%0,%H1\\n\\taddui\\t%0,%0,%L1\"; } else { return \"lhi\\t%0,((%1)>>16)&0xffff\\n\\taddui\\t%0,%0,(%1)&0xffff\"; } case 3: return \"lw\\t%0,%1\"; case 4: return \"sw\\t%0,%1\"; case 5: { int f0,f1; f0 = FLOAT_MODE_P(GET_MODE(operands[0])); f1 = FLOAT_MODE_P(GET_MODE(operands[1])); if(!f0 && !f1) return \"add\\t%0,r0,%1\"; else if(!f0 && f1) return \"movfp2i\\t%0,%1\"; else if(f0 && !f1) return \"movi2fp\\t%0,%1\"; else return \"movf\\t%0,%1\"; } } }" [(set_attr "type" "move,move,move,load,store,move") (set_attr "mode" "SI") (set_attr "length" "1,1,2,1,1,1")]) ;; ;; Move half words. ;; (define_expand "movhi" [(set (match_operand:HI 0 "nonimmediate_operand" "") (match_operand:HI 1 "general_operand" ""))] "" " { if ((reload_in_progress | reload_completed) == 0 && !register_operand (operands[0], HImode) && !register_operand (operands[1], HImode)) { rtx temp = force_reg (HImode, operands[1]); temp = emit_move_insn (operands[0], temp); DONE; } }") (define_insn "movhi_general" [(set (match_operand:HI 0 "general_operand" "=d,d,m,d") (match_operand:HI 1 "general_operand" "i,m,d,d"))] "" "* { switch(which_alternative) { case 0: return \"addi\\t%0,r0,%G1\"; case 1: return \"lh\\t%0,%1\"; case 2: return \"sh\\t%0,%1\"; case 3: return \"add\\t%0,r0,%1\"; } }" [(set_attr "type" "move,load,store,move") (set_attr "mode" "HI")]) ;; ;; move bytes. ;; (define_expand "movqi" [(set (match_operand:QI 0 "nonimmediate_operand" "") (match_operand:QI 1 "general_operand" ""))] "" " { if ((reload_in_progress | reload_completed) == 0 && !register_operand (operands[0], QImode) && !register_operand (operands[1], QImode)) { rtx temp = force_reg (QImode, operands[1]); temp = emit_move_insn (operands[0], temp); DONE; } }") (define_insn "movqi_general" [(set (match_operand:QI 0 "general_operand" "=d,d,m,d") (match_operand:QI 1 "general_operand" "i,m,d,d"))] "" "* { switch(which_alternative) { case 0: return \"addi\\t%0,r0,(%1)&0xff\"; case 1: return \"lb\\t%0,%1\"; case 2: return \"sb\\t%0,%1\"; case 3: return \"add\\t%0,r0,%1\"; } }" [(set_attr "type" "move,load,store,move") (set_attr "mode" "QI")]) ;; ;; Move floats. ;; (define_expand "movsf" [(set (match_operand:SF 0 "nonimmediate_operand" "") (match_operand:SF 1 "general_operand" ""))] "" " { if ((reload_in_progress | reload_completed) == 0 && !register_operand (operands[0], SFmode) && !register_operand (operands[1], SFmode)) { rtx temp = force_reg (SFmode, operands[1]); temp = emit_move_insn (operands[0], temp); DONE; } }") ;; ;; This pattern has to handle the strange special case of ;; moving a float value into r1 to return it. This is required ;; to be compatible with Peter Dahl's C-Regs C Compiler. ;; (define_insn "movsf_general" [(set (match_operand:SF 0 "general_operand" "=f,m,df") (match_operand:SF 1 "general_operand" "m,f,df"))] "" "* { switch(which_alternative) { case 0: return \"lf\\t%0,%1\"; case 1: return \"sf\\t%0,%1\"; case 2: { int f0,f1; f0 = (REGNO(operands[0]) >= FIRST_FP_REG); f1 = (REGNO(operands[1]) >= FIRST_FP_REG); if(!f0 && !f1) return \"add\\t%0,r0,%1\"; else if(!f0 && f1) return \"movfp2i\\t%0,%1\"; else if(f0 && !f1) return \"movi2fp\\t%0,%1\"; else return \"movf\\t%0,%1\"; } } }" [(set_attr "type" "load,store,move") (set_attr "mode" "SF")]) (define_expand "movdf" [(set (match_operand:DF 0 "nonimmediate_operand" "") (match_operand:DF 1 "general_operand" ""))] "" " { if ((reload_in_progress | reload_completed) == 0 && !register_operand (operands[0], DFmode) && !register_operand (operands[1], DFmode)) { rtx temp = force_reg (DFmode, operands[1]); temp = emit_move_insn (operands[0], temp); DONE; } }") (define_insn "movdf_general" [(set (match_operand:DF 0 "general_operand" "=f,m,f") (match_operand:DF 1 "general_operand" "m,f,f"))] "" "* { switch(which_alternative) { case 0: return \"ld\\t%0,%1\"; case 1: return \"sd\\t%0,%1\"; case 2: return \"movd\\t%0,%1\"; } }" [(set_attr "type" "load,store,move") (set_attr "mode" "DF")]) ;; ;; define_split for splitting addui/lhi pairs. ;; ; ; These don't work all the time. ; ;; (define_split ;; [(set (match_operand:SI 0 "register_operand" "=&d") ;; (match_operand:SI 1 "immediate_operand" "i"))] ;; "!(GET_CODE(operands[1])==CONST_INT && SMALL_INT(operands[1]))" ;; [(set (match_dup 0) (zero_extract:SI (match_dup 1) ;; (const_int 16) (const_int 0))) ;; (set (match_dup 0) (ior:SI (zero_extract:SI (match_dup 0) ;; (const_int 16) (const_int 0)) ;; (zero_extract:SI (match_dup 1) ;; (const_int 16) (const_int 16))))] ;; "") ;; ;; (define_insn "addui_split" ;; [(set (match_operand:SI 0 "register_operand" "=d") ;; (zero_extract:SI (match_operand:SI 1 "" "") ;; (const_int 16) (const_int 0)))] ;; "" ;; "* ;; { ;; if(GET_CODE(operands[1]) == CONST_INT) ;; return \"addui\\t%0,r0,%L1\\t; split\"; ;; else ;; return \"addui\\t%0,r0,(%1)&0xffff\\t; split\"; }" ;; [(set_attr "type" "alu") ;; (set_attr "mode" "SI") ;; (set_attr "length" "1")]) ;; ;; (define_insn "lhi_split" ;; [(set (match_operand:SI 0 "register_operand" "=&d") ;; (ior:SI (zero_extract:SI (match_dup 0) (const_int 16) (const_int 0)) ;; (zero_extract:SI (match_operand:SI 1 "immediate_operand" "i") ;; (const_int 16) (const_int 16))))] ;; "" ;; "* ;; { ;; if(GET_CODE(operands[1]) == CONST_INT) ;; return \"lhi\\t%0,%H1\\t; split\"; ;; else ;; return \"lhi\\t%0,((%1)>>16)&0xffff\\t; split\"; }" ;; [(set_attr "type" "alu") ;; (set_attr "mode" "SI") ;; (set_attr "length" "1")]) ;; ;; No-Op ;; (define_insn "nop" [(const_int 0)] "" "nop" [(set_attr "type" "alu") (set_attr "mode" "none") (set_attr "length" "1")]) ;; ;; unconditional branches and such. ;; (define_insn "indirect_jump" [(set (pc) (match_operand:SI 0 "register_operand" "d"))] "" "jr\\t%0%(" [(set_attr "type" "jump") (set_attr "mode" "none")]) (define_insn "jump" [(set (pc) (label_ref (match_operand 0 "" "")))] "" "* { if (GET_CODE (operands[0]) == REG) return \"jr\\t%0%(\"; else return \"j\\t%0%(\"; }" [(set_attr "type" "jump") (set_attr "mode" "none")]) ;; ;; calls ;; ;; (define_insn "call_value" ;; [(parallel [(set (match_operand 0 "register_operand" "=df") ;; (call (match_operand 1 "sym_ref_mem_operand" "") ;; (match_operand 2 "" "i"))) ;; (clobber (reg:SI 31))])] ;; "" ;; "jal\\t%S1%(" ;; [(set_attr "type" "jump") ;; (set_attr "mode" "none")]) (define_expand "call_value" [(parallel [(set (match_operand 0 "register_operand" "=df") (call (match_operand 1 "sym_ref_mem_operand" "") (match_operand 2 "" "i"))) (clobber (reg:SI 31))])] "" "{ gen_call_value_1(operands); DONE; }" ) (define_insn "call" [(parallel [(call (match_operand 0 "sym_ref_mem_operand" "") (match_operand 1 "" "i")) (clobber (reg:SI 31))])] "" "jal\\t%S0%(" [(set_attr "type" "jump") (set_attr "mode" "none")]) (define_insn "call_value_indirect" [(parallel [(set (match_operand 0 "register_operand" "=df") (call (mem:QI (match_operand 1 "register_operand" "d")) (match_operand 2 "" "i"))) (clobber (reg:SI 31))])] "" "jalr\\t%1%(" [(set_attr "type" "jump") (set_attr "mode" "none")]) (define_insn "call_indirect" [(parallel [(call (mem:QI (match_operand 0 "register_operand" "d")) (match_operand 1 "" "i")) (clobber (reg:SI 31))])] "" "jalr\\t%0%(" [(set_attr "type" "jump") (set_attr "mode" "none")]) ;; ;; RTL for this is generated by the define_expand for call_value. ;; ;; ;; calls that return int in r1 ;; (define_insn "call_val_internal_return_r1" [(parallel [(set (reg:SI 1) (call (match_operand 0 "sym_ref_mem_operand" "") (match_operand 1 "" "i"))) (clobber (reg:SI 31))])] "" "jal\\t%S0%(" [(set_attr "type" "jump") (set_attr "mode" "none")]) (define_insn "call_val_internal_return_r1_halfword" [(parallel [(set (reg:HI 1) (call (match_operand 0 "sym_ref_mem_operand" "") (match_operand 1 "" "i"))) (clobber (reg:SI 31))])] "" "jal\\t%S0%(" [(set_attr "type" "jump") (set_attr "mode" "none")]) (define_insn "call_val_internal_return_r1_quarterword" [(parallel [(set (reg:QI 1) (call (match_operand 0 "sym_ref_mem_operand" "") (match_operand 1 "" "i"))) (clobber (reg:SI 31))])] "" "jal\\t%S0%(" [(set_attr "type" "jump") (set_attr "mode" "none")]) ;; ;; calls that return float in f0 ;; (define_insn "call_val_internal_return_f0_float" [(parallel [(set (reg:SF 32) (call (match_operand 0 "sym_ref_mem_operand" "") (match_operand 1 "" "i"))) (clobber (reg:SI 31))])] "" "jal\\t%S0%(" [(set_attr "type" "jump") (set_attr "mode" "none")]) ;; ;; calls that return double in f0/f1 ;; (define_insn "call_val_internal_return_f0f1" [(parallel [(set (reg:DF 32) (call (match_operand 0 "sym_ref_mem_operand" "") (match_operand 1 "" "i"))) (clobber (reg:SI 31))])] "" "jal\\t%S0%(\\n" [(set_attr "type" "jump") (set_attr "mode" "none")]) ;; ;; calls that don't return a value. ;; (define_insn "call_val_internal_no_return" [(call (match_operand 0 "sym_ref_mem_operand" "") (match_operand 1 "" "i"))] "" "jal\\t%S0%(" [(set_attr "type" "jump") (set_attr "mode" "none")]) ;; ;; tablejump insn; used in generating code for switches. ;; (define_insn "tablejump" [(set (pc) (match_operand:SI 0 "register_operand" "d")) (use (label_ref (match_operand 1 "" "")))] "" "jr\\t%0%(" [(set_attr "type" "jump") (set_attr "mode" "none") (set_attr "length" "1")]) ;; ;; Comparisons and branches. ;; (define_expand "cmpsi" [(set (cc0) (compare:CC (match_operand:SI 0 "register_operand" "d") (match_operand:SI 1 "nonmemory_operand" "dI")))] "" " { dlx_compare_op0 = operands[0]; dlx_compare_op1 = operands[1]; dlx_compare_mode = SImode; DONE; }") (define_expand "tstsi" [(set (cc0) (match_operand:SI 0 "register_operand" "d"))] "" " { dlx_compare_op0 = operands[0]; dlx_compare_op1 = const0_rtx; dlx_compare_mode = SImode; DONE; }") (define_expand "cmpdf" [(set (cc0) (compare:CCFP (match_operand:DF 0 "register_operand" "f") (match_operand:DF 1 "register_operand" "f")))] "" " { dlx_compare_op0 = operands[0]; dlx_compare_op1 = operands[1]; dlx_compare_mode = DFmode; DONE; }") (define_expand "cmpsf" [(set (cc0) (compare:CCFP (match_operand:SF 0 "register_operand" "f") (match_operand:SF 1 "register_operand" "f")))] "" " { dlx_compare_op0 = operands[0]; dlx_compare_op1 = operands[1]; dlx_compare_mode = SFmode; DONE; }") ;; ;; Branches. ;; These have to be written out individually because they ;; are called by name during code generation. ;; (define_expand "beq" [(set (pc) (if_then_else (eq (cc0) (const_int 0)) (label_ref (match_operand 0 "" "")) (pc)))] "" "{ gen_conditional_branch(operands, EQ); DONE; }") (define_expand "bne" [(set (pc) (if_then_else (ne (cc0) (const_int 0)) (label_ref (match_operand 0 "" "")) (pc)))] "" "{ gen_conditional_branch(operands, NE); DONE; }") (define_expand "blt" [(set (pc) (if_then_else (lt (cc0) (const_int 0)) (label_ref (match_operand 0 "" "")) (pc)))] "" "{ gen_conditional_branch(operands, LT); DONE; }") (define_expand "bgt" [(set (pc) (if_then_else (gt (cc0) (const_int 0)) (label_ref (match_operand 0 "" "")) (pc)))] "" "{ gen_conditional_branch(operands, GT); DONE; }") (define_expand "ble" [(set (pc) (if_then_else (le (cc0) (const_int 0)) (label_ref (match_operand 0 "" "")) (pc)))] "" "{ gen_conditional_branch(operands, LE); DONE; }") (define_expand "bge" [(set (pc) (if_then_else (ge (cc0) (const_int 0)) (label_ref (match_operand 0 "" "")) (pc)))] "" "{ gen_conditional_branch(operands, GE); DONE; }") (define_expand "bltu" [(set (pc) (if_then_else (ltu (cc0) (const_int 0)) (label_ref (match_operand 0 "" "")) (pc)))] "" "{ gen_conditional_branch(operands, LTU); DONE; }") (define_expand "bgtu" [(set (pc) (if_then_else (gtu (cc0) (const_int 0)) (label_ref (match_operand 0 "" "")) (pc)))] "" "{ gen_conditional_branch(operands, GTU); DONE; }") (define_expand "bleu" [(set (pc) (if_then_else (leu (cc0) (const_int 0)) (label_ref (match_operand 0 "" "")) (pc)))] "" "{ gen_conditional_branch(operands, LEU); DONE; }") (define_expand "bgeu" [(set (pc) (if_then_else (geu (cc0) (const_int 0)) (label_ref (match_operand 0 "" "")) (pc)))] "" "{ gen_conditional_branch(operands, GEU); DONE; }") ; ; Set instructions. ; (define_expand "seq" [(set (match_operand:SI 0 "register_operand" "=d") (eq:SI (match_dup 1) (match_dup 2)))] "" " if(dlx_compare_mode != SImode) FAIL; operands[1] = dlx_compare_op0; operands[2] = dlx_compare_op1; ") (define_expand "sne" [(set (match_operand:SI 0 "register_operand" "=d") (ne:SI (match_dup 1) (match_dup 2)))] "" " if(dlx_compare_mode != SImode) FAIL; operands[1] = dlx_compare_op0; operands[2] = dlx_compare_op1; ") (define_expand "slt" [(set (match_operand:SI 0 "register_operand" "=d") (lt:SI (match_dup 1) (match_dup 2)))] "" " if(dlx_compare_mode != SImode) FAIL; operands[1] = dlx_compare_op0; operands[2] = dlx_compare_op1; ") (define_expand "sgt" [(set (match_operand:SI 0 "register_operand" "=d") (gt:SI (match_dup 1) (match_dup 2)))] "" " if(dlx_compare_mode != SImode) FAIL; operands[1] = dlx_compare_op0; operands[2] = dlx_compare_op1; ") (define_expand "sle" [(set (match_operand:SI 0 "register_operand" "=d") (le:SI (match_dup 1) (match_dup 2)))] "" " if(dlx_compare_mode != SImode) FAIL; operands[1] = dlx_compare_op0; operands[2] = dlx_compare_op1; ") (define_expand "sge" [(set (match_operand:SI 0 "register_operand" "=d") (ge:SI (match_dup 1) (match_dup 2)))] "" " if(dlx_compare_mode != SImode) FAIL; operands[1] = dlx_compare_op0; operands[2] = dlx_compare_op1; ") (define_expand "sltu" [(set (match_operand:SI 0 "register_operand" "=d") (ltu:SI (match_dup 1) (match_dup 2)))] "" " if(dlx_compare_mode != SImode) FAIL; operands[1] = dlx_compare_op0; operands[2] = dlx_compare_op1; ") (define_expand "sgtu" [(set (match_operand:SI 0 "register_operand" "=d") (gtu:SI (match_dup 1) (match_dup 2)))] "" " if(dlx_compare_mode != SImode) FAIL; operands[1] = dlx_compare_op0; operands[2] = dlx_compare_op1; ") (define_expand "sleu" [(set (match_operand:SI 0 "register_operand" "=d") (leu:SI (match_dup 1) (match_dup 2)))] "" " if(dlx_compare_mode != SImode) FAIL; operands[1] = dlx_compare_op0; operands[2] = dlx_compare_op1; ") (define_expand "sgeu" [(set (match_operand:SI 0 "register_operand" "=d") (geu:SI (match_dup 1) (match_dup 2)))] "" " if(dlx_compare_mode != SImode) FAIL; operands[1] = dlx_compare_op0; operands[2] = dlx_compare_op1; ") ;; ;; Integer conditional branches; the RTL for these is ;; generated in gen_conditional_branch(). ;; (define_insn "int_cond_branch" [(set (pc) (if_then_else (eq:SI (const_int 0) (match_operand:SI 0 "register_operand" "d")) (label_ref (match_operand 1 "" "")) (pc)))] "" "beqz\\t%0,%1%(" [(set_attr "type" "branch") (set_attr "mode" "SI")]) (define_insn "int_cond_branch_rev" [(set (pc) (if_then_else (ne:SI (const_int 0) (match_operand:SI 0 "register_operand" "d")) (label_ref (match_operand 1 "" "")) (pc)))] "" "bnez\\t%0,%1%(" [(set_attr "type" "branch") (set_attr "mode" "SI")]) ;; ;; Floating point conditional branches, ;; also generated in gen_conditional_branch(). ;; (define_insn "fp_cond_branch" [(set (pc) (if_then_else (ne:CCFP (match_operand:CCFP 0 "register_operand" "z") (const_int 0)) (label_ref (match_operand 1 "" "")) (pc)))] "" "bfpt\\t%1%(" [(set_attr "type" "branch") (set_attr "mode" "SF")]) (define_insn "fp_cond_branch_rev" [(set (pc) (if_then_else (eq:CCFP (match_operand:CCFP 0 "register_operand" "z") (const_int 0)) (label_ref (match_operand 1 "" "")) (pc)))] "" "bfpf\\t%1%(" [(set_attr "type" "branch") (set_attr "mode" "SF")]) ;; ;; RTL for s__ instructions. ;; The RTL for these is generated in gen_conditional_branch(). ;; ;; The match_operator RTL expression is very useful ;; here in that you can write 3 patterns for about ;; 32 instructions. ;; (define_insn "set_internal" [(set (match_operand:SI 0 "register_operand" "=d,d") (match_operator:SI 1 "comparison_operator" [(match_operand:SI 2 "register_operand" "d,d") (match_operand:SI 3 "nonmemory_operand" "d,I")]))] "" "@ s%C1\\t%0,%2,%3 s%C1i\\t%0,%2,%G3" [(set_attr "type" "alu") (set_attr "mode" "SI")]) ;; ;; Float compares. ;; The RTL for these is also generated in ;; gen_conditional_branch(). ;; (define_insn "" [(set (match_operand:CCFP 0 "register_operand" "=z") (match_operator:SF 1 "signed_comparison_operator" [(match_operand:SF 2 "register_operand" "f") (match_operand:SF 3 "register_operand" "f")]))] "" "%C1f\\t%2,%3" [(set_attr "type" "fp") (set_attr "mode" "SF")]) (define_insn "" [(set (match_operand:CCFP 0 "register_operand" "=z") (match_operator:DF 1 "signed_comparison_operator" [(match_operand:DF 2 "register_operand" "f") (match_operand:DF 3 "register_operand" "f")]))] "" "%C1d\\t%2,%3" [(set_attr "type" "fp") (set_attr "mode" "DF")])