📄 m32r.md
字号:
else { if (GET_CODE (operands[1]) == EQ) return \"bne %2,%3,1f\;bra %l0\;1:\"; else return \"beq %2,%3,1f\;bra %l0\;1:\"; }}" [(set_attr "type" "branch") ; We use 25000/50000 instead of 32768/65536 to account for slot filling ; which is complex to track and inaccurate length specs. (set (attr "length") (if_then_else (ltu (plus (minus (match_dup 0) (pc)) (const_int 25000)) (const_int 50000)) (const_int 4) (const_int 8)))])(define_insn "*rev_reg_branch_insn" [(set (pc) (if_then_else (match_operator 1 "eqne_comparison_operator" [(match_operand:SI 2 "register_operand" "r") (match_operand:SI 3 "register_operand" "r")]) (pc) (label_ref (match_operand 0 "" ""))))] "" "*{ /* Is branch target reachable with beq/bne? */ if (get_attr_length (insn) == 4) { if (GET_CODE (operands[1]) == NE) return \"beq %2,%3,%l0\"; else return \"bne %2,%3,%l0\"; } else { if (GET_CODE (operands[1]) == NE) return \"bne %2,%3,1f\;bra %l0\;1:\"; else return \"beq %2,%3,1f\;bra %l0\;1:\"; }}" [(set_attr "type" "branch") ; We use 25000/50000 instead of 32768/65536 to account for slot filling ; which is complex to track and inaccurate length specs. (set (attr "length") (if_then_else (ltu (plus (minus (match_dup 0) (pc)) (const_int 25000)) (const_int 50000)) (const_int 4) (const_int 8)))]); reg/zero compare and branch insns(define_insn "*zero_branch_insn" [(set (pc) (if_then_else (match_operator 1 "signed_comparison_operator" [(match_operand:SI 2 "register_operand" "r") (const_int 0)]) (label_ref (match_operand 0 "" "")) (pc)))] "" "*{ char *br,*invbr; char asmtext[40]; switch (GET_CODE (operands[1])) { case EQ : br = \"eq\"; invbr = \"ne\"; break; case NE : br = \"ne\"; invbr = \"eq\"; break; case LE : br = \"le\"; invbr = \"gt\"; break; case GT : br = \"gt\"; invbr = \"le\"; break; case LT : br = \"lt\"; invbr = \"ge\"; break; case GE : br = \"ge\"; invbr = \"lt\"; break; } /* Is branch target reachable with bxxz? */ if (get_attr_length (insn) == 4) { sprintf (asmtext, \"b%sz %%2,%%l0\", br); output_asm_insn (asmtext, operands); } else { sprintf (asmtext, \"b%sz %%2,1f\;bra %%l0\;1:\", invbr); output_asm_insn (asmtext, operands); } return \"\";}" [(set_attr "type" "branch") ; We use 25000/50000 instead of 32768/65536 to account for slot filling ; which is complex to track and inaccurate length specs. (set (attr "length") (if_then_else (ltu (plus (minus (match_dup 0) (pc)) (const_int 25000)) (const_int 50000)) (const_int 4) (const_int 8)))])(define_insn "*rev_zero_branch_insn" [(set (pc) (if_then_else (match_operator 1 "eqne_comparison_operator" [(match_operand:SI 2 "register_operand" "r") (const_int 0)]) (pc) (label_ref (match_operand 0 "" ""))))] "" "*{ char *br,*invbr; char asmtext[40]; switch (GET_CODE (operands[1])) { case EQ : br = \"eq\"; invbr = \"ne\"; break; case NE : br = \"ne\"; invbr = \"eq\"; break; case LE : br = \"le\"; invbr = \"gt\"; break; case GT : br = \"gt\"; invbr = \"le\"; break; case LT : br = \"lt\"; invbr = \"ge\"; break; case GE : br = \"ge\"; invbr = \"lt\"; break; } /* Is branch target reachable with bxxz? */ if (get_attr_length (insn) == 4) { sprintf (asmtext, \"b%sz %%2,%%l0\", invbr); output_asm_insn (asmtext, operands); } else { sprintf (asmtext, \"b%sz %%2,1f\;bra %%l0\;1:\", br); output_asm_insn (asmtext, operands); } return \"\";}" [(set_attr "type" "branch") ; We use 25000/50000 instead of 32768/65536 to account for slot filling ; which is complex to track and inaccurate length specs. (set (attr "length") (if_then_else (ltu (plus (minus (match_dup 0) (pc)) (const_int 25000)) (const_int 50000)) (const_int 4) (const_int 8)))]);; Unconditional and other jump instructions.(define_insn "jump" [(set (pc) (label_ref (match_operand 0 "" "")))] "" "bra %l0" [(set_attr "type" "uncond_branch") (set (attr "length") (if_then_else (ltu (plus (minus (match_dup 0) (pc)) (const_int 400)) (const_int 800)) (const_int 2) (const_int 4)))])(define_insn "indirect_jump" [(set (pc) (match_operand:SI 0 "address_operand" "p"))] "" "jmp %a0" [(set_attr "type" "uncond_branch") (set_attr "length" "2")]) (define_insn "tablejump" [(set (pc) (match_operand:SI 0 "address_operand" "p")) (use (label_ref (match_operand 1 "" "")))] "" "jmp %a0" [(set_attr "type" "uncond_branch") (set_attr "length" "2")])(define_expand "call" ;; operands[1] is stack_size_rtx ;; operands[2] is next_arg_register [(parallel [(call (match_operand:SI 0 "call_operand" "") (match_operand 1 "" "")) (clobber (reg:SI 14))])] "" "")(define_insn "*call_via_reg" [(call (mem:SI (match_operand:SI 0 "register_operand" "r")) (match_operand 1 "" "")) (clobber (reg:SI 14))] "" "jl %0" [(set_attr "type" "call") (set_attr "length" "2")])(define_insn "*call_via_label" [(call (mem:SI (match_operand:SI 0 "call_address_operand" "")) (match_operand 1 "" "")) (clobber (reg:SI 14))] "" "*{ int call26_p = call26_operand (operands[0], FUNCTION_MODE); if (! call26_p) { /* We may not be able to reach with a `bl' insn so punt and leave it to the linker. We do this here, rather than doing a force_reg in the define_expand so these insns won't be separated, say by scheduling, thus simplifying the linker. */ return \"seth r14,%T0\;add3 r14,r14,%B0\;jl r14\"; } else return \"bl %0\";}" [(set_attr "type" "call") (set (attr "length") (if_then_else (eq (symbol_ref "call26_operand (operands[0], FUNCTION_MODE)") (const_int 0)) (const_int 12) ; 10 + 2 for nop filler ; The return address must be on a 4 byte boundary so ; there's no point in using a value of 2 here. A 2 byte ; insn may go in the left slot but we currently can't ; use such knowledge. (const_int 4)))])(define_expand "call_value" ;; operand 2 is stack_size_rtx ;; operand 3 is next_arg_register [(parallel [(set (match_operand 0 "register_operand" "=r") (call (match_operand:SI 1 "call_operand" "") (match_operand 2 "" ""))) (clobber (reg:SI 14))])] "" "")(define_insn "*call_value_via_reg" [(set (match_operand 0 "register_operand" "=r") (call (mem:SI (match_operand:SI 1 "register_operand" "r")) (match_operand 2 "" ""))) (clobber (reg:SI 14))] "" "jl %1" [(set_attr "type" "call") (set_attr "length" "2")])(define_insn "*call_value_via_label" [(set (match_operand 0 "register_operand" "=r") (call (mem:SI (match_operand:SI 1 "call_address_operand" "")) (match_operand 2 "" ""))) (clobber (reg:SI 14))] "" "*{ int call26_p = call26_operand (operands[1], FUNCTION_MODE); if (! call26_p) { /* We may not be able to reach with a `bl' insn so punt and leave it to the linker. We do this here, rather than doing a force_reg in the define_expand so these insns won't be separated, say by scheduling, thus simplifying the linker. */ return \"seth r14,%T1\;add3 r14,r14,%B1\;jl r14\"; } else return \"bl %1\";}" [(set_attr "type" "call") (set (attr "length") (if_then_else (eq (symbol_ref "call26_operand (operands[1], FUNCTION_MODE)") (const_int 0)) (const_int 12) ; 10 + 2 for nop filler ; The return address must be on a 4 byte boundary so ; there's no point in using a value of 2 here. A 2 byte ; insn may go in the left slot but we currently can't ; use such knowledge. (const_int 4)))])(define_insn "nop" [(const_int 0)] "" "nop" [(set_attr "type" "int2") (set_attr "length" "2")]);; UNSPEC_VOLATILE is considered to use and clobber all hard registers and;; all of memory. This blocks insns from being moved across this point.(define_insn "blockage" [(unspec_volatile [(const_int 0)] 0)] "" "");; Special pattern to flush the icache.(define_insn "flush_icache" [(unspec_volatile [(match_operand 0 "memory_operand" "m")] 0)] "" "* return \"nop ; flush-icache\";" [(set_attr "type" "int2") (set_attr "length" "2")]);; Conditional move instructions;; Based on those done for the d10v(define_expand "movsicc" [ (set (match_operand:SI 0 "register_operand" "r") (if_then_else:SI (match_operand 1 "" "") (match_operand:SI 2 "conditional_move_operand" "O") (match_operand:SI 3 "conditional_move_operand" "O") ) ) ] "" "{ if (! zero_and_one (operands [2], operands [3])) FAIL; /* Generate the comparision that will set the carry flag. */ operands[1] = gen_compare ((int)GET_CODE (operands[1]), m32r_compare_op0, m32r_compare_op1, TRUE); /* See other movsicc pattern below for reason why. */ emit_insn (gen_blockage());}");; Generate the conditional instructions based on how the carry flag is examined.(define_insn "*movsicc_internal" [(set (match_operand:SI 0 "register_operand" "r") (if_then_else:SI (match_operand 1 "carry_compare_operand" "") (match_operand:SI 2 "conditional_move_operand" "O") (match_operand:SI 3 "conditional_move_operand" "O") ) )] "zero_and_one (operands [2], operands[3])" "* return emit_cond_move (operands, insn);" [(set_attr "type" "multi") (set_attr "length" "8") ])(define_insn "movcc_insn" [(set (match_operand:SI 0 "register_operand" "=r") (reg:SI 17))] "" "mvfc %0, cbr" [(set_attr "type" "misc") (set_attr "length" "2")]);; Split up troublesome insns for better scheduling.;; Peepholes go at the end.;; ??? Setting the type attribute may not be useful, but for completeness;; we do it.(define_peephole [(set (mem:SI (plus:SI (match_operand:SI 0 "register_operand" "r") (const_int 4))) (match_operand:SI 1 "register_operand" "r"))] "0 && dead_or_set_p (insn, operands[0])" "st %1,@+%0" [(set_attr "type" "store2") (set_attr "length" "2")]);; This case is triggered by compiling this code:;; ;; extern void sub(int *);;; void main (void);; {;; int i=2,j=3,k;;; while (i < j) sub(&k);;; i = j / k;;; sub(&i);;; i = j - k;;; sub(&i);;; };;;; Without the peephole the following assembler is generated for the;; divide and subtract expressions:;;;; div r5,r4 ;; mv r4,r5 ;; st r4,@(4,sp) ;; bl sub;; ;; Simialr code is produced for the subtract expression. With this;; peephole the redundant move is eliminated.;;;; This optimisation onbly works if PRESERVE_DEATH_INFO_REGNO_P is;; defined in m32r.h(define_peephole [(set (match_operand:SI 0 "register_operand" "r") (match_operand:SI 1 "register_operand" "r") ) (set (mem:SI (plus: SI (match_operand:SI 2 "register_operand" "r") (match_operand:SI 3 "immediate_operand" "J"))) (match_dup 0) ) ] "0 && dead_or_set_p (insn, operands [0])" "st %1,@(%3,%2)" [(set_attr "type" "store4") (set_attr "length" "4") ]);; Block moves, see m32r.c for more details.;; Argument 0 is the destination;; Argument 1 is the source;; Argument 2 is the length;; Argument 3 is the alignment(define_expand "movstrsi" [(parallel [(set (match_operand:BLK 0 "general_operand" "") (match_operand:BLK 1 "general_operand" "")) (use (match_operand:SI 2 "immediate_operand" "")) (use (match_operand:SI 3 "immediate_operand" ""))])] "" "{ if (operands[0]) /* avoid unused code messages */ { m32r_expand_block_move (operands); DONE; }}");; Insn generated by block moves(define_insn "movstrsi_internal" [(set (mem:BLK (match_operand:SI 0 "register_operand" "r")) ;; destination (mem:BLK (match_operand:SI 1 "register_operand" "r"))) ;; source (use (match_operand:SI 2 "m32r_block_immediate_operand" "J"));; # bytes to move (set (match_dup 0) (plus:SI (match_dup 0) (minus:SI (match_dup 2) (const_int 4)))) (set (match_dup 1) (plus:SI (match_dup 1) (match_dup 2))) (clobber (match_scratch:SI 3 "=&r")) ;; temp 1 (clobber (match_scratch:SI 4 "=&r"))] ;; temp 2 "" "* return m32r_output_block_move (insn, operands);" [(set_attr "type" "store8") (set_attr "length" "72")]) ;; Maximum
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -