diff options
author | DJ Delorie <dj@redhat.com> | 2013-09-11 20:16:03 -0400 |
---|---|---|
committer | DJ Delorie <dj@gcc.gnu.org> | 2013-09-11 20:16:03 -0400 |
commit | 3e3d9d17aaee8c46c94b73916859dbf05693c082 (patch) | |
tree | 4aea08d2edac609748062a818bbd39114a9c90b2 /gcc | |
parent | 4b47d65500aac94a4726fa57935366dd1616c14c (diff) | |
download | gcc-3e3d9d17aaee8c46c94b73916859dbf05693c082.tar.gz |
predicates.md (rl78_cmp_operator_signed): New.
* config/rl78/predicates.md (rl78_cmp_operator_signed): New.
(rl78_stack_based_mem): New.
* config/rl78/constraints.md (Iv08): New.
(Iv16): New.
(Iv24): New.
(Is09): New.
(Is17): New.
(Is25): New.
(ISsi): New.
(IShi): New.
(ISqi): New.
* config/rl78/rl78-expand.md (movqi): Reject more SUBREG operands.
(movhi): Likewise.
(movsi): Change from expand to insn-and-split.
(ashrsi3): Clobber AX.
(lshrsi3): New.
(ashlsi3): New.
(cbranchsi4): New.
* config/rl78/rl78.md (CC_REG): Fix.
(addsi3): Allow memory and immediate operands.
(addsi3_internal): Split into...
(addsi3_internal_virt): ...new, and ...
(addsi3_internal_real): ...new.
(subsi): New.
(subsi3_internal_virt): New.
(subsi3_internal_real): New.
(mulsi3): Add memory operand.
(mulsi3_rl78): Likewise.
(mulsi3_g13): Likewise.
* config/rl78/rl78-real.md (cbranchqi4_real_signed): New.
(cbranchqi4_real): Add more constraint options.
(cbranchhi4_real): Expand pattern.
(cbranchhi4_real_signed): New.
(cbranchhi4_real_inverted): New.
(cbranchsi4_real_lt): New.
(cbranchsi4_real_ge): New.
(cbranchsi4_real_signed): New.
(cbranchsi4_real): New.
(peephole2): New.
* config/rl78/rl78-virt.md (ashrsi3_virt): Add custom cases for constant shifts.
(lshrsi3_virt): Likewise.
(ashlsi3_virt): Likewise.
(cbranchqi4_virt_signed): New.
(cbranchhi4_virt_signed): New.
(cbranchsi4_virt): New.
* config/rl78/rl78.c: Whitespace fixes throughout.
(move_elim_pass): New.
(pass_data_rl78_move_elim): New.
(pass_rl78_move_elim): New.
(make_pass_rl78_move_elim): New.
(rl78_devirt_info): Run devirt earlier.
(rl78_move_elim_info): New.
(rl78_asm_file_start): Register it.
(rl78_split_movsi): New.
(rl78_as_legitimate_address): Allow virtual base registers when
appropriate.
(rl78_addr_space_convert): Remove spurious debug stuff.
(rl78_print_operand_1): Add z,s,S,r,E modifiers.
(rl78_print_operand): More cases for not printing '#'.
(rl78_expand_compare): Remove most of the logic.
(content_memory): New.
(clear_content_memory): New.
(get_content_index): New.
(get_content_name): New.
(display_content_memory): New.
(update_content): New.
(record_content): New.
(already_contains): New.
(insn_ok_now): Re-recog insns with virtual registers.
(add_postponed_content_update): New.
(process_postponed_content_update): New.
(gen_and_emit_move): New.
(transcode_memory_rtx): Record new location content. Use
gen_and_emit_move.
(force_into_acc): New.
(move_to_acc): Use gen_and_emit_move.
(move_from_acc): Likewise.
(move_acc_to_reg): Likewise.
(move_to_x): Likewise.
(move_to_hl): Likewise.
(move_to_de): Likewise.
(rl78_alloc_physical_registers_op1): Record location content.
(has_constraint): New.
(rl78_alloc_physical_registers_op2): Record location content.
Optimize use of HL.
(rl78_alloc_physical_registers_ro1): Likewise.
(rl78_alloc_physical_registers_cmp): Likewise.
(rl78_alloc_physical_registers_umul): Likewise.
(rl78_alloc_address_registers_macax): New.
(rl78_alloc_physical_registers): Initialize and set location
content memory as needed.
(rl78_reorg): Make sure split2 is called.
(rl78_rtx_costs): New.
Co-Authored-By: Nick Clifton <nickc@redhat.com>
From-SVN: r202511
Diffstat (limited to 'gcc')
-rw-r--r-- | gcc/ChangeLog | 97 | ||||
-rw-r--r-- | gcc/config/rl78/constraints.md | 51 | ||||
-rw-r--r-- | gcc/config/rl78/predicates.md | 11 | ||||
-rw-r--r-- | gcc/config/rl78/rl78-expand.md | 84 | ||||
-rw-r--r-- | gcc/config/rl78/rl78-protos.h | 1 | ||||
-rw-r--r-- | gcc/config/rl78/rl78-real.md | 136 | ||||
-rw-r--r-- | gcc/config/rl78/rl78-virt.md | 164 | ||||
-rw-r--r-- | gcc/config/rl78/rl78.c | 1280 | ||||
-rw-r--r-- | gcc/config/rl78/rl78.md | 97 |
9 files changed, 1628 insertions, 293 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog index bbe5479e6a2..e05cb8ef667 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,100 @@ +2013-09-11 DJ Delorie <dj@redhat.com> + Nick Clifton <nickc@redhat.com> + + * config/rl78/predicates.md (rl78_cmp_operator_signed): New. + (rl78_stack_based_mem): New. + * config/rl78/constraints.md (Iv08): New. + (Iv16): New. + (Iv24): New. + (Is09): New. + (Is17): New. + (Is25): New. + (ISsi): New. + (IShi): New. + (ISqi): New. + * config/rl78/rl78-expand.md (movqi): Reject more SUBREG operands. + (movhi): Likewise. + (movsi): Change from expand to insn-and-split. + (ashrsi3): Clobber AX. + (lshrsi3): New. + (ashlsi3): New. + (cbranchsi4): New. + * config/rl78/rl78.md (CC_REG): Fix. + (addsi3): Allow memory and immediate operands. + (addsi3_internal): Split into... + (addsi3_internal_virt): ...new, and ... + (addsi3_internal_real): ...new. + (subsi): New. + (subsi3_internal_virt): New. + (subsi3_internal_real): New. + (mulsi3): Add memory operand. + (mulsi3_rl78): Likewise. + (mulsi3_g13): Likewise. + * config/rl78/rl78-real.md (cbranchqi4_real_signed): New. + (cbranchqi4_real): Add more constraint options. + (cbranchhi4_real): Expand pattern. + (cbranchhi4_real_signed): New. + (cbranchhi4_real_inverted): New. + (cbranchsi4_real_lt): New. + (cbranchsi4_real_ge): New. + (cbranchsi4_real_signed): New. + (cbranchsi4_real): New. + (peephole2): New. + * config/rl78/rl78-virt.md (ashrsi3_virt): Add custom cases for constant shifts. + (lshrsi3_virt): Likewise. + (ashlsi3_virt): Likewise. + (cbranchqi4_virt_signed): New. + (cbranchhi4_virt_signed): New. + (cbranchsi4_virt): New. + * config/rl78/rl78.c: Whitespace fixes throughout. + (move_elim_pass): New. + (pass_data_rl78_move_elim): New. + (pass_rl78_move_elim): New. + (make_pass_rl78_move_elim): New. + (rl78_devirt_info): Run devirt earlier. + (rl78_move_elim_info): New. + (rl78_asm_file_start): Register it. + (rl78_split_movsi): New. + (rl78_as_legitimate_address): Allow virtual base registers when + appropriate. + (rl78_addr_space_convert): Remove spurious debug stuff. + (rl78_print_operand_1): Add z,s,S,r,E modifiers. + (rl78_print_operand): More cases for not printing '#'. + (rl78_expand_compare): Remove most of the logic. + (content_memory): New. + (clear_content_memory): New. + (get_content_index): New. + (get_content_name): New. + (display_content_memory): New. + (update_content): New. + (record_content): New. + (already_contains): New. + (insn_ok_now): Re-recog insns with virtual registers. + (add_postponed_content_update): New. + (process_postponed_content_update): New. + (gen_and_emit_move): New. + (transcode_memory_rtx): Record new location content. Use + gen_and_emit_move. + (force_into_acc): New. + (move_to_acc): Use gen_and_emit_move. + (move_from_acc): Likewise. + (move_acc_to_reg): Likewise. + (move_to_x): Likewise. + (move_to_hl): Likewise. + (move_to_de): Likewise. + (rl78_alloc_physical_registers_op1): Record location content. + (has_constraint): New. + (rl78_alloc_physical_registers_op2): Record location content. + Optimize use of HL. + (rl78_alloc_physical_registers_ro1): Likewise. + (rl78_alloc_physical_registers_cmp): Likewise. + (rl78_alloc_physical_registers_umul): Likewise. + (rl78_alloc_address_registers_macax): New. + (rl78_alloc_physical_registers): Initialize and set location + content memory as needed. + (rl78_reorg): Make sure split2 is called. + (rl78_rtx_costs): New. + 2013-09-11 Richard Sandiford <rdsandiford@googlemail.com> * simplify-rtx.c (simplify_unary_operation_1): Use simplify_gen_binary diff --git a/gcc/config/rl78/constraints.md b/gcc/config/rl78/constraints.md index 8b03cf32211..1edb58d8068 100644 --- a/gcc/config/rl78/constraints.md +++ b/gcc/config/rl78/constraints.md @@ -43,6 +43,7 @@ ; Y - any valid memory ; Wxx - various memory addressing modes ; Qxx - conditionals +; U = usual memory references mov-able to/from AX ; v = virtual registers ; Zxx = specific virtual registers @@ -56,6 +57,56 @@ (and (match_code "const_int") (match_test "IN_RANGE (ival, 1, 7)"))) +(define_constraint "Iv08" + "@internal + Integer constant equal to 8." + (and (match_code "const_int") + (match_test "IN_RANGE (ival, 8, 8)"))) +(define_constraint "Iv16" + "@internal + Integer constant equal to 16." + (and (match_code "const_int") + (match_test "IN_RANGE (ival, 16, 16)"))) +(define_constraint "Iv24" + "@internal + Integer constant equal to 24." + (and (match_code "const_int") + (match_test "IN_RANGE (ival, 24, 24)"))) + +(define_constraint "Is09" + "@internal + Integer constant in the range 9 @dots{} 15 (for shifts)." + (and (match_code "const_int") + (match_test "IN_RANGE (ival, 9, 15)"))) +(define_constraint "Is17" + "@internal + Integer constant in the range 17 @dots{} 23 (for shifts)." + (and (match_code "const_int") + (match_test "IN_RANGE (ival, 17, 23)"))) +(define_constraint "Is25" + "@internal + Integer constant in the range 25 @dots{} 31 (for shifts)." + (and (match_code "const_int") + (match_test "IN_RANGE (ival, 25, 31)"))) + +(define_constraint "ISsi" + "@internal + Integer constant with bit 31 set." + (and (match_code "const_int") + (match_test "(ival & 0x80000000) != 0"))) + +(define_constraint "IShi" + "@internal + Integer constant with bit 15 set." + (and (match_code "const_int") + (match_test "(ival & 0x8000) != 0"))) + +(define_constraint "ISqi" + "@internal + Integer constant with bit 7 set." + (and (match_code "const_int") + (match_test "(ival & 0x80) != 0"))) + (define_constraint "J" "Integer constant in the range -255 @dots{} 0" (and (match_code "const_int") diff --git a/gcc/config/rl78/predicates.md b/gcc/config/rl78/predicates.md index 33ce900bffa..99ee656aad5 100644 --- a/gcc/config/rl78/predicates.md +++ b/gcc/config/rl78/predicates.md @@ -46,6 +46,8 @@ (and (match_code "const_int") (match_test "IN_RANGE (INTVAL (op), 0, 65536)")))) +(define_predicate "rl78_cmp_operator_signed" + (match_code "gt,ge,lt,le")) (define_predicate "rl78_cmp_operator_real" (match_code "eq,ne,gtu,ltu,geu,leu")) (define_predicate "rl78_cmp_operator" @@ -58,3 +60,12 @@ (define_predicate "rl78_addw_operand" (and (match_code "reg") (match_test "REGNO (op) == AX_REG || REGNO (op) == SP_REG || REGNO (op) >= FIRST_PSEUDO_REGISTER"))) + +(define_predicate "rl78_stack_based_mem" + (and (match_code "mem") + (ior (and (match_code "reg" "0") + (match_test "REGNO (XEXP (op, 0)) == SP_REG")) + (and (match_code "plus" "0") + (and (match_code "reg" "00") + (match_test "REGNO (XEXP (XEXP (op, 0), 0)) == SP_REG") + (match_code "const_int" "01")))))) diff --git a/gcc/config/rl78/rl78-expand.md b/gcc/config/rl78/rl78-expand.md index 3f24b150bab..40c416251d3 100644 --- a/gcc/config/rl78/rl78-expand.md +++ b/gcc/config/rl78/rl78-expand.md @@ -35,9 +35,24 @@ if (GET_CODE (operand1) == SUBREG && GET_CODE (XEXP (operand1, 0)) == SYMBOL_REF) FAIL; + /* Similarly for (SUBREG (CONST (PLUS (SYMBOL_REF)))). + cf. g++.dg/abi/packed.C. */ + if (GET_CODE (operand1) == SUBREG + && GET_CODE (XEXP (operand1, 0)) == CONST + && GET_CODE (XEXP (XEXP (operand1, 0), 0)) == PLUS + && GET_CODE (XEXP (XEXP (XEXP (operand1, 0), 0), 0)) == SYMBOL_REF) + FAIL; + + /* Similarly for (SUBREG (CONST (PLUS (SYMBOL_REF)))). + cf. g++.dg/abi/packed.C. */ + if (GET_CODE (operand1) == SUBREG + && GET_CODE (XEXP (operand1, 0)) == CONST + && GET_CODE (XEXP (XEXP (operand1, 0), 0)) == PLUS + && GET_CODE (XEXP (XEXP (XEXP (operand1, 0), 0), 0)) == SYMBOL_REF) + FAIL; if (CONST_INT_P (operand1) && ! IN_RANGE (INTVAL (operand1), (-1 << 8) + 1, (1 << 8) - 1)) - gcc_unreachable(); + FAIL; } ) @@ -56,17 +71,27 @@ if (GET_CODE (operand1) == SUBREG && GET_CODE (XEXP (operand1, 0)) == SYMBOL_REF) FAIL; + /* Similarly for (SUBREG (CONST (PLUS (SYMBOL_REF)))). */ + if (GET_CODE (operand1) == SUBREG + && GET_CODE (XEXP (operand1, 0)) == CONST + && GET_CODE (XEXP (XEXP (operand1, 0), 0)) == PLUS + && GET_CODE (XEXP (XEXP (XEXP (operand1, 0), 0), 0)) == SYMBOL_REF) + FAIL; } ) -(define_expand "movsi" - [(set (match_operand:SI 0 "nonimmediate_operand") - (match_operand:SI 1 "general_operand"))] +(define_insn_and_split "movsi" + [(set (match_operand:SI 0 "nonimmediate_operand" "=vYS,v,Wfr") + (match_operand:SI 1 "general_operand" "viYS,Wfr,v"))] "" - { - rl78_expand_movsi (operands); - DONE; - } + "#" + "" + [(set (match_operand:HI 2 "nonimmediate_operand") + (match_operand:HI 4 "general_operand")) + (set (match_operand:HI 3 "nonimmediate_operand") + (match_operand:HI 5 "general_operand"))] + "rl78_split_movsi (operands);" + [(set_attr "valloc" "op1")] ) ;;---------- Conversions ------------------------ @@ -200,13 +225,33 @@ ) (define_expand "ashrsi3" - [(set (match_operand:SI 0 "register_operand") - (ashiftrt:SI (match_operand:SI 1 "register_operand") - (match_operand:SI 2 "immediate_operand"))) + [(parallel [(set (match_operand:SI 0 "nonimmediate_operand") + (ashiftrt:SI (match_operand:SI 1 "nonimmediate_operand") + (match_operand:SI 2 "nonmemory_operand"))) + (clobber (reg:HI X_REG))]) ] "" - "if (GET_CODE (operands[2]) != CONST_INT) - FAIL;" + "" +) + +(define_expand "lshrsi3" + [(parallel [(set (match_operand:SI 0 "nonimmediate_operand") + (lshiftrt:SI (match_operand:SI 1 "nonimmediate_operand") + (match_operand:SI 2 "nonmemory_operand"))) + (clobber (reg:HI X_REG))]) + ] + "" + "" +) + +(define_expand "ashlsi3" + [(parallel [(set (match_operand:SI 0 "nonimmediate_operand") + (ashift:SI (match_operand:SI 1 "nonimmediate_operand") + (match_operand:SI 2 "nonmemory_operand"))) + (clobber (reg:HI X_REG))]) + ] + "" + "" ) ;;---------- Branching ------------------------ @@ -254,3 +299,16 @@ "" "rl78_expand_compare (operands);" ) + +(define_expand "cbranchsi4" + [(parallel [(set (pc) (if_then_else + (match_operator 0 "rl78_cmp_operator" + [(match_operand:SI 1 "general_operand") + (match_operand:SI 2 "nonmemory_operand")]) + (label_ref (match_operand 3 "" "")) + (pc))) + (clobber (reg:HI AX_REG)) + ])] + "1" + "rl78_expand_compare (operands);" +) diff --git a/gcc/config/rl78/rl78-protos.h b/gcc/config/rl78/rl78-protos.h index b13c65065d1..580609da2f9 100644 --- a/gcc/config/rl78/rl78-protos.h +++ b/gcc/config/rl78/rl78-protos.h @@ -21,6 +21,7 @@ void rl78_emit_eh_epilogue (rtx); void rl78_expand_compare (rtx *); void rl78_expand_movsi (rtx *); +void rl78_split_movsi (rtx *); int rl78_force_nonfar_2 (rtx *, rtx (*gen)(rtx,rtx)); int rl78_force_nonfar_3 (rtx *, rtx (*gen)(rtx,rtx,rtx)); void rl78_expand_eh_epilogue (rtx); diff --git a/gcc/config/rl78/rl78-real.md b/gcc/config/rl78/rl78-real.md index 76daaf17e84..409abcc4a2a 100644 --- a/gcc/config/rl78/rl78-real.md +++ b/gcc/config/rl78/rl78-real.md @@ -312,11 +312,26 @@ call\t%A1" ) +(define_insn "cbranchqi4_real_signed" + [(set (pc) (if_then_else + (match_operator 0 "rl78_cmp_operator_signed" + [(match_operand:QI 1 "general_operand" "A,A,A") + (match_operand:QI 2 "general_operand" "ISqi,i,v")]) + (label_ref (match_operand 3 "" "")) + (pc)))] + "rl78_real_insns_ok ()" + "@ + cmp\t%1, %2 \;xor1 CY,%1.7\;not1 CY\;sk%c0 \;br\t!!%3 + cmp\t%1, %2 \;xor1 CY,%1.7\;sk%c0 \;br\t!!%3 + cmp\t%1, %2 \;xor1 CY,%1.7\;xor1 CY,%2.7\;sk%c0 \;br\t!!%3" + ) + + (define_insn "*cbranchqi4_real" [(set (pc) (if_then_else (match_operator 0 "rl78_cmp_operator_real" - [(match_operand:QI 1 "general_operand" "Wabvaxbc,a, v,bcdehl") - (match_operand:QI 2 "general_operand" "M, irWhlWh1Whb,i,a")]) + [(match_operand:QI 1 "general_operand" "Wabvaxbc,a, v,bcdehl") + (match_operand:QI 2 "general_operand" "M, irvWabWhlWh1Whb,i,a")]) (label_ref (match_operand 3 "" "")) (pc)))] "rl78_real_insns_ok ()" @@ -327,13 +342,120 @@ cmp\t%1, %2 \;sk%c0 \;br\t!!%3" ) -(define_insn "*cbranchhi4_real" +(define_insn "cbranchhi4_real_signed" [(set (pc) (if_then_else - (match_operator 0 "rl78_cmp_operator_real" - [(match_operand:HI 1 "general_operand" "A") - (match_operand:HI 2 "general_operand" "iBDTWhlWh1")]) - (label_ref (match_operand 3 "" "")) + (match_operator 0 "rl78_cmp_operator_signed" + [(match_operand:HI 1 "general_operand" "A,A,A,vR") + (match_operand:HI 2 "general_operand" "IShi,i,v,1")]) + (label_ref (match_operand 3)) (pc)))] "rl78_real_insns_ok ()" + "@ + cmpw\t%1, %2 \;xor1 CY,%Q1.7\;not1 CY\;sk%c0 \;br\t!!%3 + cmpw\t%1, %2 \;xor1 CY,%Q1.7\;sk%c0 \;br\t!!%3 + cmpw\t%1, %2 \;xor1 CY,%Q1.7\;xor1 CY,%Q2.7\;sk%c0 \;br\t!!%3 + %z0\t!!%3" + ) + +(define_insn "cbranchhi4_real" + [(set (pc) (if_then_else + (match_operator 0 "rl78_cmp_operator_real" + [(match_operand:HI 1 "general_operand" "A,vR") + (match_operand:HI 2 "general_operand" "iBDTvWabWhlWh1,1")]) + (label_ref (match_operand 3 "" "")) + (pc)))] + "rl78_real_insns_ok ()" + "@ + cmpw\t%1, %2 \;sk%c0 \;br\t!!%3 + %z0\t!!%3" + ) + +(define_insn "cbranchhi4_real_inverted" + [(set (pc) (if_then_else + (match_operator 0 "rl78_cmp_operator_real" + [(match_operand:HI 1 "general_operand" "A") + (match_operand:HI 2 "general_operand" "iBDTvWabWhlWh1")]) + (pc) + (label_ref (match_operand 3 "" ""))))] + "rl78_real_insns_ok ()" "cmpw\t%1, %2 \;sk%c0 \;br\t!!%3" ) + +(define_insn "cbranchsi4_real_lt" + [(set (pc) (if_then_else + (lt (match_operand:SI 0 "general_operand" "U,vWabWhlWh1") + (const_int 0)) + (label_ref (match_operand 1 "" "")) + (pc))) + (clobber (reg:HI AX_REG)) + ] + "rl78_real_insns_ok ()" + "@ + mov a, %E0 \;mov1 CY,a.7 \;sknc \;br\t!!%1 + mov1 CY,%E0.7 \;sknc \;br\t!!%1" + ) + +(define_insn "cbranchsi4_real_ge" + [(set (pc) (if_then_else + (ge (match_operand:SI 0 "general_operand" "U,vWabWhlWh1") + (const_int 0)) + (label_ref (match_operand 1 "" "")) + (pc))) + (clobber (reg:HI AX_REG)) + ] + "rl78_real_insns_ok ()" + "@ + mov a, %E0 \;mov1 CY,a.7 \;skc \;br\t!!%1 + mov1 CY,%E0.7 \;skc \;br\t!!%1" + ) + +(define_insn "cbranchsi4_real_signed" + [(set (pc) (if_then_else + (match_operator 0 "rl78_cmp_operator_signed" + [(match_operand:SI 1 "nonimmediate_operand" "vU,vU,vU") + (match_operand:SI 2 "nonmemory_operand" "ISsi,i,v")]) + (label_ref (match_operand 3 "" "")) + (pc))) + (clobber (reg:HI AX_REG)) + ] + "rl78_real_insns_ok ()" + "@ + movw ax,%H1 \;cmpw ax, %H2 \;xor1 CY,a.7\;not1 CY\; movw ax,%h1 \;sknz \;cmpw ax, %h2 \;sk%c0 \;br\t!!%3 + movw ax,%H1 \;cmpw ax, %H2 \;xor1 CY,a.7\; movw ax,%h1 \;sknz \;cmpw ax, %h2 \;sk%c0 \;br\t!!%3 + movw ax,%H1 \;cmpw ax, %H2 \;xor1 CY,a.7\;xor1 CY,%E2.7\;movw ax,%h1 \;sknz \;cmpw ax, %h2 \;sk%c0 \;br\t!!%3" + ) + +(define_insn "cbranchsi4_real" + [(set (pc) (if_then_else + (match_operator 0 "rl78_cmp_operator_real" + [(match_operand:SI 1 "general_operand" "vUi") + (match_operand:SI 2 "general_operand" "iWhlWh1v")]) + (label_ref (match_operand 3 "" "")) + (pc))) + (clobber (reg:HI AX_REG)) + ] + "rl78_real_insns_ok ()" + "movw ax,%H1 \;cmpw ax, %H2 \;movw ax,%h1 \;sknz \;cmpw ax, %h2 \;sk%c0 \;br\t!!%3" + ) + +;; Peephole to match: +;; +;; (set (mem (sp)) (ax)) +;; (set (ax) (mem (sp))) +;; or: +;; (set (mem (plus (sp) (const)) (ax)) +;; (set (ax) (mem (plus (sp) (const)))) +;; +;; which can be generated as the last instruction of the conversion +;; of one virtual insn into a real insn and the first instruction of +;; the conversion of the following virtual insn. + +(define_peephole2 + [(set (match_operand:HI 0 "rl78_stack_based_mem") + (reg:HI AX_REG)) + (set (reg:HI AX_REG) + (match_dup 0))] + "" + [(set (match_dup 0) (reg:HI AX_REG))] + ) + diff --git a/gcc/config/rl78/rl78-virt.md b/gcc/config/rl78/rl78-virt.md index d73a51484ba..0585ef52cc2 100644 --- a/gcc/config/rl78/rl78-virt.md +++ b/gcc/config/rl78/rl78-virt.md @@ -161,20 +161,130 @@ "v.shr\t%0, %1, %2" ) -;; really a macro -(define_insn "*ashrsi3_virt" - [(set (match_operand:SI 0 "register_operand" "=v,v,v") - (ashiftrt:SI (match_operand:SI 1 "register_operand" "0,v,0") - (match_operand:SI 2 "immediate_operand" "M,K,i"))) +;; This is complex mostly because the RL78 has no SImode operations, +;; and very limited HImode operations, and no variable shifts. This +;; pattern is optimized for each constant shift count and operand +;; types, so as to use a hand-optimized pattern. For readability, the +;; usual \t\; syntax is not used here. Also, there's no easy way to +;; constrain to avoid partial overlaps, hence the duplication. +(define_insn "ashrsi3_virt" ;; 0 1 2-7 8 9-15 16 17-23 24 25-31 var + [(set (match_operand:SI 0 "nonimmediate_operand" "=v,vU,&vU,v, &vU, &vU, v, &vU, v, &vU, &vU, vU, v,&vU, vU, vU, vU") + (ashiftrt:SI (match_operand:SI 1 "nonimmediate_operand" "0, 0, vU,0, vWab, U, 0, vU, 0, vWab,U, vU, 0, vU, vU, vU, 0") + (match_operand:SI 2 "nonmemory_operand" "M, K, K, Int3,Int3,Int3,Iv08,Iv08,Is09,Is09,Is09,Iv16,Is17,Is17,Iv24,Is25, iv"))) + (clobber (reg:HI X_REG)) + ] + "" + "@ + ; ashrsi %0, 0 + + movw ax,%H1 | sarw ax,1 | movw %H0,ax | mov a,%Q1 | rorc a,1 | mov %Q0,a | mov a,%q1 | rorc a,1 | mov %q0,a + movw ax,%H1 | sarw ax,1 | movw %H0,ax | mov a,%Q1 | rorc a,1 | mov %Q0,a | mov a,%q1 | rorc a,1 | mov %q0,a + + movw ax,%1 | shlw ax,%r2 | mov %0,a | mov x,%Q1 | mov a,%H1 | shlw ax,%r2 | mov %Q0,a | movw ax,%H1 | sarw ax,%u2 | movw %H0,ax + movw ax,%1 | shlw ax,%r2 | mov %0,a | mov x,%Q1 | mov a,%H1 | shlw ax,%r2 | mov %Q0,a | movw ax,%H1 | sarw ax,%u2 | movw %H0,ax + movw ax,%1 | shlw ax,%r2 | mov %0,a | mov a,%Q1 | mov x,a | mov a,%H1 | shlw ax,%r2 | mov %Q0,a | movw ax,%H1 | sarw ax,%u2 | movw %H0,ax + + mov x,%Q1 | mov a,%H1 | movw %0,ax | movw ax,%H1 | sarw ax,8 | movw %H0,ax + mov a,%Q1 | mov x, a | mov a,%H1 | movw %0,ax | movw ax,%H1 | sarw ax,8 | movw %H0,ax + + mov x,%Q1 | mov a,%H1 | shlw ax,%r2 | mov %0,a | movw ax,%H1 | shlw ax,%r2 | mov %Q0,a | movw ax,%H1 | sarw ax,%u2 | movw %H0,ax + mov x,%Q1 | mov a,%H1 | shlw ax,%r2 | mov %0,a | movw ax,%H1 | shlw ax,%r2 | mov %Q0,a | movw ax,%H1 | sarw ax,%u2 | movw %H0,ax + mov a,%Q1 | mov x,a | mov a,%H1 | shlw ax,%r2 | mov %0,a | movw ax,%H1 | shlw ax,%r2 | mov %Q0,a | movw ax,%H1 | sarw ax,%u2 | movw %H0,ax + + movw ax,%H1 | movw %0,ax | sarw ax,15 | movw %H0,ax + + movw ax,%H1 | sarw ax,%S2 | movw %0,ax | sarw ax,15 | movw %H0,ax + movw ax,%H1 | sarw ax,%S2 | movw %0,ax | sarw ax,15 | movw %H0,ax + + movw ax,%H1 | mov %0,a | sarw ax,15 | movw %H0,ax | mov %Q0,a + + movw ax,%H1 | sar a,%s2 | mov %0,a | sarw ax,15 | movw %H0,ax | mov %Q0,a + + mov b,%2 | cmp0 b | bz $2f | 1: | movw ax,%H1 | sarw ax,1 | movw %H0,ax | mov a,%Q1 | rorc a,1 | mov %Q0,a | mov a,%q1 | rorc a,1 | mov %q0,a | dec b | bnz $1b | 2:" + [(set_attr "valloc" "macax")] +) + +;; Likewise. +(define_insn "lshrsi3_virt" ;; 0 1 2-7 8 9-15 16 17-23 24 25-31 var + [(set (match_operand:SI 0 "nonimmediate_operand" "=v,vU,&vU,v, &vU, &vU, v, &vU, v, &vU, &vU, vU, v,&vU, vU, vU, vU") + (lshiftrt:SI (match_operand:SI 1 "nonimmediate_operand" "0, 0, vU,0, vWab, U, 0, vU, 0, vWab,U, vU, 0, vU, vU, vU, 0") + (match_operand:SI 2 "nonmemory_operand" "M, K, K, Int3,Int3,Int3,Iv08,Iv08,Is09,Is09,Is09,Iv16,Is17,Is17,Iv24,Is25, iv"))) + (clobber (reg:HI X_REG)) ] "" "@ - ; ashrsi %0, 0 - movw\tax,%H1\;sarw\tax,1\;movw\t%H0,ax\;mov\ta,%Q1\;rorc\ta,1\;mov\t%Q0,a\;mov\ta,%q1\;rorc\ta,1\;mov\t%q0,a - mov\tb,%2\;1:\;movw\tax,%H1\;sarw\tax,1\;movw\t%H0,ax\;mov\ta,%Q1\;rorc\ta,1\;mov\t%Q0,a\;mov\ta,%q1\;rorc\ta,1\;mov\t%q0,a\;dec\tb\;bnz $1b" + ; lshrsi %0, 0 + + movw ax,%H1 | shrw ax,1 | movw %H0,ax | mov a,%Q1 | rorc a,1 | mov %Q0,a | mov a,%q1 | rorc a,1 | mov %q0,a + movw ax,%H1 | shrw ax,1 | movw %H0,ax | mov a,%Q1 | rorc a,1 | mov %Q0,a | mov a,%q1 | rorc a,1 | mov %q0,a + + movw ax,%1 | shlw ax,%r2 | mov %0,a | mov x,%Q1 | mov a,%H1 | shlw ax,%r2 | mov %Q0,a | movw ax,%H1 | shrw ax,%u2 | movw %H0,ax + movw ax,%1 | shlw ax,%r2 | mov %0,a | mov x,%Q1 | mov a,%H1 | shlw ax,%r2 | mov %Q0,a | movw ax,%H1 | shrw ax,%u2 | movw %H0,ax + movw ax,%1 | shlw ax,%r2 | mov %0,a | mov a,%Q1 | mov x,a | mov a,%H1 | shlw ax,%r2 | mov %Q0,a | movw ax,%H1 | shrw ax,%u2 | movw %H0,ax + + mov x,%Q1 | mov a,%H1 | movw %0,ax | movw ax,%H1 | shrw ax,8 | movw %H0,ax + mov a,%Q1 | mov x, a | mov a,%H1 | movw %0,ax | movw ax,%H1 | shrw ax,8 | movw %H0,ax + + mov x,%Q1 | mov a,%H1 | shlw ax,%r2 | mov %0,a | movw ax,%H1 | shlw ax,%r2 | mov %Q0,a | movw ax,%H1 | shrw ax,%u2 | movw %H0,ax + mov x,%Q1 | mov a,%H1 | shlw ax,%r2 | mov %0,a | movw ax,%H1 | shlw ax,%r2 | mov %Q0,a | movw ax,%H1 | shrw ax,%u2 | movw %H0,ax + mov a,%Q1 | mov x,a | mov a,%H1 | shlw ax,%r2 | mov %0,a | movw ax,%H1 | shlw ax,%r2 | mov %Q0,a | movw ax,%H1 | shrw ax,%u2 | movw %H0,ax + + movw ax,%H1 | movw %0,ax | movw ax,#0 | movw %H0,ax + + movw ax,%H1 | shrw ax,%S2 | movw %0,ax | movw ax,#0 | movw %H0,ax + movw ax,%H1 | shrw ax,%S2 | movw %0,ax | movw ax,#0 | movw %H0,ax + + movw ax,%H1 | mov %0,a | movw ax,#0 | movw %H0,ax | mov %Q0,a + + movw ax,%H1 | shr a,%s2 | mov %0,a | movw ax,#0 | movw %H0,ax | mov %Q0,a + + mov b,%2 | cmp0 b | bz $2f | 1: | movw ax,%H1 | shrw ax,1 | movw %H0,ax | mov a,%Q1 | rorc a,1 | mov %Q0,a | mov a,%q1 | rorc a,1 | mov %q0,a | dec b | bnz $1b | 2:" [(set_attr "valloc" "macax")] ) +;; Likewise. +(define_insn "ashlsi3_virt" ;; 0 1 2-7 8 9-15 16 17-23 24 25-31 var + [(set (match_operand:SI 0 "nonimmediate_operand" "=v,vU,&vU,v, &vU, &vU, v, &vU, v, &vU, &vU, v, U, v,&vU, v, U, v, U, vWab,vU, vU") + (ashift:SI (match_operand:SI 1 "nonimmediate_operand" "0, 0, vU,0, vWab, U, 0, vU, 0, vWab,U, vU, vU, 0, vU, vU, vU, vU, vU, 0, vWab,U") + (match_operand:SI 2 "nonmemory_operand" "M, K, K, Int3,Int3,Int3,Iv08,Iv08,Is09,Is09,Is09,Iv16,Iv16,Is17,Is17,Iv24,Iv24,Is25,Is25,iv, iv, iv"))) + (clobber (reg:HI X_REG)) + ] + "" + "@ + ; lshrsi %0, 0 + + movw ax,%1 | shlw ax,1 | movw %0,ax | movw ax,%H1 | rolwc ax,1 | movw %H0,ax + movw ax,%1 | shlw ax,1 | movw %0,ax | movw ax,%H1 | rolwc ax,1 | movw %H0,ax + + movw ax,%H1 | shlw ax,%u2 | mov %E0,a | mov x,%Q1 | mov a, %H1 | shlw ax,%S2 | mov %H0,a | movw ax,%1 | shlw ax,%u2 | movw %0,ax + movw ax,%H1 | shlw ax,%u2 | mov %E0,a | mov x,%Q1 | mov a, %H1 | shlw ax,%S2 | mov %H0,a | movw ax,%1 | shlw ax,%u2 | movw %0,ax + movw ax,%H1 | shlw ax,%u2 | mov %E0,a | mov a,%Q1 | mov x,a | mov a, %H1 | shlw ax,%S2 | mov %H0,a | movw ax,%1 | shlw ax,%u2 | movw %0,ax + + mov x,%Q1 | mov a,%H1 | movw %H0,ax | movw ax,%1 | shlw ax,8 | movw %0,ax + mov a,%Q1 | mov x,a | mov a,%H1 | movw %H0,ax | movw ax,%1 | shlw ax,8 | movw %0,ax + + mov x,%Q1 | mov a,%H1 | shlw ax,%s2 | movw %H0,ax | movw ax,%1 | shlw ax,%s2 | mov %H0,a | movw ax,%1 | shlw ax,%u2 | movw %0,ax + mov x,%Q1 | mov a,%H1 | shlw ax,%s2 | movw %H0,ax | movw ax,%1 | shlw ax,%s2 | mov %H0,a | movw ax,%1 | shlw ax,%u2 | movw %0,ax + mov a,%Q1 | mov x,a | mov a,%H1 | shlw ax,%s2 | movw %H0,ax | movw ax,%1 | shlw ax,%s2 | mov %H0,a | movw ax,%1 | shlw ax,%u2 | movw %0,ax + + movw ax,%1 | movw %H0,ax | movw %0,#0 + movw ax,%1 | movw %H0,ax | movw ax,#0 | movw %0,ax + + movw ax,%1 | shlw ax,%S2 | movw %H0,ax | movw %0,#0 + movw ax,%1 | shlw ax,%S2 | movw %H0,ax | movw ax,#0 | movw %0,ax + + mov a,%1 | movw %H0,ax | mov %H0,#0 | movw %0,#0 + mov a,%1 | movw %H0,ax | movw ax,#0 | mov %H0,a | movW %0,ax + + mov a,%1 | shl a,%s2 | movw %H0,ax | mov %H0,#0 | movw %0,#0 + mov a,%1 | shl a,%s2 | movw %H0,ax | movw ax,#0 | mov %H0,a | movW %0,ax + + mov a,%2 | cmp0 a | bz $2f | mov d,a | movw ax,%H1 | movw bc,%1 | 1: | shlw bc,1 | rolwc ax,1 | dec d | bnz $1b | movw %H0,ax | movw ax,bc | movw %0,ax | 2: + mov a,%2 | mov d,a | movw ax,%H1 | movw bc,%1 | cmp0 0xFFEFD | bz $2f | 1: | shlw bc,1 | rolwc ax,1 | dec d | bnz $1b | 2: | movw %H0,ax | movw ax,bc | movw %0,ax + mov a,%2 | mov d,a | movw ax,%1 | movw bc,ax | movw ax,%H1 | cmp0 0xFFEFD | bz $2f | 1: | shlw bc,1 | rolwc ax,1 | dec d | bnz $1b | 2: | movw %H0,ax | movw ax,bc | movw %0,ax" + [(set_attr "valloc" "macax")] + ) + ;;---------- Branching ------------------------ (define_insn "*indirect_jump_virt" @@ -202,6 +312,18 @@ [(set_attr "valloc" "op1")] ) +(define_insn "cbranchqi4_virt_signed" + [(set (pc) (if_then_else + (match_operator 0 "rl78_cmp_operator_signed" + [(match_operand:QI 1 "general_operand" "vim") + (match_operand:QI 2 "nonmemory_operand" "vi")]) + (label_ref (match_operand 3 "" "")) + (pc)))] + "rl78_virt_insns_ok ()" + "v.cmp\t%1, %2\\n\tv.b%c0\t%3" + [(set_attr "valloc" "cmp")] + ) + (define_insn "*cbranchqi4_virt" [(set (pc) (if_then_else (match_operator 0 "rl78_cmp_operator_real" @@ -214,6 +336,18 @@ [(set_attr "valloc" "cmp")] ) +(define_insn "cbranchhi4_virt_signed" + [(set (pc) (if_then_else + (match_operator 0 "rl78_cmp_operator_signed" + [(match_operand:HI 1 "general_operand" "vim") + (match_operand:HI 2 "nonmemory_operand" "vi")]) + (label_ref (match_operand 3 "" "")) + (pc)))] + "rl78_virt_insns_ok ()" + "v.cmpw\t%1, %2\\n\tv.b%c0\t%3" + [(set_attr "valloc" "cmp")] + ) + (define_insn "*cbranchhi4_virt" [(set (pc) (if_then_else (match_operator 0 "rl78_cmp_operator_real" @@ -226,6 +360,20 @@ [(set_attr "valloc" "cmp")] ) +(define_insn "cbranchsi4_virt" + [(set (pc) (if_then_else + (match_operator 0 "rl78_cmp_operator" + [(match_operand:SI 1 "general_operand" "vim") + (match_operand:SI 2 "nonmemory_operand" "vi")]) + (label_ref (match_operand 3 "" "")) + (pc))) + (clobber (reg:HI AX_REG)) + ] + "rl78_virt_insns_ok ()" + "v.cmpd\t%1, %2\\n\tv.b%c0\t%3" + [(set_attr "valloc" "macax")] + ) + ;;---------- Peepholes ------------------------ (define_peephole2 diff --git a/gcc/config/rl78/rl78.c b/gcc/config/rl78/rl78.c index d7cacc16352..cd9010ab190 100644 --- a/gcc/config/rl78/rl78.c +++ b/gcc/config/rl78/rl78.c @@ -50,6 +50,8 @@ #include "dumpfile.h" #include "tree-pass.h" #include "context.h" +#include "tm-constrs.h" /* for satisfies_constraint_*(). */ +#include "insn-flags.h" /* for gen_*(). */ static inline bool is_interrupt_func (const_tree decl); static inline bool is_brk_interrupt_func (const_tree decl); @@ -168,6 +170,86 @@ make_pass_rl78_devirt (gcc::context *ctxt) return new pass_rl78_devirt (ctxt); } +static unsigned int +move_elim_pass (void) +{ + rtx insn, ninsn, prev = NULL_RTX; + + for (insn = get_insns (); insn; insn = ninsn) + { + rtx set; + + ninsn = next_nonnote_nondebug_insn (insn); + + if ((set = single_set (insn)) == NULL_RTX) + { + prev = NULL_RTX; + continue; + } + + /* If we have two SET insns in a row (without anything + between them) and the source of the second one is the + destination of the first one, and vice versa, then we + can eliminate the second SET. */ + if (prev + && rtx_equal_p (SET_DEST (prev), SET_SRC (set)) + && rtx_equal_p (SET_DEST (set), SET_SRC (prev)) + ) + { + if (dump_file) + fprintf (dump_file, " Delete insn %d because it is redundant\n", + INSN_UID (insn)); + + delete_insn (insn); + prev = NULL_RTX; + } + else + prev = set; + } + + if (dump_file) + print_rtl_with_bb (dump_file, get_insns (), 0); + + return 0; +} + +namespace { + +const pass_data pass_data_rl78_move_elim = +{ + RTL_PASS, /* type */ + "move_elim", /* name */ + OPTGROUP_NONE, /* optinfo_flags */ + true, /* has_gate */ + true, /* has_execute */ + TV_MACH_DEP, /* tv_id */ + 0, /* properties_required */ + 0, /* properties_provided */ + 0, /* properties_destroyed */ + 0, /* todo_flags_start */ + 0, /* todo_flags_finish */ +}; + +class pass_rl78_move_elim : public rtl_opt_pass +{ +public: + pass_rl78_move_elim(gcc::context *ctxt) + : rtl_opt_pass(pass_data_rl78_move_elim, ctxt) + { + } + + /* opt_pass methods: */ + bool gate () { return devirt_gate (); } + unsigned int execute () { return move_elim_pass (); } +}; + +} // anon namespace + +rtl_opt_pass * +make_pass_rl78_move_elim (gcc::context *ctxt) +{ + return new pass_rl78_move_elim (ctxt); +} #undef TARGET_ASM_FILE_START #define TARGET_ASM_FILE_START rl78_asm_file_start @@ -184,15 +266,25 @@ rl78_asm_file_start (void) } opt_pass *rl78_devirt_pass = make_pass_rl78_devirt (g); - struct register_pass_info rl78_devirt_info = + static struct register_pass_info rl78_devirt_info = { rl78_devirt_pass, - "vartrack", + "pro_and_epilogue", 1, PASS_POS_INSERT_BEFORE }; + opt_pass *rl78_move_elim_pass = make_pass_rl78_move_elim (g); + static struct register_pass_info rl78_move_elim_info = + { + rl78_move_elim_pass, + "bbro", + 1, + PASS_POS_INSERT_AFTER + }; + register_pass (& rl78_devirt_info); + register_pass (& rl78_move_elim_info); } @@ -332,6 +424,46 @@ rl78_expand_movsi (rtx *operands) } } +void +rl78_split_movsi (rtx *operands) +{ + rtx op00, op02, op10, op12; + + op00 = rl78_subreg (HImode, operands[0], SImode, 0); + op02 = rl78_subreg (HImode, operands[0], SImode, 2); + if (GET_CODE (operands[1]) == CONST + || GET_CODE (operands[1]) == SYMBOL_REF) + { + op10 = gen_rtx_ZERO_EXTRACT (HImode, operands[1], GEN_INT (16), GEN_INT (0)); + op10 = gen_rtx_CONST (HImode, op10); + op12 = gen_rtx_ZERO_EXTRACT (HImode, operands[1], GEN_INT (16), GEN_INT (16)); + op12 = gen_rtx_CONST (HImode, op12); + } + else + { + op10 = rl78_subreg (HImode, operands[1], SImode, 0); + op12 = rl78_subreg (HImode, operands[1], SImode, 2); + } + + if (rtx_equal_p (operands[0], operands[1])) + ; + else if (rtx_equal_p (op00, op12)) + { + operands[2] = op02; + operands[4] = op12; + operands[3] = op00; + operands[5] = op10; + } + else + { + operands[2] = op00; + operands[4] = op10; + operands[3] = op02; + operands[5] = op12; + } +} + + /* Used by various two-operand expanders which cannot accept all operands in the "far" namespace. Force some such operands into registers so that each pattern has at most one far operand. */ @@ -646,11 +778,11 @@ rl78_hl_b_c_addr_p (rtx op) int rl78_far_p (rtx x) { - if (GET_CODE (x) != MEM) + if (! MEM_P (x)) return 0; #if DEBUG0 - fprintf(stderr, "\033[35mrl78_far_p: "); debug_rtx(x); - fprintf(stderr, " = %d\033[0m\n", MEM_ADDR_SPACE (x) == ADDR_SPACE_FAR); + fprintf (stderr, "\033[35mrl78_far_p: "); debug_rtx(x); + fprintf (stderr, " = %d\033[0m\n", MEM_ADDR_SPACE (x) == ADDR_SPACE_FAR); #endif return MEM_ADDR_SPACE (x) == ADDR_SPACE_FAR; } @@ -744,6 +876,10 @@ rl78_as_legitimate_address (enum machine_mode mode ATTRIBUTE_UNUSED, rtx x, if (strict && base && GET_CODE (base) == REG && REGNO (base) >= FIRST_PSEUDO_REGISTER) return false; + if (! cfun->machine->virt_insns_ok && base && GET_CODE (base) == REG + && REGNO (base) >= 8 && REGNO (base) <= 31) + return false; + return true; } @@ -789,8 +925,6 @@ rl78_addr_space_convert (rtx op, tree from_type, tree to_type) { /* This always works. */ result = gen_reg_rtx (SImode); - debug_rtx(result); - debug_rtx(op); emit_move_insn (rl78_subreg (HImode, result, SImode, 0), op); emit_move_insn (rl78_subreg (HImode, result, SImode, 2), const0_rtx); return result; @@ -998,7 +1132,7 @@ rl78_start_function (FILE *file, HOST_WIDE_INT hwi_local ATTRIBUTE_UNUSED) for (i = 0; i < 16; i ++) if (cfun->machine->need_to_push[i]) fprintf (file, " %s", word_regnames[i*2]); - fprintf(file, "\n"); + fprintf (file, "\n"); } if (frame_pointer_needed) @@ -1094,12 +1228,17 @@ rl78_function_arg_boundary (enum machine_mode mode ATTRIBUTE_UNUSED, v - real register corresponding to a virtual register m - minus - negative of CONST_INT value. c - inverse of a conditional (NE vs EQ for example) + z - collapsed conditional + s - shift count mod 8 + S - shift count mod 16 + r - reverse shift count (8-(count mod 8)) h - bottom HI of an SI H - top HI of an SI q - bottom QI of an HI Q - top QI of an HI e - third QI of an SI (i.e. where the ES register gets values from) + E - fourth QI of an SI (i.e. MSB) */ @@ -1120,7 +1259,7 @@ rl78_print_operand_1 (FILE * file, rtx op, int letter) else { if (rl78_far_p (op)) - fprintf(file, "es:"); + fprintf (file, "es:"); if (letter == 'H') { op = adjust_address (op, HImode, 2); @@ -1146,15 +1285,20 @@ rl78_print_operand_1 (FILE * file, rtx op, int letter) op = adjust_address (op, QImode, 2); letter = 0; } + if (letter == 'E') + { + op = adjust_address (op, QImode, 3); + letter = 0; + } if (CONSTANT_P (XEXP (op, 0))) { - fprintf(file, "!"); + fprintf (file, "!"); rl78_print_operand_1 (file, XEXP (op, 0), letter); } else if (GET_CODE (XEXP (op, 0)) == PLUS && GET_CODE (XEXP (XEXP (op, 0), 0)) == SYMBOL_REF) { - fprintf(file, "!"); + fprintf (file, "!"); rl78_print_operand_1 (file, XEXP (op, 0), letter); } else if (GET_CODE (XEXP (op, 0)) == PLUS @@ -1162,15 +1306,15 @@ rl78_print_operand_1 (FILE * file, rtx op, int letter) && REGNO (XEXP (XEXP (op, 0), 0)) == 2) { rl78_print_operand_1 (file, XEXP (XEXP (op, 0), 1), 'u'); - fprintf(file, "["); + fprintf (file, "["); rl78_print_operand_1 (file, XEXP (XEXP (op, 0), 0), 0); - fprintf(file, "]"); + fprintf (file, "]"); } else { - fprintf(file, "["); + fprintf (file, "["); rl78_print_operand_1 (file, XEXP (op, 0), letter); - fprintf(file, "]"); + fprintf (file, "]"); } } break; @@ -1184,6 +1328,8 @@ rl78_print_operand_1 (FILE * file, rtx op, int letter) fprintf (file, "%s", reg_names [REGNO (op) & ~1]); else if (letter == 'e') fprintf (file, "%s", reg_names [REGNO (op) + 2]); + else if (letter == 'E') + fprintf (file, "%s", reg_names [REGNO (op) + 3]); else if (letter == 'S') fprintf (file, "0x%x", 0xffef8 + REGNO (op)); else if (GET_MODE (op) == HImode @@ -1209,10 +1355,20 @@ rl78_print_operand_1 (FILE * file, rtx op, int letter) fprintf (file, "%ld", INTVAL (op) & 0xffff); else if (letter == 'e') fprintf (file, "%ld", (INTVAL (op) >> 16) & 0xff); + else if (letter == 'E') + fprintf (file, "%ld", (INTVAL (op) >> 24) & 0xff); else if (letter == 'm') fprintf (file, "%ld", - INTVAL (op)); + else if (letter == 's') + fprintf (file, "%ld", INTVAL (op) % 8); + else if (letter == 'S') + fprintf (file, "%ld", INTVAL (op) % 16); + else if (letter == 'r') + fprintf (file, "%ld", 8 - (INTVAL (op) % 8)); + else if (letter == 'C') + fprintf (file, "%ld", (INTVAL (op) ^ 0x8000) & 0xffff); else - fprintf(file, "%ld", INTVAL (op)); + fprintf (file, "%ld", INTVAL (op)); break; case CONST: @@ -1316,22 +1472,68 @@ rl78_print_operand_1 (FILE * file, rtx op, int letter) break; case LTU: - fprintf (file, letter == 'c' ? "nc" : "c"); + if (letter == 'z') + fprintf (file, "#comparison eliminated"); + else + fprintf (file, letter == 'c' ? "nc" : "c"); break; case LEU: - fprintf (file, letter == 'c' ? "h" : "nh"); + if (letter == 'z') + fprintf (file, "br"); + else + fprintf (file, letter == 'c' ? "h" : "nh"); break; case GEU: - fprintf (file, letter == 'c' ? "c" : "nc"); + if (letter == 'z') + fprintf (file, "br"); + else + fprintf (file, letter == 'c' ? "c" : "nc"); break; case GTU: - fprintf (file, letter == 'c' ? "nh" : "h"); + if (letter == 'z') + fprintf (file, "#comparison eliminated"); + else + fprintf (file, letter == 'c' ? "nh" : "h"); break; case EQ: - fprintf (file, letter == 'c' ? "nz" : "z"); + if (letter == 'z') + fprintf (file, "br"); + else + fprintf (file, letter == 'c' ? "nz" : "z"); break; case NE: - fprintf (file, letter == 'c' ? "z" : "nz"); + if (letter == 'z') + fprintf (file, "#comparison eliminated"); + else + fprintf (file, letter == 'c' ? "z" : "nz"); + break; + + /* Note: these assume appropriate adjustments were made so that + unsigned comparisons, which is all this chip has, will + work. */ + case LT: + if (letter == 'z') + fprintf (file, "#comparison eliminated"); + else + fprintf (file, letter == 'c' ? "nc" : "c"); + break; + case LE: + if (letter == 'z') + fprintf (file, "br"); + else + fprintf (file, letter == 'c' ? "h" : "nh"); + break; + case GE: + if (letter == 'z') + fprintf (file, "br"); + else + fprintf (file, letter == 'c' ? "c" : "nc"); + break; + case GT: + if (letter == 'z') + fprintf (file, "#comparison eliminated"); + else + fprintf (file, letter == 'c' ? "nh" : "h"); break; default: @@ -1346,7 +1548,7 @@ rl78_print_operand_1 (FILE * file, rtx op, int letter) static void rl78_print_operand (FILE * file, rtx op, int letter) { - if (CONSTANT_P (op) && letter != 'u') + if (CONSTANT_P (op) && letter != 'u' && letter != 's' && letter != 'r' && letter != 'S') fprintf (file, "#"); rl78_print_operand_1 (file, op, letter); } @@ -1391,66 +1593,8 @@ rl78_trampoline_adjust_address (rtx m_tramp) void rl78_expand_compare (rtx *operands) { - /* RL78 does not have signed comparisons. We must modify the - operands to be in the unsigned range, and emit an unsigned - comparison. */ - - enum machine_mode mode; - rtx high_bit; - int i; - RTX_CODE new_cond; - - switch (GET_CODE (operands[0])) - { - case GE: - new_cond = GEU; - break; - case LE: - new_cond = LEU; - break; - case GT: - new_cond = GTU; - break; - case LT: - new_cond = LTU; - break; - default: - return; - } - -#if DEBUG0 - fprintf (stderr, "\033[38;5;129mrl78_expand_compare\n"); - debug_rtx (operands[0]); - fprintf (stderr, "\033[0m"); -#endif - - mode = GET_MODE (operands[1]); - if (mode == VOIDmode) - mode = GET_MODE (operands[2]); - high_bit = GEN_INT (~0 << (GET_MODE_BITSIZE (mode) - 1)); - - /* 0: conditional 1,2: operands */ - for (i = 1; i <= 2; i ++) - { - rtx r = operands[i]; - - if (GET_CODE (r) == CONST_INT) - r = GEN_INT (INTVAL (r) ^ INTVAL (high_bit)); - else - { - r = gen_rtx_PLUS (mode, operands[i], high_bit); - r = copy_to_mode_reg (mode, r); - } - operands[i] = r; - } - - operands[0] = gen_rtx_fmt_ee (new_cond, GET_MODE (operands[0]), operands[1], operands[2]); - -#if DEBUG0 - fprintf (stderr, "\033[38;5;142mrl78_expand_compare\n"); - debug_rtx (operands[0]); - fprintf (stderr, "\033[0m"); -#endif + if (GET_CODE (operands[2]) == MEM) + operands[2] = copy_to_mode_reg (GET_MODE (operands[2]), operands[2]); } @@ -1473,10 +1617,10 @@ rl78_peep_movhi_p (rtx *operands) #if DEBUG_PEEP fprintf (stderr, "\033[33m"); - debug_rtx(operands[0]); - debug_rtx(operands[1]); - debug_rtx(operands[2]); - debug_rtx(operands[3]); + debug_rtx (operands[0]); + debug_rtx (operands[1]); + debug_rtx (operands[2]); + debug_rtx (operands[3]); fprintf (stderr, "\033[0m"); #endif @@ -1662,14 +1806,242 @@ re-run regmove, but that has not yet been attempted. */ #define DEBUG_ALLOC 0 +/* This array is used to hold knowledge about the contents of the + real registers (A ... H), the memory-based registers (r8 ... r31) + and the first NUM_STACK_LOCS words on the stack. We use this to + avoid generating redundant move instructions. + + A value in the range 0 .. 31 indicates register A .. r31. + A value in the range 32 .. 63 indicates stack slot (value - 32). + A value of NOT_KNOWN indicates that the contents of that location + are not known. */ + +#define NUM_STACK_LOCS 32 +#define NOT_KNOWN 127 + +static unsigned char content_memory [32 + NUM_STACK_LOCS]; + +static unsigned char saved_update_index = NOT_KNOWN; +static unsigned char saved_update_value; +static enum machine_mode saved_update_mode; + + +static inline void +clear_content_memory (void) +{ + memset (content_memory, NOT_KNOWN, sizeof content_memory); + if (dump_file) + fprintf (dump_file, " clear content memory\n"); + saved_update_index = NOT_KNOWN; +} + +/* Convert LOC into an index into the content_memory array. + If LOC cannot be converted, return NOT_KNOWN. */ + +static unsigned char +get_content_index (rtx loc) +{ + enum machine_mode mode; + + if (loc == NULL_RTX) + return NOT_KNOWN; + + if (REG_P (loc)) + { + if (REGNO (loc) < 32) + return REGNO (loc); + return NOT_KNOWN; + } + + mode = GET_MODE (loc); + + if (! rl78_stack_based_mem (loc, mode)) + return NOT_KNOWN; + + loc = XEXP (loc, 0); + + if (REG_P (loc)) + /* loc = MEM (SP) */ + return 32; + + /* loc = MEM (PLUS (SP, INT)). */ + loc = XEXP (loc, 1); + + if (INTVAL (loc) < NUM_STACK_LOCS) + return 32 + INTVAL (loc); + + return NOT_KNOWN; +} + +/* Return a string describing content INDEX in mode MODE. + WARNING: Can return a pointer to a static buffer. */ + +static const char * +get_content_name (unsigned char index, enum machine_mode mode) +{ + static char buffer [128]; + + if (index == NOT_KNOWN) + return "Unknown"; + + if (index > 31) + sprintf (buffer, "stack slot %d", index - 32); + else if (mode == HImode) + sprintf (buffer, "%s%s", + reg_names [index + 1], reg_names [index]); + else + return reg_names [index]; + + return buffer; +} + +#if DEBUG_ALLOC + +static void +display_content_memory (FILE * file) +{ + unsigned int i; + + fprintf (file, " Known memory contents:\n"); + + for (i = 0; i < sizeof content_memory; i++) + if (content_memory[i] != NOT_KNOWN) + { + fprintf (file, " %s contains a copy of ", get_content_name (i, QImode)); + fprintf (file, "%s\n", get_content_name (content_memory [i], QImode)); + } +} +#endif + +static void +update_content (unsigned char index, unsigned char val, enum machine_mode mode) +{ + unsigned int i; + + gcc_assert (index < sizeof content_memory); + + content_memory [index] = val; + if (val != NOT_KNOWN) + content_memory [val] = index; + + /* Make the entry in dump_file *before* VAL is increased below. */ + if (dump_file) + { + fprintf (dump_file, " %s now contains ", get_content_name (index, mode)); + if (val == NOT_KNOWN) + fprintf (dump_file, "Unknown\n"); + else + fprintf (dump_file, "%s and vice versa\n", get_content_name (val, mode)); + } + + if (mode == HImode) + { + val = val == NOT_KNOWN ? val : val + 1; + + content_memory [index + 1] = val; + if (val != NOT_KNOWN) + { + content_memory [val] = index + 1; + -- val; + } + } + + /* Any other places that had INDEX recorded as their contents are now invalid. */ + for (i = 0; i < sizeof content_memory; i++) + { + if (i == index + || (val != NOT_KNOWN && i == val)) + { + if (mode == HImode) + ++ i; + continue; + } + + if (content_memory[i] == index + || (val != NOT_KNOWN && content_memory[i] == val)) + { + content_memory[i] = NOT_KNOWN; + + if (dump_file) + fprintf (dump_file, " %s cleared\n", get_content_name (i, mode)); + + if (mode == HImode) + content_memory[++ i] = NOT_KNOWN; + } + } +} + +/* Record that LOC contains VALUE. + For HImode locations record that LOC+1 contains VALUE+1. + If LOC is not a register or stack slot, do nothing. + If VALUE is not a register or stack slot, clear the recorded content. */ + +static void +record_content (rtx loc, rtx value) +{ + enum machine_mode mode; + unsigned char index; + unsigned char val; + + if ((index = get_content_index (loc)) == NOT_KNOWN) + return; + + val = get_content_index (value); + + mode = GET_MODE (loc); + + if (val == index) + { + if (! optimize) + return; + + /* This should not happen when optimizing. */ +#if 1 + fprintf (stderr, "ASSIGNMENT of location to itself detected! [%s]\n", + get_content_name (val, mode)); + return; +#else + gcc_unreachable (); +#endif + } + + update_content (index, val, mode); +} + +/* Returns TRUE if LOC already contains a copy of VALUE. */ + +static bool +already_contains (rtx loc, rtx value) +{ + unsigned char index; + unsigned char val; + + if ((index = get_content_index (loc)) == NOT_KNOWN) + return false; + + if ((val = get_content_index (value)) == NOT_KNOWN) + return false; + + if (content_memory [index] != val) + return false; + + if (GET_MODE (loc) == HImode) + return content_memory [index + 1] == val + 1; + + return true; +} + /* Rescans an insn to see if it's recognized again. This is done carefully to ensure that all the constraint information is accurate for the newly matched insn. */ static bool insn_ok_now (rtx insn) { + rtx pattern = PATTERN (insn); + INSN_CODE (insn) = -1; - if (recog (PATTERN (insn), insn, 0) > -1) + + if (recog (pattern, insn, 0) > -1) { extract_insn (insn); if (constrain_operands (1)) @@ -1679,15 +2051,34 @@ insn_ok_now (rtx insn) debug_rtx (insn); fprintf (stderr, "\033[0m"); #endif + if (SET_P (pattern)) + record_content (SET_DEST (pattern), SET_SRC (pattern)); + return true; } } else { - fprintf (stderr, "\033[41;30m Unrecognized insn \033[0m\n"); + /* We need to re-recog the insn with virtual registers to get + the operands */ + cfun->machine->virt_insns_ok = 1; + if (recog (pattern, insn, 0) > -1) + { + extract_insn (insn); + if (constrain_operands (0)) + { + cfun->machine->virt_insns_ok = 0; + return false; + } + } + +#if DEBUG_ALLOC + fprintf (stderr, "\033[41;30m Unrecognized *virtual* insn \033[0m\n"); debug_rtx (insn); +#endif gcc_unreachable (); } + #if DEBUG_ALLOC fprintf (stderr, "\033[31m"); debug_rtx (insn); @@ -1697,15 +2088,15 @@ insn_ok_now (rtx insn) } #if DEBUG_ALLOC -#define WORKED fprintf (stderr, "\033[48;5;22m Worked at line %d \033[0m\n", __LINE__) +#define WORKED fprintf (stderr, "\033[48;5;22m Worked at line %d \033[0m\n", __LINE__) #define FAILEDSOFAR fprintf (stderr, "\033[48;5;52m FAILED at line %d \033[0m\n", __LINE__) -#define FAILED fprintf (stderr, "\033[48;5;52m FAILED at line %d \033[0m\n", __LINE__), gcc_unreachable() +#define FAILED fprintf (stderr, "\033[48;5;52m FAILED at line %d \033[0m\n", __LINE__), gcc_unreachable() #define MAYBE_OK(insn) if (insn_ok_now (insn)) { WORKED; return; } else { FAILEDSOFAR; } +#define MUST_BE_OK(insn) if (insn_ok_now (insn)) { WORKED; return; } FAILED #else -#define WORKED -#define FAILEDSOFAR #define FAILED gcc_unreachable () #define MAYBE_OK(insn) if (insn_ok_now (insn)) return; +#define MUST_BE_OK(insn) if (insn_ok_now (insn)) return; FAILED #endif /* Registers into which we move the contents of virtual registers. */ @@ -1787,16 +2178,95 @@ rl78_hi8 (rtx addr) return rl78_subreg (QImode, addr, SImode, 2); } -/* Copy any register values into real registers and return an RTX for - the same memory, now addressed by real registers. Any needed insns - are emitted before BEFORE. */ +static void +add_postponed_content_update (rtx to, rtx value) +{ + unsigned char index; + + if ((index = get_content_index (to)) == NOT_KNOWN) + return; + + gcc_assert (saved_update_index == NOT_KNOWN); + saved_update_index = index; + saved_update_value = get_content_index (value); + saved_update_mode = GET_MODE (to); +} + +static void +process_postponed_content_update (void) +{ + if (saved_update_index != NOT_KNOWN) + { + update_content (saved_update_index, saved_update_value, saved_update_mode); + saved_update_index = NOT_KNOWN; + } +} + +/* Generate and emit a move of (register) FROM into TO. if WHERE is not NULL + then if BEFORE is true then emit the insn before WHERE, otherwise emit it + after WHERE. If TO already contains FROM then do nothing. Returns TO if + BEFORE is true, FROM otherwise. */ +static rtx +gen_and_emit_move (rtx to, rtx from, rtx where, bool before) +{ + enum machine_mode mode = GET_MODE (to); + + if (optimize && before && already_contains (to, from)) + { +#if DEBUG_ALLOC + display_content_memory (stderr); +#endif + if (dump_file) + { + fprintf (dump_file, " Omit move of %s into ", + get_content_name (get_content_index (from), mode)); + fprintf (dump_file, "%s as it already contains this value\n", + get_content_name (get_content_index (to), mode)); + } + } + else + { + rtx move = mode == QImode ? gen_movqi (to, from) : gen_movhi (to, from); + + EM (move); + + if (where == NULL_RTX) + emit_insn (move); + else if (before) + emit_insn_before (move, where); + else + { + rtx note = find_reg_note (where, REG_EH_REGION, NULL_RTX); + + /* If necessary move REG_EH_REGION notes forward. + cf. compiling gcc.dg/pr44545.c. */ + if (note != NULL_RTX) + { + add_reg_note (move, REG_EH_REGION, XEXP (note, 0)); + remove_note (where, note); + } + + emit_insn_after (move, where); + } + + if (before) + record_content (to, from); + else + add_postponed_content_update (to, from); + } + return before ? to : from; +} + +/* If M is MEM(REG) or MEM(PLUS(REG,INT)) and REG is virtual then + copy it into NEWBASE and return the updated MEM. Otherwise just + return M. Any needed insns are emitted before BEFORE. */ static rtx transcode_memory_rtx (rtx m, rtx newbase, rtx before) { rtx base, index, addendr; int addend = 0; - if (GET_CODE (m) != MEM) + if (! MEM_P (m)) return m; if (GET_MODE (XEXP (m, 0)) == SImode) @@ -1806,16 +2276,18 @@ transcode_memory_rtx (rtx m, rtx newbase, rtx before) fprintf (stderr, "setting ES:\n"); debug_rtx(seg); #endif - emit_insn_before (EM(gen_movqi (A, seg)), before); - emit_insn_before (EM(gen_movqi_es (A)), before); + emit_insn_before (EM (gen_movqi (A, seg)), before); + emit_insn_before (EM (gen_movqi_es (A)), before); + record_content (A, NULL_RTX); + m = change_address (m, GET_MODE (m), rl78_lo16 (XEXP (m, 0))); } - characterize_address (XEXP (m, 0), &base, &index, &addendr); + characterize_address (XEXP (m, 0), & base, & index, & addendr); gcc_assert (index == NULL_RTX); #if DEBUG_ALLOC - fprintf (stderr, "\033[33m"); debug_rtx(m); fprintf (stderr, "\033[0m"); + fprintf (stderr, "\033[33m"); debug_rtx (m); fprintf (stderr, "\033[0m"); debug_rtx (base); #endif if (base == NULL_RTX) @@ -1824,6 +2296,9 @@ transcode_memory_rtx (rtx m, rtx newbase, rtx before) if (addendr && GET_CODE (addendr) == CONST_INT) addend = INTVAL (addendr); + gcc_assert (REG_P (base)); + gcc_assert (REG_P (newbase)); + if (REGNO (base) == SP_REG) { if (addend >= 0 && addend <= 255) @@ -1844,17 +2319,22 @@ transcode_memory_rtx (rtx m, rtx newbase, rtx before) EM (emit_insn_before (gen_movhi (AX, base), before)); EM (emit_insn_before (gen_addhi3 (AX, AX, addendr), before)); EM (emit_insn_before (gen_movhi (newbase, AX), before)); + record_content (AX, NULL_RTX); + record_content (newbase, NULL_RTX); + base = newbase; addend = 0; } else { - EM (emit_insn_before (gen_movhi (newbase, base), before)); - base = newbase; + base = gen_and_emit_move (newbase, base, before, true); } if (addend) - base = gen_rtx_PLUS (HImode, base, GEN_INT (addend)); + { + record_content (base, NULL_RTX); + base = gen_rtx_PLUS (HImode, base, GEN_INT (addend)); + } #if DEBUG_ALLOC fprintf (stderr, "\033[33m"); @@ -1874,49 +2354,48 @@ transcode_memory_rtx (rtx m, rtx newbase, rtx before) static rtx move_to_acc (int opno, rtx before) { - rtx src = OP(opno); + rtx src = OP (opno); enum machine_mode mode = GET_MODE (src); - if (GET_CODE (src) == REG - && REGNO (src) < 2) + if (REG_P (src) && REGNO (src) < 2) return src; if (mode == VOIDmode) mode = recog_data.operand_mode[opno]; - if (mode == QImode) - { - EM (emit_insn_before (gen_movqi (A, src), before)); - return A; - } - else - { - EM (emit_insn_before (gen_movhi (AX, src), before)); - return AX; - } + return gen_and_emit_move (mode == QImode ? A : AX, src, before, true); +} + +static void +force_into_acc (rtx src, rtx before) +{ + enum machine_mode mode = GET_MODE (src); + rtx move; + + if (REG_P (src) && REGNO (src) < 2) + return; + + move = mode == QImode ? gen_movqi (A, src) : gen_movhi (AX, src); + + EM (move); + + emit_insn_before (move, before); + record_content (AX, NULL_RTX); } /* Copy accumulator (A or AX) to DEST, placing any generated insns after AFTER. Returns accumulator RTX. */ static rtx -move_from_acc (rtx dest, rtx after) +move_from_acc (unsigned int opno, rtx after) { + rtx dest = OP (opno); enum machine_mode mode = GET_MODE (dest); if (REG_P (dest) && REGNO (dest) < 2) return dest; - if (mode == QImode) - { - EM (emit_insn_after (gen_movqi (dest, A), after)); - return A; - } - else - { - EM (emit_insn_after (gen_movhi (dest, AX), after)); - return AX; - } + return gen_and_emit_move (dest, mode == QImode ? A : AX, after, false); } /* Copy accumulator (A or AX) to REGNO, placing any generated insns @@ -1930,16 +2409,7 @@ move_acc_to_reg (rtx acc, int regno, rtx before) reg = gen_rtx_REG (mode, regno); - if (mode == QImode) - { - EM (emit_insn_before (gen_movqi (reg, A), before)); - return reg; - } - else - { - EM (emit_insn_before (gen_movhi (reg, AX), before)); - return reg; - } + return gen_and_emit_move (reg, acc, before, true); } /* Copy SRC to X, placing any generated insns before BEFORE. @@ -1948,7 +2418,7 @@ move_acc_to_reg (rtx acc, int regno, rtx before) static rtx move_to_x (int opno, rtx before) { - rtx src = OP(opno); + rtx src = OP (opno); enum machine_mode mode = GET_MODE (src); rtx reg; @@ -1958,17 +2428,12 @@ move_to_x (int opno, rtx before) if (mode == QImode || ! is_virtual_register (OP (opno))) { - OP(opno) = move_to_acc (opno, before); - OP(opno) = move_acc_to_reg (OP(opno), X_REG, before); + OP (opno) = move_to_acc (opno, before); + OP (opno) = move_acc_to_reg (OP(opno), X_REG, before); return reg; } - if (mode == QImode) - EM (emit_insn_before (gen_movqi (reg, src), before)); - else - EM (emit_insn_before (gen_movhi (reg, src), before)); - - return reg; + return gen_and_emit_move (reg, src, before, true); } /* Copy OP(opno) to H or HL, placing any generated insns before BEFORE. @@ -1992,12 +2457,7 @@ move_to_hl (int opno, rtx before) return reg; } - if (mode == QImode) - EM (emit_insn_before (gen_movqi (reg, src), before)); - else - EM (emit_insn_before (gen_movhi (reg, src), before)); - - return reg; + return gen_and_emit_move (reg, src, before, true); } /* Copy OP(opno) to E or DE, placing any generated insns before BEFORE. @@ -2022,9 +2482,7 @@ move_to_de (int opno, rtx before) } else { - rtx move = mode == QImode ? gen_movqi (reg, src) : gen_movhi (reg, src); - - EM (emit_insn_before (move, before)); + gen_and_emit_move (reg, src, before, true); } return reg; @@ -2038,63 +2496,104 @@ rl78_alloc_physical_registers_op1 (rtx insn) /* We first try using A as the destination, then copying it back. */ - if (rtx_equal_p (OP(0), OP(1))) + if (rtx_equal_p (OP (0), OP (1))) { - OP(0) = - OP(1) = transcode_memory_rtx (OP(1), DE, insn); + OP (0) = + OP (1) = transcode_memory_rtx (OP (1), DE, insn); } else { - OP(0) = transcode_memory_rtx (OP(0), BC, insn); - OP(1) = transcode_memory_rtx (OP(1), HL, insn); + /* If necessary, load the operands into BC and HL. + Check to see if we already have OP (0) in HL + and if so, swap the order. */ + if (MEM_P (OP (0)) + && already_contains (HL, XEXP (OP (0), 0))) + { + OP (0) = transcode_memory_rtx (OP (0), HL, insn); + OP (1) = transcode_memory_rtx (OP (1), BC, insn); + } + else + { + OP (0) = transcode_memory_rtx (OP (0), BC, insn); + OP (1) = transcode_memory_rtx (OP (1), HL, insn); + } } MAYBE_OK (insn); - OP(0) = move_from_acc (OP(0), insn); + OP (0) = move_from_acc (0, insn); MAYBE_OK (insn); /* Try copying the src to acc first, then. This is for, for example, ZERO_EXTEND or NOT. */ - OP(1) = move_to_acc (1, insn); + OP (1) = move_to_acc (1, insn); - MAYBE_OK (insn); + MUST_BE_OK (insn); +} + +/* Returns true if operand OPNUM contains a constraint of type CONSTRAINT. + Assumes that the current insn has already been recognised and hence the + constraint data has been filled in. */ +static bool +has_constraint (unsigned int opnum, enum constraint_num constraint) +{ + const char * p = recog_data.constraints[opnum]; + + /* No constraints means anything is accepted. */ + if (p == NULL || *p == 0 || *p == ',') + return true; + + do + { + char c; + unsigned int len; - FAILED; + c = *p; + len = CONSTRAINT_LEN (c, p); + gcc_assert (len > 0); + + switch (c) + { + case 0: + case ',': + return false; + default: + if (lookup_constraint (p) == constraint) + return true; + } + p += len; + } + while (1); } -/* Devirtualize an insn of the form (SET (op) (unop (op) (op))). */ +/* Devirtualize an insn of the form (SET (op) (binop (op) (op))). */ static void rl78_alloc_physical_registers_op2 (rtx insn) { - /* op[0] = op[1] func op[2] */ - rtx prev = prev_nonnote_nondebug_insn (insn); + rtx prev; rtx first; bool hl_used; + int tmp_id; + rtx saved_op1; - if (rtx_equal_p (OP(0), OP(1))) + if (rtx_equal_p (OP (0), OP (1))) { - OP(0) = - OP(1) = transcode_memory_rtx (OP(1), DE, insn); - prev = next_nonnote_nondebug_insn (prev); - OP(2) = transcode_memory_rtx (OP(2), HL, insn); - prev = prev_nonnote_nondebug_insn (prev); + OP (0) = + OP (1) = transcode_memory_rtx (OP (1), DE, insn); + OP (2) = transcode_memory_rtx (OP (2), HL, insn); } - else if (rtx_equal_p (OP(0), OP(2))) + else if (rtx_equal_p (OP (0), OP (2))) { - OP(1) = transcode_memory_rtx (OP(1), DE, insn); - prev = next_nonnote_nondebug_insn (prev); - OP(0) = - OP(2) = transcode_memory_rtx (OP(2), HL, insn); - prev = prev_nonnote_nondebug_insn (prev); + OP (1) = transcode_memory_rtx (OP (1), DE, insn); + OP (0) = + OP (2) = transcode_memory_rtx (OP (2), HL, insn); } else { - OP(0) = transcode_memory_rtx (OP(0), BC, insn); - OP(1) = transcode_memory_rtx (OP(1), DE, insn); - prev = next_nonnote_nondebug_insn (prev); - OP(2) = transcode_memory_rtx (OP(2), HL, insn); + OP (0) = transcode_memory_rtx (OP (0), BC, insn); + OP (1) = transcode_memory_rtx (OP (1), DE, insn); + OP (2) = transcode_memory_rtx (OP (2), HL, insn); } MAYBE_OK (insn); @@ -2110,17 +2609,106 @@ rl78_alloc_physical_registers_op2 (rtx insn) OP (2) = tmp; } - /* Make a note of wether (H)L is being used. It matters - because if OP(2) alsoneeds reloading, then we must take + /* Make a note of whether (H)L is being used. It matters + because if OP (2) alsoneeds reloading, then we must take care not to corrupt HL. */ hl_used = reg_mentioned_p (L, OP (0)) || reg_mentioned_p (L, OP (1)); - OP(0) = move_from_acc (OP (0), insn); - OP(1) = move_to_acc (1, insn); + /* If HL is not currently being used and dest == op1 then there are + some possible optimizations available by reloading one of the + operands into HL, before trying to use the accumulator. */ + if (optimize + && ! hl_used + && rtx_equal_p (OP (0), OP (1))) + { + /* If op0 is a Ws1 type memory address then switching the base + address register to HL might allow us to perform an in-memory + operation. (eg for the INCW instruction). + + FIXME: Adding the move into HL is costly if this optimization is not + going to work, so for now, make sure that we know that the new insn will + match the requirements of the addhi3_real pattern. Really we ought to + generate a candidate sequence, test that, and then install it if the + results are good. */ + if (satisfies_constraint_Ws1 (OP (0)) + && has_constraint (0, CONSTRAINT_Wh1) + && (satisfies_constraint_K (OP (2)) || satisfies_constraint_L (OP (2)))) + { + rtx base, index, addend, newbase; + + characterize_address (XEXP (OP (0), 0), & base, & index, & addend); + gcc_assert (index == NULL_RTX); + gcc_assert (REG_P (base) && REGNO (base) == SP_REG); + + /* Ws1 addressing allows an offset of 0, Wh1 addressing requires a non-zero offset. */ + if (addend != NULL_RTX) + { + newbase = gen_and_emit_move (HL, base, insn, true); + record_content (newbase, NULL_RTX); + newbase = gen_rtx_PLUS (HImode, newbase, addend); + + OP (0) = OP (1) = change_address (OP (0), VOIDmode, newbase); + + /* We do not want to fail here as this means that + we have inserted useless insns into the stream. */ + MUST_BE_OK (insn); + } + } + else if (REG_P (OP (0)) + && satisfies_constraint_Ws1 (OP (2)) + && has_constraint (2, CONSTRAINT_Wh1)) + { + rtx base, index, addend, newbase; + + characterize_address (XEXP (OP (2), 0), & base, & index, & addend); + gcc_assert (index == NULL_RTX); + gcc_assert (REG_P (base) && REGNO (base) == SP_REG); + + /* Ws1 addressing allows an offset of 0, Wh1 addressing requires a non-zero offset. */ + if (addend != NULL_RTX) + { + gen_and_emit_move (HL, base, insn, true); + + if (REGNO (OP (0)) != X_REG) + { + OP (1) = move_to_acc (1, insn); + OP (0) = move_from_acc (0, insn); + } + + record_content (HL, NULL_RTX); + newbase = gen_rtx_PLUS (HImode, HL, addend); + + OP (2) = change_address (OP (2), VOIDmode, newbase); + + /* We do not want to fail here as this means that + we have inserted useless insns into the stream. */ + MUST_BE_OK (insn); + } + } + } + + + OP (0) = move_from_acc (0, insn); + + tmp_id = get_max_insn_count (); + saved_op1 = OP (1); + + if (rtx_equal_p (OP (1), OP (2))) + OP (2) = OP (1) = move_to_acc (1, insn); + else + OP (1) = move_to_acc (1, insn); MAYBE_OK (insn); - /* We have to copy op2 to HL, but that involves AX, which + /* If we omitted the move of OP1 into the accumulator (because + it was already there from a previous insn), then force the + generation of the move instruction now. We know that we + are about to emit a move into HL (or DE) via AX, and hence + our optimization to remove the load of OP1 is no longer valid. */ + if (tmp_id == get_max_insn_count ()) + force_into_acc (saved_op1, insn); + + /* We have to copy op2 to HL (or DE), but that involves AX, which already has a live value. Emit it before those insns. */ if (prev) @@ -2131,89 +2719,160 @@ rl78_alloc_physical_registers_op2 (rtx insn) OP (2) = hl_used ? move_to_de (2, first) : move_to_hl (2, first); - MAYBE_OK (insn); - - FAILED; + MUST_BE_OK (insn); } -/* Devirtualize an insn of the form (SET () (unop (op))). */ +/* Devirtualize an insn of the form SET (PC) (MEM/REG). */ static void rl78_alloc_physical_registers_ro1 (rtx insn) { - /* (void) op[0] */ - OP(0) = transcode_memory_rtx (OP(0), BC, insn); + OP (0) = transcode_memory_rtx (OP (0), BC, insn); MAYBE_OK (insn); - OP(0) = move_to_acc (0, insn); - - MAYBE_OK (insn); + OP (0) = move_to_acc (0, insn); - FAILED; + MUST_BE_OK (insn); } /* Devirtualize a compare insn. */ + static void rl78_alloc_physical_registers_cmp (rtx insn) { - /* op[1] cmp_op[0] op[2] */ + int tmp_id; + rtx saved_op1; rtx prev = prev_nonnote_nondebug_insn (insn); rtx first; - OP(1) = transcode_memory_rtx (OP(1), DE, insn); - OP(2) = transcode_memory_rtx (OP(2), HL, insn); + OP (1) = transcode_memory_rtx (OP (1), DE, insn); + OP (2) = transcode_memory_rtx (OP (2), HL, insn); + /* HI compares have to have OP(1) in AX, but QI + compares do not, so it is worth checking here. */ MAYBE_OK (insn); - OP(1) = move_to_acc (1, insn); + /* For an HImode compare, OP(1) must always be in AX. + But if OP(1) is a REG (and not AX), then we can avoid + a reload of OP(1) if we reload OP(2) into AX and invert + the comparison. */ + if (REG_P (OP (1)) + && REGNO (OP (1)) != AX_REG + && GET_MODE (OP (1)) == HImode + && MEM_P (OP (2))) + { + rtx cmp = XEXP (SET_SRC (PATTERN (insn)), 0); + + OP (2) = move_to_acc (2, insn); + + switch (GET_CODE (cmp)) + { + case EQ: + case NE: + break; + case LTU: cmp = gen_rtx_GTU (HImode, OP (2), OP (1)); break; + case GTU: cmp = gen_rtx_LTU (HImode, OP (2), OP (1)); break; + case LEU: cmp = gen_rtx_GEU (HImode, OP (2), OP (1)); break; + case GEU: cmp = gen_rtx_LEU (HImode, OP (2), OP (1)); break; + + case LT: + case GT: + case LE: + case GE: +#if DEBUG_ALLOC + debug_rtx (insn); +#endif + default: + gcc_unreachable (); + } + + if (GET_CODE (cmp) == EQ || GET_CODE (cmp) == NE) + PATTERN (insn) = gen_cbranchhi4_real (cmp, OP (2), OP (1), OP (3)); + else + PATTERN (insn) = gen_cbranchhi4_real_inverted (cmp, OP (2), OP (1), OP (3)); + + MUST_BE_OK (insn); + } + + /* Surprisingly, gcc can generate a comparison of a register with itself, but this + should be handled by the second alternative of the cbranchhi_real pattern. */ + if (rtx_equal_p (OP (1), OP (2))) + { + OP (1) = OP (2) = BC; + MUST_BE_OK (insn); + } + + tmp_id = get_max_insn_count (); + saved_op1 = OP (1); + + OP (1) = move_to_acc (1, insn); MAYBE_OK (insn); + /* If we omitted the move of OP1 into the accumulator (because + it was already there from a previous insn), then force the + generation of the move instruction now. We know that we + are about to emit a move into HL via AX, and hence our + optimization to remove the load of OP1 is no longer valid. */ + if (tmp_id == get_max_insn_count ()) + force_into_acc (saved_op1, insn); + /* We have to copy op2 to HL, but that involves the acc, which already has a live value. Emit it before those insns. */ - if (prev) first = next_nonnote_nondebug_insn (prev); else for (first = insn; prev_nonnote_nondebug_insn (first); first = prev_nonnote_nondebug_insn (first)) ; - OP(2) = move_to_hl (2, first); + OP (2) = move_to_hl (2, first); - MAYBE_OK (insn); - - FAILED; + MUST_BE_OK (insn); } /* Like op2, but AX = A op X. */ + static void rl78_alloc_physical_registers_umul (rtx insn) { - /* op[0] = op[1] func op[2] */ rtx prev = prev_nonnote_nondebug_insn (insn); rtx first; + int tmp_id; + rtx saved_op1; - OP(0) = transcode_memory_rtx (OP(0), BC, insn); - OP(1) = transcode_memory_rtx (OP(1), DE, insn); - OP(2) = transcode_memory_rtx (OP(2), HL, insn); + OP (0) = transcode_memory_rtx (OP (0), BC, insn); + OP (1) = transcode_memory_rtx (OP (1), DE, insn); + OP (2) = transcode_memory_rtx (OP (2), HL, insn); MAYBE_OK (insn); if (recog_data.constraints[1][0] == '%' - && is_virtual_register (OP(1)) - && !is_virtual_register (OP(2)) - && !CONSTANT_P (OP(2))) + && is_virtual_register (OP (1)) + && !is_virtual_register (OP (2)) + && !CONSTANT_P (OP (2))) { - rtx tmp = OP(1); - OP(1) = OP(2); - OP(2) = tmp; + rtx tmp = OP (1); + OP (1) = OP (2); + OP (2) = tmp; } - OP(0) = move_from_acc (OP(0), insn); - OP(1) = move_to_acc (1, insn); + OP (0) = move_from_acc (0, insn); + + tmp_id = get_max_insn_count (); + saved_op1 = OP (1); + + OP (1) = move_to_acc (1, insn); MAYBE_OK (insn); + /* If we omitted the move of OP1 into the accumulator (because + it was already there from a previous insn), then force the + generation of the move instruction now. We know that we + are about to emit a move into HL (or DE) via AX, and hence + our optimization to remove the load of OP1 is no longer valid. */ + if (tmp_id == get_max_insn_count ()) + force_into_acc (saved_op1, insn); + /* We have to copy op2 to X, but that involves the acc, which already has a live value. Emit it before those insns. */ @@ -2222,11 +2881,65 @@ rl78_alloc_physical_registers_umul (rtx insn) else for (first = insn; prev_nonnote_nondebug_insn (first); first = prev_nonnote_nondebug_insn (first)) ; - OP(2) = move_to_x (2, first); + OP (2) = move_to_x (2, first); + + MUST_BE_OK (insn); +} + +static void +rl78_alloc_address_registers_macax (rtx insn) +{ + int which, op; + bool replace_in_op0 = false; + bool replace_in_op1 = false; MAYBE_OK (insn); - FAILED; + /* Two different MEMs are not allowed. */ + which = 0; + for (op = 2; op >= 0; op --) + { + if (MEM_P (OP (op))) + { + if (op == 0 && replace_in_op0) + continue; + if (op == 1 && replace_in_op1) + continue; + + switch (which) + { + case 0: + /* If we replace a MEM, make sure that we replace it for all + occurrences of the same MEM in the insn. */ + replace_in_op0 = (op > 0 && rtx_equal_p (OP (op), OP (0))); + replace_in_op1 = (op > 1 && rtx_equal_p (OP (op), OP (1))); + + OP (op) = transcode_memory_rtx (OP (op), HL, insn); + if (op == 2 + && MEM_P (OP (op)) + && (REGNO (XEXP (OP (op), 0)) == SP_REG + || (GET_CODE (XEXP (OP (op), 0)) == PLUS + && REGNO (XEXP (XEXP (OP (op), 0), 0)) == SP_REG))) + { + emit_insn_before (gen_movhi (HL, gen_rtx_REG (HImode, SP_REG)), insn); + OP (op) = replace_rtx (OP (op), gen_rtx_REG (HImode, SP_REG), HL); + } + if (replace_in_op0) + OP (0) = OP (op); + if (replace_in_op1) + OP (1) = OP (op); + break; + case 1: + OP (op) = transcode_memory_rtx (OP (op), DE, insn); + break; + case 2: + OP (op) = transcode_memory_rtx (OP (op), BC, insn); + break; + } + which ++; + } + } + MUST_BE_OK (insn); } /* Scan all insns and devirtualize them. */ @@ -2266,23 +2979,46 @@ rl78_alloc_physical_registers (void) cfun->machine->virt_insns_ok = 0; cfun->machine->real_insns_ok = 1; + clear_content_memory (); + for (insn = get_insns (); insn; insn = curr) { + rtx pattern; + curr = insn ? next_nonnote_nondebug_insn (insn) : NULL; if (!INSN_P (insn)) - continue; - if (GET_CODE (PATTERN (insn)) != SET - && GET_CODE (PATTERN (insn)) != CALL) - continue; + { + if (LABEL_P (insn)) + clear_content_memory (); + + continue; + } - if (GET_CODE (PATTERN (insn)) == SET - && GET_CODE (SET_SRC (PATTERN (insn))) == ASM_OPERANDS) + if (dump_file) + fprintf (dump_file, "Converting insn %d\n", INSN_UID (insn)); + + pattern = PATTERN (insn); + if (GET_CODE (pattern) == PARALLEL) + pattern = XVECEXP (pattern, 0, 0); + if (JUMP_P (insn) || CALL_P (insn) || GET_CODE (pattern) == CALL) + clear_content_memory (); + if (GET_CODE (pattern) != SET + && GET_CODE (pattern) != CALL) + continue; + if (GET_CODE (SET_SRC (pattern)) == ASM_OPERANDS) continue; valloc_method = get_attr_valloc (insn); - PATTERN (insn)= copy_rtx_if_shared (PATTERN (insn)); + PATTERN (insn) = copy_rtx_if_shared (PATTERN (insn)); + + if (valloc_method == VALLOC_MACAX) + { + record_content (AX, NULL_RTX); + record_content (BC, NULL_RTX); + record_content (DE, NULL_RTX); + } if (insn_ok_now (insn)) continue; @@ -2312,9 +3048,18 @@ rl78_alloc_physical_registers (void) rl78_alloc_physical_registers_umul (insn); break; case VALLOC_MACAX: - /* Macro that clobbers AX */ + /* Macro that clobbers AX. */ + rl78_alloc_address_registers_macax (insn); + record_content (AX, NULL_RTX); + record_content (BC, NULL_RTX); + record_content (DE, NULL_RTX); break; } + + if (JUMP_P (insn) || CALL_P (insn) || GET_CODE (pattern) == CALL) + clear_content_memory (); + else + process_postponed_content_update (); } #if DEBUG_ALLOC fprintf (stderr, "\033[0m"); @@ -2426,7 +3171,7 @@ rl78_calculate_death_notes (void) fprintf (dump_file, "\nDead:"); for (i = 0; i < FIRST_PSEUDO_REGISTER; i ++) if (dead[i]) - fprintf(dump_file, " %s", reg_names[i]); + fprintf (dump_file, " %s", reg_names[i]); fprintf (dump_file, "\n"); print_rtl_single (dump_file, insn); } @@ -2651,13 +3396,13 @@ rl78_propogate_register_origins (void) } } - /* Special case - our ADDSI3 macro uses AX */ + /* Special case - our ADDSI3 macro uses AX and sometimes BC. */ if (get_attr_valloc (insn) == VALLOC_MACAX) { if (dump_file) - fprintf (dump_file, "Resetting origin of AX for macro.\n"); + fprintf (dump_file, "Resetting origin of AX/BC for macro.\n"); for (i = 0; i < FIRST_PSEUDO_REGISTER; i++) - if (i <= 1 || origins[i] <= 1) + if (i <= 3 || origins[i] <= 3) { origins[i] = i; age[i] = 0; @@ -2712,13 +3457,15 @@ rl78_remove_unused_sets (void) } } -#undef xTARGET_MACHINE_DEPENDENT_REORG -#define xTARGET_MACHINE_DEPENDENT_REORG rl78_reorg - /* This is the top of the devritualization pass. */ static void rl78_reorg (void) { + /* split2 only happens when optimizing, but we need all movSIs to be + split now. */ + if (optimize <= 0) + split_all_insns (); + rl78_alloc_physical_registers (); if (dump_file) @@ -2753,7 +3500,7 @@ rl78_reorg (void) df_analyze (); } -#undef TARGET_RETURN_IN_MEMORY +#undef TARGET_RETURN_IN_MEMORY #define TARGET_RETURN_IN_MEMORY rl78_return_in_memory static bool @@ -2764,6 +3511,63 @@ rl78_return_in_memory (const_tree type, const_tree fntype ATTRIBUTE_UNUSED) } +#undef TARGET_RTX_COSTS +#define TARGET_RTX_COSTS rl78_rtx_costs + +static bool rl78_rtx_costs (rtx x, + int code, + int outer_code ATTRIBUTE_UNUSED, + int opno ATTRIBUTE_UNUSED, + int * total, + bool speed ATTRIBUTE_UNUSED) +{ + if (code == IF_THEN_ELSE) + return COSTS_N_INSNS (10); + if (GET_MODE (x) == SImode) + { + switch (code) + { + case MULT: + if (RL78_MUL_RL78) + *total = COSTS_N_INSNS (14); + else if (RL78_MUL_G13) + *total = COSTS_N_INSNS (29); + else + *total = COSTS_N_INSNS (500); + return true; + case PLUS: + *total = COSTS_N_INSNS (8); + return true; + case ASHIFT: + case ASHIFTRT: + case LSHIFTRT: + if (GET_CODE (XEXP (x, 1)) == CONST_INT) + { + switch (INTVAL (XEXP (x, 1))) + { + case 0: *total = COSTS_N_INSNS (0); break; + case 1: *total = COSTS_N_INSNS (6); break; + case 2: case 3: case 4: case 5: case 6: case 7: + *total = COSTS_N_INSNS (10); break; + case 8: *total = COSTS_N_INSNS (6); break; + case 9: case 10: case 11: case 12: case 13: case 14: case 15: + *total = COSTS_N_INSNS (10); break; + case 16: *total = COSTS_N_INSNS (3); break; + case 17: case 18: case 19: case 20: case 21: case 22: case 23: + *total = COSTS_N_INSNS (4); break; + case 24: *total = COSTS_N_INSNS (4); break; + case 25: case 26: case 27: case 28: case 29: case 30: case 31: + *total = COSTS_N_INSNS (5); break; + } + } + else + *total = COSTS_N_INSNS (10+4*16); + return true; + } + } + return false; +} + #undef TARGET_UNWIND_WORD_MODE #define TARGET_UNWIND_WORD_MODE rl78_unwind_word_mode diff --git a/gcc/config/rl78/rl78.md b/gcc/config/rl78/rl78.md index efc26210498..314c37e5c6d 100644 --- a/gcc/config/rl78/rl78.md +++ b/gcc/config/rl78/rl78.md @@ -35,7 +35,7 @@ (FP_REG 22) (SP_REG 32) - (CC_REG 33) + (CC_REG 34) (ES_REG 35) (CS_REG 36) @@ -205,33 +205,76 @@ ;; efficient than anything else. (define_expand "addsi3" - [(set (match_operand:SI 0 "register_operand" "=&v") - (plus:SI (match_operand:SI 1 "nonmemory_operand" "vi") - (match_operand 2 "nonmemory_operand" "vi"))) + [(set (match_operand:SI 0 "nonimmediate_operand" "=&vm") + (plus:SI (match_operand:SI 1 "general_operand" "vim") + (match_operand 2 "general_operand" "vim"))) ] "" - "if (!nonmemory_operand (operands[1], SImode)) - operands[1] = force_reg (SImode, operands[1]); - if (!nonmemory_operand (operands[1], SImode)) - operands[2] = force_reg (SImode, operands[2]);" + "emit_insn (gen_addsi3_internal_virt (operands[0], operands[1], operands[2])); + DONE;" ) -(define_insn "addsi3_internal" - [(set (match_operand:SI 0 "register_operand" "=&v") - (plus:SI (match_operand:SI 1 "nonmemory_operand" "vi") - (match_operand:SI 2 "nonmemory_operand" "vi"))) +(define_insn "addsi3_internal_virt" + [(set (match_operand:SI 0 "nonimmediate_operand" "=v,&vm, vm") + (plus:SI (match_operand:SI 1 "general_operand" "0, vim, vim") + (match_operand 2 "general_operand" "vim,vim,vim"))) + (clobber (reg:HI AX_REG)) + (clobber (reg:HI BC_REG)) ] + "rl78_virt_insns_ok ()" "" - "; addSI macro %0 = %1 + %2 - movw ax, %h1 - addw ax, %h2 - movw %h0, ax - movw ax,%H1 - sknc - incw ax - addw ax,%H2 - movw %H0,ax - ; end of addSI macro" + [(set_attr "valloc" "macax")] +) + +(define_insn "addsi3_internal_real" + [(set (match_operand:SI 0 "nonimmediate_operand" "=v,&vU, vU") + (plus:SI (match_operand:SI 1 "general_operand" "+0, viU, viU") + (match_operand 2 "general_operand" "viWabWhlWh1,viWabWhlWh1,viWabWhlWh1"))) + (clobber (reg:HI AX_REG)) + (clobber (reg:HI BC_REG)) + ] + "rl78_real_insns_ok ()" + "@ + movw ax,%h1 \;addw ax,%h2 \;movw %h0, ax \;movw ax,%H1 \;sknc \;incw ax \;addw ax,%H2 \;movw %H0,ax + movw ax,%h1 \;addw ax,%h2 \;movw %h0, ax \;movw ax,%H1 \;sknc \;incw ax \;addw ax,%H2 \;movw %H0,ax + movw ax,%h1 \;addw ax,%h2 \;movw bc, ax \;movw ax,%H1 \;sknc \;incw ax \;addw ax,%H2 \;movw %H0,ax \;movw ax,bc \;movw %h0, ax" + [(set_attr "valloc" "macax")] +) + +(define_expand "subsi3" + [(set (match_operand:SI 0 "nonimmediate_operand" "=&vm") + (minus:SI (match_operand:SI 1 "general_operand" "vim") + (match_operand 2 "general_operand" "vim"))) + ] + "" + "emit_insn (gen_subsi3_internal_virt (operands[0], operands[1], operands[2])); + DONE;" +) + +(define_insn "subsi3_internal_virt" + [(set (match_operand:SI 0 "nonimmediate_operand" "=v,&vm, vm") + (minus:SI (match_operand:SI 1 "general_operand" "0, vim, vim") + (match_operand 2 "general_operand" "vim,vim,vim"))) + (clobber (reg:HI AX_REG)) + (clobber (reg:HI BC_REG)) + ] + "rl78_virt_insns_ok ()" + "" + [(set_attr "valloc" "macax")] +) + +(define_insn "subsi3_internal_real" + [(set (match_operand:SI 0 "nonimmediate_operand" "=v,&vU, vU") + (minus:SI (match_operand:SI 1 "general_operand" "+0, viU, viU") + (match_operand 2 "general_operand" "viWabWhlWh1,viWabWhlWh1,viWabWhlWh1"))) + (clobber (reg:HI AX_REG)) + (clobber (reg:HI BC_REG)) + ] + "rl78_real_insns_ok ()" + "@ + movw ax,%h1 \;subw ax,%h2 \;movw %h0, ax \;movw ax,%H1 \;sknc \;decw ax \;subw ax,%H2 \;movw %H0,ax + movw ax,%h1 \;subw ax,%h2 \;movw %h0, ax \;movw ax,%H1 \;sknc \;decw ax \;subw ax,%H2 \;movw %H0,ax + movw ax,%h1 \;subw ax,%h2 \;movw bc, ax \;movw ax,%H1 \;sknc \;decw ax \;subw ax,%H2 \;movw %H0,ax \;movw ax,bc \;movw %h0, ax" [(set_attr "valloc" "macax")] ) @@ -255,7 +298,7 @@ (define_expand "mulsi3" [(set (match_operand:SI 0 "register_operand" "=&v") - (mult:SI (match_operand:SI 1 "nonmemory_operand" "vi") + (mult:SI (match_operand:SI 1 "general_operand" "+vim") (match_operand:SI 2 "nonmemory_operand" "vi"))) ] "! RL78_MUL_NONE" @@ -319,8 +362,8 @@ ;; bits of the result). (define_insn "mulsi3_rl78" [(set (match_operand:SI 0 "register_operand" "=&v") - (mult:SI (match_operand:SI 1 "nonmemory_operand" "vi") - (match_operand:SI 2 "nonmemory_operand" "vi"))) + (mult:SI (match_operand:SI 1 "general_operand" "+viU") + (match_operand:SI 2 "general_operand" "vi"))) ] "RL78_MUL_RL78" "; mulsi macro %0 = %1 * %2 @@ -349,8 +392,8 @@ ;; Warning: this matches the silicon not the documentation. (define_insn "mulsi3_g13" [(set (match_operand:SI 0 "register_operand" "=&v") - (mult:SI (match_operand:SI 1 "nonmemory_operand" "vi") - (match_operand:SI 2 "nonmemory_operand" "vi"))) + (mult:SI (match_operand:SI 1 "general_operand" "viU") + (match_operand:SI 2 "general_operand" "viU"))) ] "RL78_MUL_G13" "; mulsi macro %0 = %1 * %2 |