| ;; Machine description of the Lattice Mico32 architecture for GNU C compiler. |
| ;; Contributed by Jon Beniston <jon@beniston.com> |
| |
| ;; Copyright (C) 2009-2025 Free Software Foundation, Inc. |
| |
| ;; This file is part of GCC. |
| |
| ;; GCC 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 3, or (at your |
| ;; option) any later version. |
| |
| ;; GCC 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 GCC; see the file COPYING3. If not see |
| ;; <http://www.gnu.org/licenses/>. |
| |
| ;; Include predicate and constraint definitions |
| (include "predicates.md") |
| (include "constraints.md") |
| |
| |
| ;; Register numbers |
| (define_constants |
| [(RA_REGNUM 29) ; return address register. |
| ] |
| ) |
| |
| ;; LM32 specific volatile operations |
| (define_constants |
| [(UNSPECV_BLOCKAGE 1)] ; prevent scheduling across pro/epilog boundaries |
| ) |
| |
| ;; LM32 specific operations |
| (define_constants |
| [(UNSPEC_GOT 2) |
| (UNSPEC_GOTOFF_HI16 3) |
| (UNSPEC_GOTOFF_LO16 4)] |
| ) |
| |
| ;; --------------------------------- |
| ;; instruction types |
| ;; --------------------------------- |
| |
| (define_attr "type" |
| "unknown,load,store,arith,compare,shift,multiply,divide,call,icall,ubranch,uibranch,cbranch" |
| (const_string "unknown")) |
| |
| ;; --------------------------------- |
| ;; instruction lengths |
| ;; --------------------------------- |
| |
| ; All instructions are 4 bytes |
| ; Except for branches that are out of range, and have to be implemented |
| ; as two instructions |
| (define_attr "length" "" |
| (cond [ |
| (eq_attr "type" "cbranch") |
| (if_then_else |
| (lt (abs (minus (match_dup 2) (pc))) |
| (const_int 32768) |
| ) |
| (const_int 4) |
| (const_int 8) |
| ) |
| ] |
| (const_int 4)) |
| ) |
| |
| ;; --------------------------------- |
| ;; scheduling |
| ;; --------------------------------- |
| |
| (define_automaton "lm32") |
| |
| (define_cpu_unit "x" "lm32") |
| (define_cpu_unit "m" "lm32") |
| (define_cpu_unit "w" "lm32") |
| |
| (define_insn_reservation "singlecycle" 1 |
| (eq_attr "type" "store,arith,call,icall,ubranch,uibranch,cbranch") |
| "x") |
| |
| (define_insn_reservation "twocycle" 2 |
| (eq_attr "type" "compare,shift,divide") |
| "x,m") |
| |
| (define_insn_reservation "threecycle" 3 |
| (eq_attr "type" "load,multiply") |
| "x,m,w") |
| |
| ;; --------------------------------- |
| ;; mov |
| ;; --------------------------------- |
| |
| (define_expand "movqi" |
| [(set (match_operand:QI 0 "general_operand" "") |
| (match_operand:QI 1 "general_operand" ""))] |
| "" |
| " |
| { |
| if (can_create_pseudo_p ()) |
| { |
| if (GET_CODE (operand0) == MEM) |
| { |
| /* Source operand for store must be in a register. */ |
| operands[1] = force_reg (QImode, operands[1]); |
| } |
| } |
| }") |
| |
| (define_expand "movhi" |
| [(set (match_operand:HI 0 "general_operand" "") |
| (match_operand:HI 1 "general_operand" ""))] |
| "" |
| " |
| { |
| if (can_create_pseudo_p ()) |
| { |
| if (GET_CODE (operands[0]) == MEM) |
| { |
| /* Source operand for store must be in a register. */ |
| operands[1] = force_reg (HImode, operands[1]); |
| } |
| } |
| }") |
| |
| (define_expand "movsi" |
| [(set (match_operand:SI 0 "general_operand" "") |
| (match_operand:SI 1 "general_operand" ""))] |
| "" |
| " |
| { |
| if (can_create_pseudo_p ()) |
| { |
| if (GET_CODE (operands[0]) == MEM |
| || (GET_CODE (operands[0]) == SUBREG |
| && GET_CODE (SUBREG_REG (operands[0])) == MEM)) |
| { |
| /* Source operand for store must be in a register. */ |
| operands[1] = force_reg (SImode, operands[1]); |
| } |
| } |
| |
| if (flag_pic && symbolic_operand (operands[1], SImode)) |
| { |
| if (GET_CODE (operands[1]) == LABEL_REF |
| || (GET_CODE (operands[1]) == SYMBOL_REF |
| && SYMBOL_REF_LOCAL_P (operands[1]) |
| && !SYMBOL_REF_WEAK (operands[1]))) |
| { |
| emit_insn (gen_movsi_gotoff_hi16 (operands[0], operands[1])); |
| emit_insn (gen_addsi3 (operands[0], |
| operands[0], |
| pic_offset_table_rtx)); |
| emit_insn (gen_movsi_gotoff_lo16 (operands[0], |
| operands[0], |
| operands[1])); |
| } |
| else |
| emit_insn (gen_movsi_got (operands[0], operands[1])); |
| crtl->uses_pic_offset_table = 1; |
| DONE; |
| } |
| else if (flag_pic && GET_CODE (operands[1]) == CONST) |
| { |
| rtx op = XEXP (operands[1], 0); |
| if (GET_CODE (op) == PLUS) |
| { |
| rtx arg0 = XEXP (op, 0); |
| rtx arg1 = XEXP (op, 1); |
| if (GET_CODE (arg0) == LABEL_REF |
| || (GET_CODE (arg0) == SYMBOL_REF |
| && SYMBOL_REF_LOCAL_P (arg0) |
| && !SYMBOL_REF_WEAK (arg0))) |
| { |
| emit_insn (gen_movsi_gotoff_hi16 (operands[0], arg0)); |
| emit_insn (gen_addsi3 (operands[0], |
| operands[0], |
| pic_offset_table_rtx)); |
| emit_insn (gen_movsi_gotoff_lo16 (operands[0], |
| operands[0], |
| arg0)); |
| } |
| else |
| emit_insn (gen_movsi_got (operands[0], arg0)); |
| emit_insn (gen_addsi3 (operands[0], operands[0], arg1)); |
| crtl->uses_pic_offset_table = 1; |
| DONE; |
| } |
| } |
| else if (!flag_pic && reloc_operand (operands[1], GET_MODE (operands[1]))) |
| { |
| emit_insn (gen_rtx_SET (operands[0], gen_rtx_HIGH (SImode, operands[1]))); |
| emit_insn (gen_rtx_SET (operands[0], gen_rtx_LO_SUM (SImode, operands[0], |
| operands[1]))); |
| DONE; |
| } |
| else if (GET_CODE (operands[1]) == CONST_INT) |
| { |
| if (!(satisfies_constraint_K (operands[1]) |
| || satisfies_constraint_L (operands[1]) |
| || satisfies_constraint_U (operands[1]))) |
| { |
| emit_insn (gen_movsi_insn (operands[0], |
| GEN_INT (INTVAL (operands[1]) & ~0xffff))); |
| emit_insn (gen_iorsi3 (operands[0], |
| operands[0], |
| GEN_INT (INTVAL (operands[1]) & 0xffff))); |
| DONE; |
| } |
| } |
| }") |
| |
| (define_expand "cpymemsi" |
| [(parallel [(set (match_operand:BLK 0 "general_operand" "") |
| (match_operand:BLK 1 "general_operand" "")) |
| (use (match_operand:SI 2 "" "")) |
| (use (match_operand:SI 3 "const_int_operand" ""))])] |
| "" |
| { |
| if (!lm32_expand_block_move (operands)) |
| FAIL; |
| DONE; |
| }) |
| |
| ;; --------------------------------- |
| ;; load/stores/moves |
| ;; --------------------------------- |
| |
| (define_insn "movsi_got" |
| [(set (match_operand:SI 0 "register_operand" "=r") |
| (unspec:SI [(match_operand 1 "" "")] UNSPEC_GOT))] |
| "flag_pic" |
| "lw %0, (gp+got(%1))" |
| [(set_attr "type" "load")] |
| ) |
| |
| (define_insn "movsi_gotoff_hi16" |
| [(set (match_operand:SI 0 "register_operand" "=r") |
| (unspec:SI [(match_operand 1 "" "")] UNSPEC_GOTOFF_HI16))] |
| "flag_pic" |
| "orhi %0, r0, gotoffhi16(%1)" |
| [(set_attr "type" "load")] |
| ) |
| |
| (define_insn "movsi_gotoff_lo16" |
| [(set (match_operand:SI 0 "register_operand" "=r") |
| (unspec:SI [(plus:SI (match_operand:SI 1 "register_operand" "0") |
| (match_operand 2 "" ""))] UNSPEC_GOTOFF_LO16))] |
| "flag_pic" |
| "addi %0, %1, gotofflo16(%2)" |
| [(set_attr "type" "arith")] |
| ) |
| |
| (define_insn "*movsi_lo_sum" |
| [(set (match_operand:SI 0 "register_operand" "=r") |
| (lo_sum:SI (match_operand:SI 1 "register_operand" "0") |
| (match_operand:SI 2 "reloc_operand" "i")))] |
| "!flag_pic" |
| "ori %0, %0, lo(%2)" |
| [(set_attr "type" "arith")] |
| ) |
| |
| (define_insn "*movqi_insn" |
| [(set (match_operand:QI 0 "nonimmediate_operand" "=r,r,m,m,r") |
| (match_operand:QI 1 "general_operand" "m,r,r,J,n"))] |
| "lm32_move_ok (QImode, operands)" |
| "@ |
| lbu %0, %1 |
| or %0, %1, r0 |
| sb %0, %1 |
| sb %0, r0 |
| addi %0, r0, %1" |
| [(set_attr "type" "load,arith,store,store,arith")] |
| ) |
| |
| (define_insn "*movhi_insn" |
| [(set (match_operand:HI 0 "nonimmediate_operand" "=r,r,m,m,r,r") |
| (match_operand:HI 1 "general_operand" "m,r,r,J,K,L"))] |
| "lm32_move_ok (HImode, operands)" |
| "@ |
| lhu %0, %1 |
| or %0, %1, r0 |
| sh %0, %1 |
| sh %0, r0 |
| addi %0, r0, %1 |
| ori %0, r0, %1" |
| [(set_attr "type" "load,arith,store,store,arith,arith")] |
| ) |
| |
| (define_insn "movsi_insn" |
| [(set (match_operand:SI 0 "nonimmediate_operand" "=r,r,m,m,r,r,r,r,r,r") |
| (match_operand:SI 1 "general_operand" "m,r,r,J,K,L,U,S,Y,n"))] |
| "lm32_move_ok (SImode, operands)" |
| "@ |
| lw %0, %1 |
| or %0, %1, r0 |
| sw %0, %1 |
| sw %0, r0 |
| addi %0, r0, %1 |
| ori %0, r0, %1 |
| orhi %0, r0, hi(%1) |
| mva %0, gp(%1) |
| orhi %0, r0, hi(%1) |
| ori %0, r0, lo(%1); orhi %0, %0, hi(%1)" |
| [(set_attr "type" "load,arith,store,store,arith,arith,arith,arith,arith,arith")] |
| ) |
| |
| ;; --------------------------------- |
| ;; sign and zero extension |
| ;; --------------------------------- |
| |
| (define_insn "*extendqihi2" |
| [(set (match_operand:HI 0 "register_operand" "=r,r") |
| (sign_extend:HI (match_operand:QI 1 "nonimmediate_operand" "m,r")))] |
| "TARGET_SIGN_EXTEND_ENABLED || (GET_CODE (operands[1]) != REG)" |
| "@ |
| lb %0, %1 |
| sextb %0, %1" |
| [(set_attr "type" "load,arith")] |
| ) |
| |
| (define_insn "zero_extendqihi2" |
| [(set (match_operand:HI 0 "register_operand" "=r,r") |
| (zero_extend:HI (match_operand:QI 1 "nonimmediate_operand" "m,r")))] |
| "" |
| "@ |
| lbu %0, %1 |
| andi %0, %1, 0xff" |
| [(set_attr "type" "load,arith")] |
| ) |
| |
| (define_insn "*extendqisi2" |
| [(set (match_operand:SI 0 "register_operand" "=r,r") |
| (sign_extend:SI (match_operand:QI 1 "nonimmediate_operand" "m,r")))] |
| "TARGET_SIGN_EXTEND_ENABLED || (GET_CODE (operands[1]) != REG)" |
| "@ |
| lb %0, %1 |
| sextb %0, %1" |
| [(set_attr "type" "load,arith")] |
| ) |
| |
| (define_insn "zero_extendqisi2" |
| [(set (match_operand:SI 0 "register_operand" "=r,r") |
| (zero_extend:SI (match_operand:QI 1 "nonimmediate_operand" "m,r")))] |
| "" |
| "@ |
| lbu %0, %1 |
| andi %0, %1, 0xff" |
| [(set_attr "type" "load,arith")] |
| ) |
| |
| (define_insn "*extendhisi2" |
| [(set (match_operand:SI 0 "register_operand" "=r,r") |
| (sign_extend:SI (match_operand:HI 1 "nonimmediate_operand" "m,r")))] |
| "TARGET_SIGN_EXTEND_ENABLED || (GET_CODE (operands[1]) != REG)" |
| "@ |
| lh %0, %1 |
| sexth %0, %1" |
| [(set_attr "type" "load,arith")] |
| ) |
| |
| (define_insn "zero_extendhisi2" |
| [(set (match_operand:SI 0 "register_operand" "=r,r") |
| (zero_extend:SI (match_operand:HI 1 "nonimmediate_operand" "m,r")))] |
| "" |
| "@ |
| lhu %0, %1 |
| andi %0, %1, 0xffff" |
| [(set_attr "type" "load,arith")] |
| ) |
| |
| ;; --------------------------------- |
| ;; compare |
| ;; --------------------------------- |
| |
| (define_expand "cstoresi4" |
| [(set (match_operand:SI 0 "register_operand") |
| (match_operator:SI 1 "ordered_comparison_operator" |
| [(match_operand:SI 2 "register_operand") |
| (match_operand:SI 3 "register_or_int_operand")]))] |
| "" |
| { |
| lm32_expand_scc (operands); |
| DONE; |
| }) |
| |
| (define_insn "*seq" |
| [(set (match_operand:SI 0 "register_operand" "=r,r") |
| (eq:SI (match_operand:SI 1 "register_or_zero_operand" "%rJ,rJ") |
| (match_operand:SI 2 "register_or_K_operand" "r,K")))] |
| "" |
| "@ |
| cmpe %0, %z1, %2 |
| cmpei %0, %z1, %2" |
| [(set_attr "type" "compare")] |
| ) |
| |
| (define_insn "*sne" |
| [(set (match_operand:SI 0 "register_operand" "=r,r") |
| (ne:SI (match_operand:SI 1 "register_or_zero_operand" "%rJ,rJ") |
| (match_operand:SI 2 "register_or_K_operand" "r,K")))] |
| "" |
| "@ |
| cmpne %0, %z1, %2 |
| cmpnei %0, %z1, %2" |
| [(set_attr "type" "compare")] |
| ) |
| |
| (define_insn "*sgt" |
| [(set (match_operand:SI 0 "register_operand" "=r,r") |
| (gt:SI (match_operand:SI 1 "register_or_zero_operand" "rJ,rJ") |
| (match_operand:SI 2 "register_or_K_operand" "r,K")))] |
| "" |
| "@ |
| cmpg %0, %z1, %2 |
| cmpgi %0, %z1, %2" |
| [(set_attr "type" "compare")] |
| ) |
| |
| (define_insn "*sge" |
| [(set (match_operand:SI 0 "register_operand" "=r,r") |
| (ge:SI (match_operand:SI 1 "register_or_zero_operand" "rJ,rJ") |
| (match_operand:SI 2 "register_or_K_operand" "r,K")))] |
| "" |
| "@ |
| cmpge %0, %z1, %2 |
| cmpgei %0, %z1, %2" |
| [(set_attr "type" "compare")] |
| ) |
| |
| (define_insn "*sgtu" |
| [(set (match_operand:SI 0 "register_operand" "=r,r") |
| (gtu:SI (match_operand:SI 1 "register_or_zero_operand" "rJ,rJ") |
| (match_operand:SI 2 "register_or_L_operand" "r,L")))] |
| "" |
| "@ |
| cmpgu %0, %z1, %2 |
| cmpgui %0, %z1, %2" |
| [(set_attr "type" "compare")] |
| ) |
| |
| (define_insn "*sgeu" |
| [(set (match_operand:SI 0 "register_operand" "=r,r") |
| (geu:SI (match_operand:SI 1 "register_or_zero_operand" "rJ,rJ") |
| (match_operand:SI 2 "register_or_L_operand" "r,L")))] |
| "" |
| "@ |
| cmpgeu %0, %z1, %2 |
| cmpgeui %0, %z1, %2" |
| [(set_attr "type" "compare")] |
| ) |
| |
| ;; --------------------------------- |
| ;; unconditional branch |
| ;; --------------------------------- |
| |
| (define_insn "jump" |
| [(set (pc) (label_ref (match_operand 0 "" "")))] |
| "" |
| "bi %0" |
| [(set_attr "type" "ubranch")] |
| ) |
| |
| (define_insn "indirect_jump" |
| [(set (pc) (match_operand:SI 0 "register_operand" "r"))] |
| "" |
| "b %0" |
| [(set_attr "type" "uibranch")] |
| ) |
| |
| ;; --------------------------------- |
| ;; conditional branch |
| ;; --------------------------------- |
| |
| (define_expand "cbranchsi4" |
| [(set (pc) |
| (if_then_else (match_operator 0 "comparison_operator" |
| [(match_operand:SI 1 "register_operand") |
| (match_operand:SI 2 "nonmemory_operand")]) |
| (label_ref (match_operand 3 "" "")) |
| (pc)))] |
| "" |
| " |
| { |
| lm32_expand_conditional_branch (operands); |
| DONE; |
| }") |
| |
| (define_insn "*beq" |
| [(set (pc) |
| (if_then_else (eq:SI (match_operand:SI 0 "register_or_zero_operand" "rJ") |
| (match_operand:SI 1 "register_or_zero_operand" "rJ")) |
| (label_ref (match_operand 2 "" "")) |
| (pc)))] |
| "" |
| { |
| return get_attr_length (insn) == 4 |
| ? "be %z0,%z1,%2" |
| : "bne %z0,%z1,8\n\tbi %2"; |
| } |
| [(set_attr "type" "cbranch")]) |
| |
| (define_insn "*bne" |
| [(set (pc) |
| (if_then_else (ne:SI (match_operand:SI 0 "register_or_zero_operand" "rJ") |
| (match_operand:SI 1 "register_or_zero_operand" "rJ")) |
| (label_ref (match_operand 2 "" "")) |
| (pc)))] |
| "" |
| { |
| return get_attr_length (insn) == 4 |
| ? "bne %z0,%z1,%2" |
| : "be %z0,%z1,8\n\tbi %2"; |
| } |
| [(set_attr "type" "cbranch")]) |
| |
| (define_insn "*bgt" |
| [(set (pc) |
| (if_then_else (gt:SI (match_operand:SI 0 "register_or_zero_operand" "rJ") |
| (match_operand:SI 1 "register_or_zero_operand" "rJ")) |
| (label_ref (match_operand 2 "" "")) |
| (pc)))] |
| "" |
| { |
| return get_attr_length (insn) == 4 |
| ? "bg %z0,%z1,%2" |
| : "bge %z1,%z0,8\n\tbi %2"; |
| } |
| [(set_attr "type" "cbranch")]) |
| |
| (define_insn "*bge" |
| [(set (pc) |
| (if_then_else (ge:SI (match_operand:SI 0 "register_or_zero_operand" "rJ") |
| (match_operand:SI 1 "register_or_zero_operand" "rJ")) |
| (label_ref (match_operand 2 "" "")) |
| (pc)))] |
| "" |
| { |
| return get_attr_length (insn) == 4 |
| ? "bge %z0,%z1,%2" |
| : "bg %z1,%z0,8\n\tbi %2"; |
| } |
| [(set_attr "type" "cbranch")]) |
| |
| (define_insn "*bgtu" |
| [(set (pc) |
| (if_then_else (gtu:SI (match_operand:SI 0 "register_or_zero_operand" "rJ") |
| (match_operand:SI 1 "register_or_zero_operand" "rJ")) |
| (label_ref (match_operand 2 "" "")) |
| (pc)))] |
| "" |
| { |
| return get_attr_length (insn) == 4 |
| ? "bgu %z0,%z1,%2" |
| : "bgeu %z1,%z0,8\n\tbi %2"; |
| } |
| [(set_attr "type" "cbranch")]) |
| |
| (define_insn "*bgeu" |
| [(set (pc) |
| (if_then_else (geu:SI (match_operand:SI 0 "register_or_zero_operand" "rJ") |
| (match_operand:SI 1 "register_or_zero_operand" "rJ")) |
| (label_ref (match_operand 2 "" "")) |
| (pc)))] |
| "" |
| { |
| return get_attr_length (insn) == 4 |
| ? "bgeu %z0,%z1,%2" |
| : "bgu %z1,%z0,8\n\tbi %2"; |
| } |
| [(set_attr "type" "cbranch")]) |
| |
| ;; --------------------------------- |
| ;; call |
| ;; --------------------------------- |
| |
| (define_expand "call" |
| [(parallel [(call (match_operand 0 "" "") |
| (match_operand 1 "" "")) |
| (clobber (reg:SI RA_REGNUM)) |
| ])] |
| "" |
| " |
| { |
| rtx addr = XEXP (operands[0], 0); |
| if (!CONSTANT_ADDRESS_P (addr)) |
| XEXP (operands[0], 0) = force_reg (Pmode, addr); |
| }") |
| |
| (define_insn "*call" |
| [(call (mem:SI (match_operand:SI 0 "call_operand" "r,s")) |
| (match_operand 1 "" "")) |
| (clobber (reg:SI RA_REGNUM))] |
| "" |
| "@ |
| call %0 |
| calli %0" |
| [(set_attr "type" "call,icall")] |
| ) |
| |
| (define_expand "call_value" |
| [(parallel [(set (match_operand 0 "" "") |
| (call (match_operand 1 "" "") |
| (match_operand 2 "" ""))) |
| (clobber (reg:SI RA_REGNUM)) |
| ])] |
| "" |
| " |
| { |
| rtx addr = XEXP (operands[1], 0); |
| if (!CONSTANT_ADDRESS_P (addr)) |
| XEXP (operands[1], 0) = force_reg (Pmode, addr); |
| }") |
| |
| (define_insn "*call_value" |
| [(set (match_operand 0 "register_operand" "=r,r") |
| (call (mem:SI (match_operand:SI 1 "call_operand" "r,s")) |
| (match_operand 2 "" ""))) |
| (clobber (reg:SI RA_REGNUM))] |
| "" |
| "@ |
| call %1 |
| calli %1" |
| [(set_attr "type" "call,icall")] |
| ) |
| |
| (define_insn "return_internal" |
| [(use (match_operand:SI 0 "register_operand" "r")) |
| (return)] |
| "" |
| "b %0" |
| [(set_attr "type" "uibranch")] |
| ) |
| |
| (define_expand "return" |
| [(return)] |
| "lm32_can_use_return ()" |
| "" |
| ) |
| |
| (define_expand "simple_return" |
| [(simple_return)] |
| "" |
| "" |
| ) |
| |
| (define_insn "*return" |
| [(return)] |
| "reload_completed" |
| "ret" |
| [(set_attr "type" "uibranch")] |
| ) |
| |
| (define_insn "*simple_return" |
| [(simple_return)] |
| "" |
| "ret" |
| [(set_attr "type" "uibranch")] |
| ) |
| |
| ;; --------------------------------- |
| ;; switch/case statements |
| ;; --------------------------------- |
| |
| (define_expand "tablejump" |
| [(set (pc) (match_operand 0 "register_operand" "")) |
| (use (label_ref (match_operand 1 "" "")))] |
| "" |
| " |
| { |
| rtx target = operands[0]; |
| if (flag_pic) |
| { |
| /* For PIC, the table entry is relative to the start of the table. */ |
| rtx label = gen_reg_rtx (SImode); |
| target = gen_reg_rtx (SImode); |
| emit_move_insn (label, gen_rtx_LABEL_REF (SImode, operands[1])); |
| emit_insn (gen_addsi3 (target, operands[0], label)); |
| } |
| emit_jump_insn (gen_tablejumpsi (target, operands[1])); |
| DONE; |
| }") |
| |
| (define_insn "tablejumpsi" |
| [(set (pc) (match_operand:SI 0 "register_operand" "r")) |
| (use (label_ref (match_operand 1 "" "")))] |
| "" |
| "b %0" |
| [(set_attr "type" "ubranch")] |
| ) |
| |
| ;; --------------------------------- |
| ;; arithmetic |
| ;; --------------------------------- |
| |
| (define_insn "addsi3" |
| [(set (match_operand:SI 0 "register_operand" "=r,r") |
| (plus:SI (match_operand:SI 1 "register_or_zero_operand" "%rJ,rJ") |
| (match_operand:SI 2 "register_or_K_operand" "r,K")))] |
| "" |
| "@ |
| add %0, %z1, %2 |
| addi %0, %z1, %2" |
| [(set_attr "type" "arith")] |
| ) |
| |
| (define_insn "subsi3" |
| [(set (match_operand:SI 0 "register_operand" "=r") |
| (minus:SI (match_operand:SI 1 "register_or_zero_operand" "rJ") |
| (match_operand:SI 2 "register_or_zero_operand" "rJ")))] |
| "" |
| "sub %0, %z1, %z2" |
| [(set_attr "type" "arith")] |
| ) |
| |
| (define_insn "mulsi3" |
| [(set (match_operand:SI 0 "register_operand" "=r,r") |
| (mult:SI (match_operand:SI 1 "register_or_zero_operand" "%rJ,rJ") |
| (match_operand:SI 2 "register_or_K_operand" "r,K")))] |
| "TARGET_MULTIPLY_ENABLED" |
| "@ |
| mul %0, %z1, %2 |
| muli %0, %z1, %2" |
| [(set_attr "type" "multiply")] |
| ) |
| |
| (define_insn "udivsi3" |
| [(set (match_operand:SI 0 "register_operand" "=r") |
| (udiv:SI (match_operand:SI 1 "register_or_zero_operand" "rJ") |
| (match_operand:SI 2 "register_operand" "r")))] |
| "TARGET_DIVIDE_ENABLED" |
| "divu %0, %z1, %2" |
| [(set_attr "type" "divide")] |
| ) |
| |
| (define_insn "umodsi3" |
| [(set (match_operand:SI 0 "register_operand" "=r") |
| (umod:SI (match_operand:SI 1 "register_or_zero_operand" "rJ") |
| (match_operand:SI 2 "register_operand" "r")))] |
| "TARGET_DIVIDE_ENABLED" |
| "modu %0, %z1, %2" |
| [(set_attr "type" "divide")] |
| ) |
| |
| ;; --------------------------------- |
| ;; negation and inversion |
| ;; --------------------------------- |
| |
| (define_insn "negsi2" |
| [(set (match_operand:SI 0 "register_operand" "=r") |
| (neg:SI (match_operand:SI 1 "register_or_zero_operand" "rJ")))] |
| "" |
| "sub %0, r0, %z1" |
| [(set_attr "type" "arith")] |
| ) |
| |
| (define_insn "one_cmplsi2" |
| [(set (match_operand:SI 0 "register_operand" "=r") |
| (not:SI (match_operand:SI 1 "register_or_zero_operand" "rJ")))] |
| "" |
| "not %0, %z1" |
| [(set_attr "type" "arith")] |
| ) |
| |
| ;; --------------------------------- |
| ;; logical |
| ;; --------------------------------- |
| |
| (define_insn "andsi3" |
| [(set (match_operand:SI 0 "register_operand" "=r,r") |
| (and:SI (match_operand:SI 1 "register_or_zero_operand" "%rJ,rJ") |
| (match_operand:SI 2 "register_or_L_operand" "r,L")))] |
| "" |
| "@ |
| and %0, %z1, %2 |
| andi %0, %z1, %2" |
| [(set_attr "type" "arith")] |
| ) |
| |
| (define_insn "iorsi3" |
| [(set (match_operand:SI 0 "register_operand" "=r,r") |
| (ior:SI (match_operand:SI 1 "register_or_zero_operand" "%rJ,rJ") |
| (match_operand:SI 2 "register_or_L_operand" "r,L")))] |
| "" |
| "@ |
| or %0, %z1, %2 |
| ori %0, %z1, %2" |
| [(set_attr "type" "arith")] |
| ) |
| |
| (define_insn "xorsi3" |
| [(set (match_operand:SI 0 "register_operand" "=r,r") |
| (xor:SI (match_operand:SI 1 "register_or_zero_operand" "%rJ,rJ") |
| (match_operand:SI 2 "register_or_L_operand" "r,L")))] |
| "" |
| "@ |
| xor %0, %z1, %2 |
| xori %0, %z1, %2" |
| [(set_attr "type" "arith")] |
| ) |
| |
| (define_insn "*norsi3" |
| [(set (match_operand:SI 0 "register_operand" "=r,r") |
| (not:SI (ior:SI (match_operand:SI 1 "register_or_zero_operand" "%rJ,rJ") |
| (match_operand:SI 2 "register_or_L_operand" "r,L"))))] |
| "" |
| "@ |
| nor %0, %z1, %2 |
| nori %0, %z1, %2" |
| [(set_attr "type" "arith")] |
| ) |
| |
| (define_insn "*xnorsi3" |
| [(set (match_operand:SI 0 "register_operand" "=r,r") |
| (not:SI (xor:SI (match_operand:SI 1 "register_or_zero_operand" "%rJ,rJ") |
| (match_operand:SI 2 "register_or_L_operand" "r,L"))))] |
| "" |
| "@ |
| xnor %0, %z1, %2 |
| xnori %0, %z1, %2" |
| [(set_attr "type" "arith")] |
| ) |
| |
| ;; --------------------------------- |
| ;; shifts |
| ;; --------------------------------- |
| |
| (define_expand "ashlsi3" |
| [(set (match_operand:SI 0 "register_operand" "") |
| (ashift:SI (match_operand:SI 1 "register_or_zero_operand" "") |
| (match_operand:SI 2 "register_or_L_operand" "")))] |
| "" |
| { |
| if (!TARGET_BARREL_SHIFT_ENABLED) |
| { |
| if (!optimize_size |
| && satisfies_constraint_L (operands[2]) |
| && INTVAL (operands[2]) <= 8) |
| { |
| int i; |
| int shifts = INTVAL (operands[2]); |
| |
| if (shifts == 0) |
| emit_move_insn (operands[0], operands[1]); |
| else |
| emit_insn (gen_addsi3 (operands[0], operands[1], operands[1])); |
| for (i = 1; i < shifts; i++) |
| emit_insn (gen_addsi3 (operands[0], operands[0], operands[0])); |
| DONE; |
| } |
| else |
| FAIL; |
| } |
| }) |
| |
| (define_insn "*ashlsi3" |
| [(set (match_operand:SI 0 "register_operand" "=r,r") |
| (ashift:SI (match_operand:SI 1 "register_or_zero_operand" "rJ,rJ") |
| (match_operand:SI 2 "register_or_L_operand" "r,L")))] |
| "TARGET_BARREL_SHIFT_ENABLED" |
| "@ |
| sl %0, %z1, %2 |
| sli %0, %z1, %2" |
| [(set_attr "type" "shift")] |
| ) |
| |
| (define_expand "ashrsi3" |
| [(set (match_operand:SI 0 "register_operand" "") |
| (ashiftrt:SI (match_operand:SI 1 "register_or_zero_operand" "") |
| (match_operand:SI 2 "register_or_L_operand" "")))] |
| "" |
| { |
| if (!TARGET_BARREL_SHIFT_ENABLED) |
| { |
| if (!optimize_size |
| && satisfies_constraint_L (operands[2]) |
| && INTVAL (operands[2]) <= 8) |
| { |
| int i; |
| int shifts = INTVAL (operands[2]); |
| rtx one = GEN_INT (1); |
| |
| if (shifts == 0) |
| emit_move_insn (operands[0], operands[1]); |
| else |
| emit_insn (gen_ashrsi3_1bit (operands[0], operands[1], one)); |
| for (i = 1; i < shifts; i++) |
| emit_insn (gen_ashrsi3_1bit (operands[0], operands[0], one)); |
| DONE; |
| } |
| else |
| FAIL; |
| } |
| }) |
| |
| (define_insn "*ashrsi3" |
| [(set (match_operand:SI 0 "register_operand" "=r,r") |
| (ashiftrt:SI (match_operand:SI 1 "register_or_zero_operand" "rJ,rJ") |
| (match_operand:SI 2 "register_or_L_operand" "r,L")))] |
| "TARGET_BARREL_SHIFT_ENABLED" |
| "@ |
| sr %0, %z1, %2 |
| sri %0, %z1, %2" |
| [(set_attr "type" "shift")] |
| ) |
| |
| (define_insn "ashrsi3_1bit" |
| [(set (match_operand:SI 0 "register_operand" "=r") |
| (ashiftrt:SI (match_operand:SI 1 "register_or_zero_operand" "rJ") |
| (match_operand:SI 2 "constant_M_operand" "M")))] |
| "!TARGET_BARREL_SHIFT_ENABLED" |
| "sri %0, %z1, %2" |
| [(set_attr "type" "shift")] |
| ) |
| |
| (define_expand "lshrsi3" |
| [(set (match_operand:SI 0 "register_operand" "") |
| (lshiftrt:SI (match_operand:SI 1 "register_or_zero_operand" "") |
| (match_operand:SI 2 "register_or_L_operand" "")))] |
| "" |
| { |
| if (!TARGET_BARREL_SHIFT_ENABLED) |
| { |
| if (!optimize_size |
| && satisfies_constraint_L (operands[2]) |
| && INTVAL (operands[2]) <= 8) |
| { |
| int i; |
| int shifts = INTVAL (operands[2]); |
| rtx one = GEN_INT (1); |
| |
| if (shifts == 0) |
| emit_move_insn (operands[0], operands[1]); |
| else |
| emit_insn (gen_lshrsi3_1bit (operands[0], operands[1], one)); |
| for (i = 1; i < shifts; i++) |
| emit_insn (gen_lshrsi3_1bit (operands[0], operands[0], one)); |
| DONE; |
| } |
| else |
| FAIL; |
| } |
| }) |
| |
| (define_insn "*lshrsi3" |
| [(set (match_operand:SI 0 "register_operand" "=r,r") |
| (lshiftrt:SI (match_operand:SI 1 "register_or_zero_operand" "rJ,rJ") |
| (match_operand:SI 2 "register_or_L_operand" "r,L")))] |
| "TARGET_BARREL_SHIFT_ENABLED" |
| "@ |
| sru %0, %z1, %2 |
| srui %0, %z1, %2" |
| [(set_attr "type" "shift")] |
| ) |
| |
| (define_insn "lshrsi3_1bit" |
| [(set (match_operand:SI 0 "register_operand" "=r") |
| (lshiftrt:SI (match_operand:SI 1 "register_or_zero_operand" "rJ") |
| (match_operand:SI 2 "constant_M_operand" "M")))] |
| "!TARGET_BARREL_SHIFT_ENABLED" |
| "srui %0, %z1, %2" |
| [(set_attr "type" "shift")] |
| ) |
| |
| ;; --------------------------------- |
| ;; function entry / exit |
| ;; --------------------------------- |
| |
| (define_expand "prologue" |
| [(const_int 1)] |
| "" |
| " |
| { |
| lm32_expand_prologue (); |
| DONE; |
| }") |
| |
| (define_expand "epilogue" |
| [(return)] |
| "" |
| " |
| { |
| lm32_expand_epilogue (); |
| DONE; |
| }") |
| |
| ;; --------------------------------- |
| ;; nop |
| ;; --------------------------------- |
| |
| (define_insn "nop" |
| [(const_int 0)] |
| "" |
| "nop" |
| [(set_attr "type" "arith")] |
| ) |
| |
| ;; --------------------------------- |
| ;; blockage |
| ;; --------------------------------- |
| |
| ;; used to stop the scheduler from |
| ;; scheduling code across certain boundaries |
| |
| (define_insn "blockage" |
| [(unspec_volatile [(const_int 0)] UNSPECV_BLOCKAGE)] |
| "" |
| "" |
| [(set_attr "length" "0")] |
| ) |