📄 fr30.md
字号:
;; Now, the actual comparisons, generated by the branch and/or scc operations(define_insn "*cmpsi_internal" [(set (reg:CC 16) (compare:CC (match_operand:SI 0 "register_operand" "r,r,r") (match_operand:SI 1 "nonmemory_operand" "r,I,J")))] "" "@ cmp %1, %0 cmp %1, %0 cmp2 %1, %0");;}}} ;;{{{ Branches ;; Define_expands called by the machine independent part of the compiler;; to allocate a new comparison register(define_expand "beq" [(set (reg:CC 16) (compare:CC (match_dup 1) (match_dup 2))) (set (pc) (if_then_else (eq:CC (reg:CC 16) (const_int 0)) (label_ref (match_operand 0 "" "")) (pc)))] "" "{ operands[1] = fr30_compare_op0; operands[2] = fr30_compare_op1; }")(define_expand "bne" [(set (reg:CC 16) (compare:CC (match_dup 1) (match_dup 2))) (set (pc) (if_then_else (ne:CC (reg:CC 16) (const_int 0)) (label_ref (match_operand 0 "" "")) (pc)))] "" "{ operands[1] = fr30_compare_op0; operands[2] = fr30_compare_op1; }")(define_expand "blt" [(set (reg:CC 16) (compare:CC (match_dup 1) (match_dup 2))) (set (pc) (if_then_else (lt:CC (reg:CC 16) (const_int 0)) (label_ref (match_operand 0 "" "")) (pc)))] "" "{ operands[1] = fr30_compare_op0; operands[2] = fr30_compare_op1; }")(define_expand "ble" [(set (reg:CC 16) (compare:CC (match_dup 1) (match_dup 2))) (set (pc) (if_then_else (le:CC (reg:CC 16) (const_int 0)) (label_ref (match_operand 0 "" "")) (pc)))] "" "{ operands[1] = fr30_compare_op0; operands[2] = fr30_compare_op1; }")(define_expand "bgt" [(set (reg:CC 16) (compare:CC (match_dup 1) (match_dup 2))) (set (pc) (if_then_else (gt:CC (reg:CC 16) (const_int 0)) (label_ref (match_operand 0 "" "")) (pc)))] "" "{ operands[1] = fr30_compare_op0; operands[2] = fr30_compare_op1; }")(define_expand "bge" [(set (reg:CC 16) (compare:CC (match_dup 1) (match_dup 2))) (set (pc) (if_then_else (ge:CC (reg:CC 16) (const_int 0)) (label_ref (match_operand 0 "" "")) (pc)))] "" "{ operands[1] = fr30_compare_op0; operands[2] = fr30_compare_op1; }")(define_expand "bltu" [(set (reg:CC 16) (compare:CC (match_dup 1) (match_dup 2))) (set (pc) (if_then_else (ltu:CC (reg:CC 16) (const_int 0)) (label_ref (match_operand 0 "" "")) (pc)))] "" "{ operands[1] = fr30_compare_op0; operands[2] = fr30_compare_op1; }")(define_expand "bleu" [(set (reg:CC 16) (compare:CC (match_dup 1) (match_dup 2))) (set (pc) (if_then_else (leu:CC (reg:CC 16) (const_int 0)) (label_ref (match_operand 0 "" "")) (pc)))] "" "{ operands[1] = fr30_compare_op0; operands[2] = fr30_compare_op1; }")(define_expand "bgtu" [(set (reg:CC 16) (compare:CC (match_dup 1) (match_dup 2))) (set (pc) (if_then_else (gtu:CC (reg:CC 16) (const_int 0)) (label_ref (match_operand 0 "" "")) (pc)))] "" "{ operands[1] = fr30_compare_op0; operands[2] = fr30_compare_op1; }")(define_expand "bgeu" [(set (reg:CC 16) (compare:CC (match_dup 1) (match_dup 2))) (set (pc) (if_then_else (geu:CC (reg:CC 16) (const_int 0)) (label_ref (match_operand 0 "" "")) (pc)))] "" "{ operands[1] = fr30_compare_op0; operands[2] = fr30_compare_op1; }");; Actual branches. We must allow for the (label_ref) and the (pc) to be;; swapped. If they are swapped, it reverses the sense of the branch.;; This pattern matches the (branch-if-true) branches generated above.;; It generates two different instruction sequences depending upon how;; far away the destination is.;; The calculation for the instruction length is derived as follows:;; The branch instruction has a 9 bit signed displacement so we have;; this inequality for the displacement:;;;; -256 <= pc < 256;; or;; -256 + 256 <= pc + 256 < 256 + 256;; ie;; 0 <= pc + 256 < 512 ;;;; if we consider the displacement as an unsigned value, then negative;; displacements become very large positive displacements, and the;; inequality becomes:;;;; pc + 256 < 512;;;; In order to allow for the fact that the real branch instruction works;; from pc + 2, we increase the offset to 258.;;;; Note - we do not have to worry about whether the branch is delayed or;; not, as branch shortening happens after delay slot reorganisation.(define_insn "*branch_true" [(set (pc) (if_then_else (match_operator:CC 0 "comparison_operator" [(reg:CC 16) (const_int 0)]) (label_ref (match_operand 1 "" "")) (pc)))] "" "* { if (get_attr_length (insn) == 2) return \"b%b0%#\\t%l1\"; else { static char buffer [100]; const char * tmp_reg; const char * ldi_insn; tmp_reg = reg_names [COMPILER_SCRATCH_REGISTER]; ldi_insn = TARGET_SMALL_MODEL ? \"ldi:20\" : \"ldi:32\"; /* The code produced here is, for say the EQ case: Bne 1f LDI <label>, r0 JMP r0 1: */ sprintf (buffer, \"b%%B0\\t1f\\t;\\n\\t%s\\t%%l1, %s\\t;\\n\\tjmp%%#\\t@%s\\t;\\n1:\", ldi_insn, tmp_reg, tmp_reg); return buffer; } }" [(set (attr "length") (if_then_else (ltu (plus (minus (match_dup 1) (pc)) (const_int 254)) (const_int 506)) (const_int 2) (if_then_else (eq_attr "size" "small") (const_int 8) (const_int 10)))) (set_attr "delay_type" "delayed")]);; This pattern is a duplicate of the previous one, except that the;; branch occurs if the test is false, so the %B operator is used.(define_insn "*branch_false" [(set (pc) (if_then_else (match_operator:CC 0 "comparison_operator" [(reg:CC 16) (const_int 0)]) (pc) (label_ref (match_operand 1 "" ""))))] "" "* { if (get_attr_length (insn) == 2) return \"b%B0%#\\t%l1 \"; else { static char buffer [100]; const char * tmp_reg; const char * ldi_insn; tmp_reg = reg_names [COMPILER_SCRATCH_REGISTER]; ldi_insn = TARGET_SMALL_MODEL ? \"ldi:20\" : \"ldi:32\"; sprintf (buffer, \"b%%b0\\t1f\\t;\\n\\t%s\\t%%l1, %s\\t;\\n\\tjmp%%#\\t@%s\\t;\\n1:\", ldi_insn, tmp_reg, tmp_reg); return buffer; } }" [(set (attr "length") (if_then_else (ltu (plus (minus (match_dup 1) (pc)) (const_int 254)) (const_int 506)) (const_int 2) (if_then_else (eq_attr "size" "small") (const_int 8) (const_int 10)))) (set_attr "delay_type" "delayed")]);;}}} ;;{{{ Calls & Jumps ;; Subroutine call instruction returning no value. Operand 0 is the function;; to call; operand 1 is the number of bytes of arguments pushed (in mode;; `SImode', except it is normally a `const_int'); operand 2 is the number of;; registers used as operands.(define_insn "call" [(call (match_operand 0 "call_operand" "Qm") (match_operand 1 "" "g")) (clobber (reg:SI 17))] "" "call%#\\t%0" [(set_attr "delay_type" "delayed")]);; Subroutine call instruction returning a value. Operand 0 is the hard;; register in which the value is returned. There are three more operands, the;; same as the three operands of the `call' instruction (but with numbers;; increased by one).;; Subroutines that return `BLKmode' objects use the `call' insn.(define_insn "call_value" [(set (match_operand 0 "register_operand" "=r") (call (match_operand 1 "call_operand" "Qm") (match_operand 2 "" "g"))) (clobber (reg:SI 17))] "" "call%#\\t%1" [(set_attr "delay_type" "delayed")]);; Normal unconditional jump.;; For a description of the computation of the length ;; attribute see the branch patterns above.;;;; Although this instruction really clobbers r0, flow;; relies on jump being simplejump_p in several places;; and as r0 is fixed, this doesn't change anything(define_insn "jump" [(set (pc) (label_ref (match_operand 0 "" "")))] "" "* { if (get_attr_length (insn) == 2) return \"bra%#\\t%0\"; else { static char buffer [100]; const char * tmp_reg; const char * ldi_insn; tmp_reg = reg_names [COMPILER_SCRATCH_REGISTER]; ldi_insn = TARGET_SMALL_MODEL ? \"ldi:20\" : \"ldi:32\"; sprintf (buffer, \"%s\\t%%0, %s\\t;\\n\\tjmp%%#\\t@%s\\t;\", ldi_insn, tmp_reg, tmp_reg); return buffer; } }" [(set (attr "length") (if_then_else (ltu (plus (minus (match_dup 0) (pc)) (const_int 254)) (const_int 506)) (const_int 2) (if_then_else (eq_attr "size" "small") (const_int 6) (const_int 8)))) (set_attr "delay_type" "delayed")]);; Indirect jump through a register(define_insn "indirect_jump" [(set (pc) (match_operand:SI 0 "nonimmediate_operand" "r"))] "GET_CODE (operands[0]) != MEM || GET_CODE (XEXP (operands[0], 0)) != PLUS" "jmp%#\\t@%0" [(set_attr "delay_type" "delayed")])(define_insn "tablejump" [(set (pc) (match_operand:SI 0 "register_operand" "r")) (use (label_ref (match_operand 1 "" "")))] "" "jmp%#\\t@%0" [(set_attr "delay_type" "delayed")]);;}}} ;;{{{ Function Prologues and Epilogues ;; Called after register allocation to add any instructions needed for the;; prologue. Using a prologue insn is favored compared to putting all of the;; instructions in output_function_prologue(), since it allows the scheduler;; to intermix instructions with the saves of the caller saved registers. In;; some cases, it might be necessary to emit a barrier instruction as the last;; insn to prevent such scheduling.(define_expand "prologue" [(clobber (const_int 0))] "" "{ fr30_expand_prologue (); DONE; }");; Called after register allocation to add any instructions needed for the;; epilogue. Using an epilogue insn is favored compared to putting all of the;; instructions in output_function_epilogue(), since it allows the scheduler;; to intermix instructions with the restores of the caller saved registers.;; In some cases, it might be necessary to emit a barrier instruction as the;; first insn to prevent such scheduling.(define_expand "epilogue" [(return)] "" "{ fr30_expand_epilogue (); DONE; }")(define_insn "return_from_func" [(return) (use (reg:SI 17))] "reload_completed" "ret%#" [(set_attr "delay_type" "delayed")])(define_insn "leave_func" [(set (reg:SI 15) (reg:SI 14)) (set (reg:SI 14) (mem:SI (post_inc:SI (reg:SI 15))))] "reload_completed" "leave")(define_insn "enter_func" [(set:SI (mem:SI (minus:SI (reg:SI 15) (const_int 4))) (reg:SI 14)) (set:SI (reg:SI 14) (minus:SI (reg:SI 15) (const_int 4))) (set:SI (reg:SI 15) (minus:SI (reg:SI 15) (match_operand 0 "immediate_operand" "i")))] "reload_completed" "enter #%0" [(set_attr "delay_type" "other")]);;}}} ;;{{{ Miscellaneous ;; No operation, needed in case the user uses -g but not -O.(define_insn "nop" [(const_int 0)] "" "nop");; Pseudo instruction that prevents the scheduler from moving code above this;; point.(define_insn "blockage" [(unspec_volatile [(const_int 0)] 0)] "" "" [(set_attr "length" "0")]);;}}} ;; Local Variables:;; mode: md;; folded-file: t;; End:
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -