Various RL78-specific fixes and tweaks wrt volatiles and addressing modes. Committed.
* config/rl78/rl78-real.md (addqi3_real): Allow volatiles. (addhi3_real): Likewise. Fix [HL+0] syntax. (subqi3_real): Likewise. (subhi3_real): Likewise. (cbranchqi4_real): Likewise. Allow saddr,#imm. (cbranchhi4_real): Likewise. (cbranchhi4_real_inverted): Likewise. (cbranchsi4_real_lt): Likewise. (cbranchsi4_real_ge): Likewise. (cbranchsi4_real_ge): Likewise. * config/rl78/rl78-virt.md (add<mode>3_virt): Likewise. (sub<mode>3_virt): Likewise. (cbranchqi4_virt): Likewise. (cbranchhi4_virt): Likewise. * config/rl78/rl78.c (rl78_print_operand_1): 'p' modifier means always use '[reg+imm]' even when imm is zero. * config/rl78/predicates.md (rl78_volatile_memory_operand): New. (rl78_general_operand): New. (rl78_nonimmediate_operand): New. (rl78_nonfar_operand): Use them. (rl78_nonfar_nonimm_operand): Likewise. (rl78_stack_based_mem): Fix. * config/rl78/constraints.md (Ibqi): New. (IBqi): New. (Wsa): New. (Wsf): New. (Cs1): Fix. * config/rl78/rl78-expand.md (andqi3): Accept volatiles. (iorqi3): Likewise. (xorqi3): Likewise. * config/rl78/rl78-protos.h (rl78_sfr_p): New. * config/rl78/constrains (Qs8): New constraint. * config/rl78/rl78.c (rl78_flags_already_set): New function. * config/rl78/rl78-protos.h (rl78_flags_already_set): New prototype. * config/rl78/rl78-real.md (update_Z): New attribute. Update patterns to set it. (cbranchqi4_real): Call rl78_flags_already_set() to determine if a shorter compare and branch sequence can be used. (cbranchhi4_real): Likewise. (cbranchhi4_real_inverted): Likewise. * config/rl78/predicates.md (uword_operand): Allow symbol_refs. * config/rl78/rl78-c.c (rl78_register_pragmas): Register __near address space. * config/rl78/rl78.c (rl78_get_name_encoding): New. (rl78_option_override): Allow -mes0 only if C. (characterize_address): Support subregs of symbol_refs. (rl78_addr_space_address_mode): Move. Add __near. (rl78_far_p): Likewise. (rl78_addr_space_pointer_mode): Likewise. (rl78_as_legitimate_address): Likewise. (rl78_addr_space_subset_p): Likewise. (rl78_addr_space_convert): Likewise. (rl78_print_operand_1): Support 16-bit addressing of 32-bit symbols with -mes0. (transcode_memory_rtx): Don't copy ES if -mes0. Allow symbol[BC] addressing. (rl78_alloc_physical_registers_op1): Change logic to prefer symbol[BC] addressing. (frodata_section): New. (rl78_asm_init_sections): Initialize it. (rl78_select_section): Put __far readonly symbols in .frodata. (rl78_make_type_far): New. (rl78_insert_attributes): Force all readonly symbols to be __far when -mes0. (rl78_asm_out_integer): New. * config/rl78/rl78.h (ADDR_SPACE_NEAR): New. * config/rl78/rl78.opt (-mes0): New. * config/rl78/rl78.h (ASM_OUTPUT_LABELREF): New. (ASM_OUTPUT_ALIGNED_DECL_COMMON): New. (ASM_OUTPUT_ALIGNED_DECL_LOCAL): New. * config/rl78/rl78-protos.h (rl78_output_labelref): New. (rl78_saddr_p): New. (rl78_output_aligned_common): New. * config/rl78/rl78.c (rl78_output_symbol_ref): Strip encodings. (rl78_handle_saddr_attribute): New. (rl78_handle_naked_attribute): New. (rl78_attribute_table): Add saddr. (rl78_print_operand_1): Don't print '!' on saddr operands. (rl78_print_operand_1): Strip encodings. (rl78_sfr_p): New. (rl78_strip_name_encoding): New. (rl78_attrlist_to_encoding): New. (rl78_encode_section_info): New. (rl78_asm_init_sections): New. (rl78_select_section): New. (rl78_output_labelref): New. (rl78_output_aligned_common): New. (rl78_asm_out_integer): New. (rl78_asm_ctor_dtor): New. (rl78_asm_constructor): New. (rl78_asm_destructor): New. * config/rl78/rl78-real.md (movqi_es): Rename to movqi_to_es. * config/rl78/rl78.c (rl78_expand_epilogue): Update. (transcode_memory_rtx): Update. (rl78_expand_epilogue): Use A_REG instead of 0. Index: config/rl78/predicates.md =================================================================== --- config/rl78/predicates.md (revision 219790) +++ config/rl78/predicates.md (working copy) @@ -15,24 +15,40 @@ ;; GNU General Public License for more details. ;; You should have received a copy of the GNU General Public License ;; along with GCC; see the file COPYING3. If not see ;; <http://www.gnu.org/licenses/>. -(define_predicate "rl78_any_operand" + +(define_predicate "rl78_volatile_memory_operand" + (and (match_code "mem") + (match_test ("memory_address_addr_space_p (GET_MODE (op), XEXP (op, 0), MEM_ADDR_SPACE (op))"))) +) + +; TRUE for any valid general operand. We do this because +; general_operand refuses to match volatile memory refs. + +(define_predicate "rl78_general_operand" (ior (match_operand 0 "general_operand") - (match_code "mem,const_int,const_double,reg")) + (match_operand 0 "rl78_volatile_memory_operand")) +) + +; Likewise for nonimmediate_operand. + +(define_predicate "rl78_nonimmediate_operand" + (ior (match_operand 0 "nonimmediate_operand") + (match_operand 0 "rl78_volatile_memory_operand")) ) (define_predicate "rl78_nonfar_operand" - (and (match_operand 0 "general_operand") + (and (match_operand 0 "rl78_general_operand") (not (match_test "rl78_far_p (op)"))) ) (define_predicate "rl78_nonfar_nonimm_operand" - (and (match_operand 0 "nonimmediate_operand") + (and (match_operand 0 "rl78_nonimmediate_operand") (not (match_test "rl78_far_p (op)"))) ) (define_predicate "rl78_near_mem_operand" (and (match_code "mem") (match_test "!rl78_far_p (op) && rl78_as_legitimate_address (VOIDmode, XEXP (op, 0), true, ADDR_SPACE_GENERIC)")) @@ -44,15 +60,20 @@ (define_predicate "rl78_24_operand" (and (match_code "const_int") (match_test "INTVAL (op) == 2 || INTVAL (op) == 4"))) (define_predicate "uword_operand" - (ior (match_code "const") - (and (match_code "const_int") - (match_test "IN_RANGE (INTVAL (op), 0, 65536)")))) + (ior (ior (ior (match_code "const") + (and (match_code "const_int") + (match_test "IN_RANGE (INTVAL (op), 0, 65536)"))) + (and (match_code "subreg") + (ior (match_code "symbol_ref" "0") + (match_code "const" "0")))) + (match_code "symbol_ref") + )) (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" @@ -70,7 +91,9 @@ (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")))))) + (and (match_code "const_int" "01") + (match_test "IN_RANGE (INTVAL (XEXP (XEXP (op, 0), 1)), 0, 256 - GET_MODE_SIZE (GET_MODE (op)))")) + ))))) Index: config/rl78/rl78.h =================================================================== --- config/rl78/rl78.h (revision 219790) +++ config/rl78/rl78.h (working copy) @@ -131,13 +131,14 @@ #define MOVE_MAX 2 #define STARTING_FRAME_OFFSET 0 #define TRULY_NOOP_TRUNCATION(OUTPREC, INPREC) 1 -#define ADDR_SPACE_FAR 1 +#define ADDR_SPACE_NEAR 1 +#define ADDR_SPACE_FAR 2 #define HAVE_PRE_DECCREMENT 0 #define HAVE_POST_INCREMENT 0 #define MOVE_RATIO(SPEED) ((SPEED) ? 24 : 16) #define SLOW_BYTE_ACCESS 0 @@ -238,12 +239,14 @@ enum reg_class "V_REGS", \ "GR_REGS", \ "PSWREG", \ "ALL_REGS" \ } +/* Note that no class may include the second register in $fp, because + we treat $fp as a single HImode register. */ #define REG_CLASS_CONTENTS \ { \ { 0x00000000, 0x00000000 }, /* No registers, */ \ { 0x00000001, 0x00000000 }, \ { 0x00000002, 0x00000000 }, \ { 0x00000003, 0x00000000 }, \ @@ -421,12 +424,22 @@ typedef unsigned int CUMULATIVE_ARGS; the tablejump insn. */ #define ASM_OUTPUT_ADDR_DIFF_ELT(FILE, BODY, VALUE, REL) \ fprintf (FILE, "\t.long .L%d - 1b\n", VALUE) +#define ASM_OUTPUT_SYMBOL_REF(FILE, SYM) rl78_output_symbol_ref ((FILE), (SYM)) + +#define ASM_OUTPUT_LABELREF(FILE, SYM) rl78_output_labelref ((FILE), (SYM)) + +#define ASM_OUTPUT_ALIGNED_DECL_COMMON(STREAM, DECL, NAME, SIZE, ALIGNMENT) \ + rl78_output_aligned_common (STREAM, DECL, NAME, SIZE, ALIGNMENT, 1) + +#define ASM_OUTPUT_ALIGNED_DECL_LOCAL(STREAM, DECL, NAME, SIZE, ALIGNMENT) \ + rl78_output_aligned_common (STREAM, DECL, NAME, SIZE, ALIGNMENT, 0) + #define ASM_OUTPUT_ALIGN(STREAM, LOG) \ do \ { \ if ((LOG) == 0) \ break; \ fprintf (STREAM, "\t.balign %d\n", 1 << (LOG)); \ Index: config/rl78/constraints.md =================================================================== --- config/rl78/constraints.md (revision 219790) +++ config/rl78/constraints.md (working copy) @@ -108,12 +108,23 @@ (define_constraint "ISqi" "@internal Integer constant with bit 7 set." (and (match_code "const_int") (match_test "(ival & 0x80) != 0"))) +(define_constraint "Ibqi" + "@internal + Integer constant with one bit in 0..7 set." + (and (match_code "const_int") + (match_test "(ival & 0xff) && (exact_log2 (ival & 0xff) >= 0)"))) +(define_constraint "IBqi" + "@internal + Integer constant with one bit in 0..7 clear." + (and (match_code "const_int") + (match_test "(~ival & 0xff) && (exact_log2 (~ival & 0xff) >= 0)"))) + (define_constraint "J" "Integer constant in the range -255 @dots{} 0" (and (match_code "const_int") (match_test "IN_RANGE (ival, -255, 0)"))) (define_constraint "K" @@ -339,27 +350,41 @@ (ior (and (match_code "reg" "0") (match_test "REGNO (XEXP (op, 0)) == SP_REG")) (and (match_code "plus" "0") (and (and (match_code "reg" "00") (match_test "REGNO (XEXP (XEXP (op, 0), 0)) == SP_REG")) - (match_test "ubyte_operand (XEXP (XEXP (op, 0), 1), VOIDmode)")))) + (and (match_code "const_int" "01") + (match_test "IN_RANGE (INTVAL (XEXP (XEXP (op, 0), 1)), 0, 256 - GET_MODE_SIZE (GET_MODE (op)))"))))) ) ) + (define_memory_constraint "Ws1" "es:word8[SP]" (match_test "(rl78_es_addr (op) && satisfies_constraint_Cs1 (rl78_es_base (op))) || satisfies_constraint_Cs1 (op)") ) (define_memory_constraint "Wfr" "ES/CS far pointer" (and (match_code "mem") (match_test "rl78_far_p (op)")) ) +(define_memory_constraint "Wsa" + "any SADDR memory access" + (and (match_code "mem") + (match_test "rl78_saddr_p (op)")) +) + +(define_memory_constraint "Wsf" + "any SFR memory access" + (and (match_code "mem") + (match_test "rl78_sfr_p (op)")) +) + (define_memory_constraint "Y" "any near legitimate memory access" (and (match_code "mem") (match_test "!rl78_far_p (op) && rl78_as_legitimate_address (VOIDmode, XEXP (op, 0), true, ADDR_SPACE_GENERIC)")) ) @@ -381,6 +406,12 @@ "built-in compare types" (match_code "eq,ne,gtu,ltu,geu,leu")) (define_memory_constraint "Qsc" "synthetic compares" (match_code "gt,lt,ge,le")) + +(define_constraint "Qs8" + "Integer constant computed from (SUBREG (SYMREF))." + (and (match_code "subreg") + (match_test "GET_CODE (XEXP (op, 0)) == SYMBOL_REF")) +) Index: config/rl78/rl78-protos.h =================================================================== --- config/rl78/rl78-protos.h (revision 219790) +++ config/rl78/rl78-protos.h (working copy) @@ -42,6 +42,14 @@ void rl78_register_pragmas (void); bool rl78_regno_mode_code_ok_for_base_p (int, machine_mode, addr_space_t, int, int); void rl78_setup_peep_movhi (rtx *); bool rl78_virt_insns_ok (void); bool rl78_es_addr (rtx); rtx rl78_es_base (rtx); + +bool rl78_flags_already_set (rtx, rtx); +void rl78_output_symbol_ref (FILE *, rtx); +void rl78_output_labelref (FILE *, const char *); +int rl78_saddr_p (rtx x); +int rl78_sfr_p (rtx x); +void rl78_output_aligned_common (FILE *, tree, const char *, + int, int, int); Index: config/rl78/rl78-expand.md =================================================================== --- config/rl78/rl78-expand.md (revision 219790) +++ config/rl78/rl78-expand.md (working copy) @@ -147,35 +147,35 @@ (zero_extend:HI (match_operand:QI 2 "register_operand"))))] "!TARGET_G10" "" ) (define_expand "andqi3" - [(set (match_operand:QI 0 "nonimmediate_operand") - (and:QI (match_operand:QI 1 "general_operand") - (match_operand:QI 2 "general_operand"))) + [(set (match_operand:QI 0 "rl78_nonimmediate_operand") + (and:QI (match_operand:QI 1 "rl78_general_operand") + (match_operand:QI 2 "rl78_general_operand"))) ] "" "if (rl78_force_nonfar_3 (operands, gen_andqi3)) DONE;" ) (define_expand "iorqi3" - [(set (match_operand:QI 0 "nonimmediate_operand") - (ior:QI (match_operand:QI 1 "general_operand") - (match_operand:QI 2 "general_operand"))) + [(set (match_operand:QI 0 "rl78_nonimmediate_operand") + (ior:QI (match_operand:QI 1 "rl78_general_operand") + (match_operand:QI 2 "rl78_general_operand"))) ] "" "if (rl78_force_nonfar_3 (operands, gen_iorqi3)) DONE;" ) (define_expand "xorqi3" - [(set (match_operand:QI 0 "nonimmediate_operand") - (xor:QI (match_operand:QI 1 "general_operand") - (match_operand:QI 2 "general_operand"))) + [(set (match_operand:QI 0 "rl78_nonimmediate_operand") + (xor:QI (match_operand:QI 1 "rl78_general_operand") + (match_operand:QI 2 "rl78_general_operand"))) ] "" "if (rl78_force_nonfar_3 (operands, gen_xorqi3)) DONE;" ) Index: config/rl78/rl78-real.md =================================================================== --- config/rl78/rl78-real.md (revision 219790) +++ config/rl78/rl78-real.md (working copy) @@ -24,15 +24,23 @@ ;; allow virtual registers in their predicates - the reorg pass that ;; allocates physical registers uses the constraints to select ;; registers, but insns with virtual registers MUST match one of these ;; patterns - other than the constraints - so that the operand info is ;; properly set up for the alloc pass. +;; This attribute reflects how the insn alters the Z flag, +;; based upon the value of the it's output. The default is NO +;; for no change, but other possibilities are UPDATE_Z if it changes +;; the Z flag and CLOBBER if the state of the flag is indeterminate. +;; The CY and AC flags are not set in the same way as the Z flag, so +;; their values are not tracked. +(define_attr "update_Z" "no,update_Z,clobber" (const_string "no")) + ;;---------- Moving ------------------------ -(define_insn "movqi_es" +(define_insn "movqi_to_es" [(set (reg:QI ES_REG) (match_operand:QI 0 "register_operand" "a"))] "" "mov\tes, %0" ) @@ -48,29 +56,30 @@ (match_operand:QI 0 "register_operand" "a"))] "" "mov\tcs, %0" ) (define_insn "*movqi_real" - [(set (match_operand:QI 0 "nonimmediate_operand" "=g,RaxbcWab,RaxbcWab,a, bcx,R, WabWd2WhlWh1WhbWbcWs1v, bcx") - (match_operand 1 "general_operand" "0,K, M, RInt8sJvWabWdeWd2WhlWh1WhbWbcWs1,Wab,aInt8J,a, R"))] + [(set (match_operand:QI 0 "rl78_nonimmediate_operand" "=g,RaxbcWab,RaxbcWab,a, bcx,R, WabWd2WhlWh1WhbWbcWs1v, bcx,WsaWsf") + (match_operand 1 "rl78_general_operand" "0,K, M, RInt8sJvWabWdeWd2WhlWh1WhbWbcWs1,Wab,aInt8J,a, R, i"))] "rl78_real_insns_ok ()" "@ ; mov\t%0, %1 oneb\t%0 clrb\t%0 mov\t%0, %1 mov\t%0, %1 mov\t%0, %1 mov\t%0, %1 - mov\t%0, %S1" + mov\t%0, %S1 + mov\t%0, %1" ) (define_insn "*movhi_real" - [(set (match_operand:HI 0 "nonimmediate_operand" "=g,AB,AB,RSv,A,BDTvSWabWd2WdeWhlWh1WbcWs1, BDT,ABDT,v") - (match_operand:HI 1 "general_operand" " 0,K, M, i, BDTvSWabWd2WdeWh1WhlWbcWs1,A, BDT,vS, ABDT"))] + [(set (match_operand:HI 0 "rl78_nonimmediate_operand" "=g,AB,AB,RSv,A,BDTvSWabWd2WdeWhlWh1WbcWs1, BDT,ABDT,v") + (match_operand:HI 1 "rl78_general_operand" " 0,K, M, i, BDTvSWabWd2WdeWh1WhlWbcWs1,A, BDT,vS, ABDT"))] "rl78_real_insns_ok ()" "@ ; movw\t%0, %1 onew\t%0 clrw\t%0 movw\t%0, %1 @@ -101,66 +110,72 @@ sarw\t%0, 8" ) ;;---------- Arithmetic ------------------------ (define_insn "*addqi3_real" - [(set (match_operand:QI 0 "nonimmediate_operand" "=rvWabWhlWh1,rvWabWhlWh1,a,*bcdehl") - (plus:QI (match_operand:QI 1 "general_operand" "%0,0,0,0") - (match_operand:QI 2 "general_operand" "K,L,RWhlWh1Wabi,a"))) + [(set (match_operand:QI 0 "rl78_nonimmediate_operand" "=rvWabWhlWh1,rvWabWhlWh1,a,*bcdehl,Wsa") + (plus:QI (match_operand:QI 1 "rl78_general_operand" "%0,0,0,0,0") + (match_operand:QI 2 "rl78_general_operand" "K,L,RWhlWh1Wabi,a,i"))) ] "rl78_real_insns_ok ()" "@ inc\t%0 dec\t%0 add\t%0, %2 + add\t%0, %2 add\t%0, %2" + [(set (attr "update_Z") (const_string "update_Z"))] ) (define_insn "*addhi3_real" - [(set (match_operand:HI 0 "nonimmediate_operand" "=vABDTWh1Wab,vABDTWh1Wab,v,v,A,S,S,A") - (plus:HI (match_operand:HI 1 "general_operand" "%0,0,0,0,0,0,0,S") - (match_operand:HI 2 "general_operand" "K,L,N,O,RWh1WhlWabiv,Int8,J,Ri"))) + [(set (match_operand:HI 0 "rl78_nonimmediate_operand" "=vABDTWh1Wab,vABDTWh1Wab,v,v,A,S,S,A") + (plus:HI (match_operand:HI 1 "rl78_general_operand" "%0,0,0,0,0,0,0,S") + (match_operand:HI 2 "" "K,L,N,O,RWh1WhlWabiv,Int8Qs8,J,Ri"))) ] "rl78_real_insns_ok ()" "@ - incw\t%0 - decw\t%0 + incw\t%p0 + decw\t%p0 incw\t%0 \;incw\t%0 decw\t%0 \;decw\t%0 addw\t%0, %p2 addw\t%0, %2 subw\t%0, %m2 movw\t%0, %1 \;addw\t%0, %2" + [(set_attr "update_Z" "*,*,*,*,update_Z,update_Z,update_Z,update_Z")] ) (define_insn "*addqihi3a_real" [(set (match_operand:HI 0 "register_operand" "=r") (plus:HI (zero_extend:HI (match_operand:QI 1 "register_operand" "r")) (match_operand:HI 2 "register_operand" "0"))) ] "rl78_real_insns_ok ()" "add\t%q0, %q1 \;addc\t%Q0, #0" + [(set (attr "update_Z") (const_string "update_Z"))] ) (define_insn "*subqi3_real" [(set (match_operand:QI 0 "nonimmediate_operand" "=a,R,v") (minus:QI (match_operand:QI 1 "general_operand" "0,0,0") - (match_operand:QI 2 "general_operand" "RiWabWhbWh1Whl,a,i"))) + (match_operand:QI 2 "rl78_general_operand" "RiWabWhbWh1Whl,a,i"))) ] "rl78_real_insns_ok ()" "sub\t%0, %2" + [(set (attr "update_Z") (const_string "update_Z"))] ) (define_insn "*subhi3_real" [(set (match_operand:HI 0 "nonimmediate_operand" "=A,S") (minus:HI (match_operand:HI 1 "general_operand" "0,0") - (match_operand:HI 2 "general_operand" "iBDTWabWh1v,i"))) + (match_operand:HI 2 "rl78_general_operand" "iBDTWabWh1v,i"))) ] "rl78_real_insns_ok ()" "subw\t%0, %2" + [(set (attr "update_Z") (const_string "update_Z"))] ) (define_insn "*umulhi3_shift_real" [(set (match_operand:HI 0 "register_operand" "=A,A") (mult:HI (match_operand:HI 1 "rl78_nonfar_operand" "0,0") (match_operand:HI 2 "rl78_24_operand" "N,i")))] @@ -176,36 +191,47 @@ (zero_extend:HI (match_operand:QI 2 "general_operand" "x"))))] "rl78_real_insns_ok () && !TARGET_G10" "mulu\t%2" ) (define_insn "*andqi3_real" - [(set (match_operand:QI 0 "nonimmediate_operand" "=A,R,v") - (and:QI (match_operand:QI 1 "general_operand" "%0,0,0") - (match_operand:QI 2 "general_operand" "iRvWabWhbWh1Whl,A,i"))) + [(set (match_operand:QI 0 "rl78_nonimmediate_operand" "=Wsf,A,R,vWsa") + (and:QI (match_operand:QI 1 "rl78_general_operand" "%0,0,0,0") + (match_operand:QI 2 "rl78_general_operand" "IBqi,iRvWabWhbWh1Whl,A,i"))) ] "rl78_real_insns_ok ()" - "and\t%0, %2" + "@ + clr1\t%0.%B2 + and\t%0, %2 + and\t%0, %2 + and\t%0, %2" + [(set_attr "update_Z" "*,update_Z,update_Z,update_Z")] ) (define_insn "*iorqi3_real" - [(set (match_operand:QI 0 "nonimmediate_operand" "=A,R,v") - (ior:QI (match_operand:QI 1 "general_operand" "%0,0,0") - (match_operand:QI 2 "general_operand" "iRvWabWhbWh1Whl,A,i"))) + [(set (match_operand:QI 0 "rl78_nonimmediate_operand" "=Wsf,A,R,vWsa") + (ior:QI (match_operand:QI 1 "rl78_general_operand" "%0,0,0,0") + (match_operand:QI 2 "rl78_general_operand" "Ibqi,iRvWabWhbWh1Whl,A,i"))) ] "rl78_real_insns_ok ()" - "or\t%0, %2" + "@ + set1\t%0.%B2 + or\t%0, %2 + or\t%0, %2 + or\t%0, %2" + [(set_attr "update_Z" "*,update_Z,update_Z,update_Z")] ) (define_insn "*xorqi3_real" - [(set (match_operand:QI 0 "nonimmediate_operand" "=A,R,v") - (xor:QI (match_operand:QI 1 "general_operand" "%0,0,0") - (match_operand 2 "general_operand" "iRvWabWhbWh1Whl,A,i"))) + [(set (match_operand:QI 0 "rl78_nonimmediate_operand" "=A,R,vWsa") + (xor:QI (match_operand:QI 1 "rl78_general_operand" "%0,0,0") + (match_operand 2 "rl78_general_operand" "iRvWabWhbWh1Whl,A,i"))) ] "rl78_real_insns_ok ()" "xor\t%0, %2" + [(set (attr "update_Z") (const_string "update_Z"))] ) ;;---------- Shifts ------------------------ (define_insn "*ashlqi3_real" [(set (match_operand:QI 0 "nonimmediate_operand" "=abc,a,a") @@ -214,24 +240,26 @@ ] "rl78_real_insns_ok ()" "@ shl\t%0, %u2 cmp0 %2\; bz $2f\; 1: shl\t%0, 1 \;dec %2 \;bnz $1b\;2: inc %2\;dec %2\;bz $2f\;1: shl\t%0, 1 \;dec %2 \;bnz $1b\;2:" + [(set_attr "update_Z" "*,clobber,clobber")] ) (define_insn "*ashlhi3_real" [(set (match_operand:HI 0 "nonimmediate_operand" "=AB,A,A") (ashift:HI (match_operand:HI 1 "general_operand" "0,0,0") (match_operand:QI 2 "general_operand" "P,bc,dehl"))) ] "rl78_real_insns_ok ()" "@ shlw\t%0, %u2 cmp0 %2\; bz $2f\; 1: shlw\t%0, 1 \;dec %2 \;bnz $1b\;2: inc %2\;dec %2\;bz $2f\;1: shlw\t%0, 1 \;dec %2 \;bnz $1b\;2:" + [(set_attr "update_Z" "*,clobber,clobber")] ) ;;---------- (define_insn "*ashrqi3_real" [(set (match_operand:QI 0 "nonimmediate_operand" "=abc,a,a") @@ -240,24 +268,26 @@ ] "rl78_real_insns_ok ()" "@ sar\t%0, %u2 cmp0 %2\; bz $2f\; 1: sar\t%0, 1 \;dec %2 \;bnz $1b\;2: inc %2\;dec %2\;bz $2f\;1: sar\t%0, 1\;dec %2 \;bnz $1b\;2:" + [(set_attr "update_Z" "*,clobber,clobber")] ) (define_insn "*ashrhi3_real" [(set (match_operand:HI 0 "nonimmediate_operand" "=AB,A,A") (ashiftrt:HI (match_operand:HI 1 "general_operand" "0,0,0") (match_operand:QI 2 "general_operand" "P,bc,dehl"))) ] "rl78_real_insns_ok ()" "@ sarw\t%0, %u2 cmp0 %2\; bz $2f\; 1: sarw\t%0, 1 \;dec %2 \;bnz $1b\;2: inc %2\;dec %2\;bz $2f\;1: sarw\t%0, 1\;dec %2\;bnz $1b\;2:" + [(set_attr "update_Z" "*,clobber,clobber")] ) ;;---------- (define_insn "*lshrqi3_real" [(set (match_operand:QI 0 "nonimmediate_operand" "=abc,a,a") @@ -266,24 +296,26 @@ ] "rl78_real_insns_ok ()" "@ shr\t%0, %u2 cmp0 %2\; bz $2f\; 1: shr\t%0, 1 \;dec %2 \;bnz $1b\;2: inc %2\;dec %2\;bz $2f\;1: shr\t%0, 1\;dec %2\;bnz $1b\;2:" + [(set_attr "update_Z" "*,clobber,clobber")] ) (define_insn "*lshrhi3_real" [(set (match_operand:HI 0 "nonimmediate_operand" "=AB,A,A") (lshiftrt:HI (match_operand:HI 1 "general_operand" "0,0,0") (match_operand:QI 2 "general_operand" "P,bc,dehl"))) ] "rl78_real_insns_ok ()" "@ shrw\t%0, %u2 cmp0 %2\; bz $2f\; 1: shrw\t%0, 1 \;dec %2 \;bnz $1b\;2: inc %2\;dec %2\;bz $2f\;1: shrw\t%0, 1\;dec %2\;bnz $1b\;2:" + [(set_attr "update_Z" "*,clobber,clobber")] ) ;;---------- Branching ------------------------ (define_insn "*indirect_jump_real" [(set (pc) @@ -304,118 +336,156 @@ [(call (match_operand:HI 0 "memory_operand" "Wab,Wca") (match_operand 1 "" ""))] "rl78_real_insns_ok ()" "@ call\t!!%A0 call\t%A0" + [(set (attr "update_Z") (const_string "clobber"))] ) (define_insn "*call_value_real" [(set (match_operand 0 "register_operand" "=v,v") (call (match_operand:HI 1 "memory_operand" "Wab,Wca") (match_operand 2 "" "")))] "rl78_real_insns_ok ()" "@ call\t!!%A1 call\t%A1" + [(set (attr "update_Z") (const_string "clobber"))] ) (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")]) + [(match_operand:QI 1 "general_operand" "A,A,A,A,Wsa") + (match_operand:QI 2 "general_operand" "M,ISqi,i,v,i")]) (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" + { + gcc_assert (GET_CODE (operands[0]) != EQ && GET_CODE (operands[0]) != NE); + + switch (which_alternative) + { + case 0: return "cmp0\t%1\; xor1\tCY, %1.7\; sk%C0\; br\t!!%3"; + case 1: return "cmp\t%1, %2\; xor1\tCY, %1.7\; not1\tCY\; sk%C0\; br\t!!%3"; + case 4: + case 2: return "cmp\t%1, %2\; xor1\tCY, %1.7\; sk%C0\; br\t!!%3"; + case 3: return "cmp\t%1, %2\; xor1\tCY, %1.7\; xor1\tCY, %2.7\; sk%C0\; br\t!!%3"; + default: gcc_unreachable (); + } + } + [(set (attr "update_Z") (const_string "clobber"))] ;; FIXME: flags are set based on %1 vs %2 ) (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, irvWabWhlWh1Whb,i,a")]) + [(match_operand:QI 1 "rl78_general_operand" "Wabvaxbc,a, vWsaWab,bcdehl") + (match_operand:QI 2 "rl78_general_operand" "M, irvWabWhlWh1Whb,i,a")]) (label_ref (match_operand 3 "" "")) (pc)))] "rl78_real_insns_ok ()" - "@ - cmp0\t%1 \;sk%C0 \;br\t!!%3 - cmp\t%1, %2 \;sk%C0 \;br\t!!%3 - cmp\t%1, %2 \;sk%C0 \;br\t!!%3 - cmp\t%1, %2 \;sk%C0 \;br\t!!%3" + { + if (which_alternative == 0) + { + if (rl78_flags_already_set (operands[0], operands[1])) + return "sk%C0\; br\t!!%3\; # zero-comparison eliminated"; + else + return "cmp0\t%1\; sk%C0\; br\t!!%3"; + } + return "cmp\t%1, %2\; sk%C0\; br\t!!%3"; + } + [(set (attr "update_Z") (const_string "clobber"))] ;; FIXME: alt 0: flags are set based on %1 vs %2 ) (define_insn "*cbranchhi4_real_signed" [(set (pc) (if_then_else (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 + cmpw\t%1, %2\; xor1\tCY, %Q1.7\; not1\tCY\; sk%C0\; br\t!!%3 + cmpw\t%1, %2\; xor1\tCY, %Q1.7\; sk%C0\; br\t!!%3 + cmpw\t%1, %2\; xor1\tCY, %Q1.7\; xor1\tCY, %Q2.7\; sk%C0\; br\t!!%3 %z0\t!!%3" + [(set_attr "update_Z" "clobber,clobber,clobber,*")] ) (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")]) + [(match_operand:HI 1 "general_operand" "A,A,vR") + (match_operand:HI 2 "rl78_general_operand" "M,iBDTvWabWhlWh1,1")]) (label_ref (match_operand 3 "" "")) (pc)))] "rl78_real_insns_ok ()" - "@ - cmpw\t%1, %2 \;sk%C0 \;br\t!!%3 - %z0\t!!%3" + { + switch (which_alternative) + { + case 0: + if (rl78_flags_already_set (operands[0], operands[1])) + return "sk%C0\; br\t!!%3\; # cmpw eliminated"; + /* else fall through. */ + case 1: + return "cmpw\t%1, %2\; sk%C0\; br\t!!%3"; + case 2: + return "%z0\t!!%3"; + default: + gcc_unreachable (); + } + } + [(set (attr "update_Z") (const_string "clobber"))] ;; FIXME: Z might be set based on %1 vs %2 ) (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")]) + [(match_operand:HI 1 "general_operand" "A,A") + (match_operand:HI 2 "rl78_general_operand" "M,iBDTvWabWhlWh1")]) (pc) (label_ref (match_operand 3 "" ""))))] "rl78_real_insns_ok ()" - "cmpw\t%1, %2 \;sk%C0 \;br\t!!%3" + { + if (which_alternative == 0 && rl78_flags_already_set (operands[0], operands[1])) + return "sk%C0\; br\t!!%3\; # inverted cmpw eliminated"; + else + return "cmpw\t%1, %2\; sk%C0\; br\t!!%3"; + } + [(set (attr "update_Z") (const_string "clobber"))] ;; FIXME: flags are set based on %1 vs %2 ) (define_insn "*cbranchsi4_real_lt" [(set (pc) (if_then_else - (lt (match_operand:SI 0 "general_operand" "U,vWabWhlWh1") + (lt (match_operand:SI 0 "rl78_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" + mov\ta, %E0\; mov1\tCY, a.7\; sknc\; br\t!!%1 + mov1\tCY, %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") + (ge (match_operand:SI 0 "rl78_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" + mov\ta, %E0\; mov1\tCY, a.7\; skc\; br\t!!%1 + mov1\tCY, %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 "general_operand" "vU,vU,vU,i,i") @@ -423,30 +493,32 @@ (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 - movw ax, %H1\; cmpw ax, %H2\; xor1 CY, a.7\; not1 CY\; movw ax, %h1 \;sknz\; cmpw ax, %h2 \;sk%0 \;br\t!!%3 - movw ax, %H1\; cmpw ax, %H2\; xor1 CY, a.7\; movw ax, %h1\; sknz\; cmpw ax, %h2\; sk%0\; br\t!!%3" + movw\tax, %H1\; cmpw\tax, %H2\; xor1\tCY, a.7\; not1\tCY\; movw\tax, %h1\; sknz\; cmpw\tax, %h2\; sk%C0\; br\t!!%3 + movw\tax, %H1\; cmpw\tax, %H2\; xor1\tCY, a.7\; movw\tax, %h1\; sknz\; cmpw\tax, %h2\; sk%C0\; br\t!!%3 + movw\tax, %H1\; cmpw\tax, %H2\; xor1\tCY, a.7\; xor1\tCY, %E2.7\; movw\tax, %h1\; sknz\; cmpw\tax, %h2\; sk%C0\; br\t!!%3 + movw\tax, %H1\; cmpw\tax, %H2\; xor1\tCY, a.7\; not1\tCY\; movw\tax, %h1\; sknz\; cmpw\tax, %h2\; sk%0\; br\t!!%3 + movw\tax, %H1\; cmpw\tax, %H2\; xor1\tCY, a.7\; movw\tax, %h1\; sknz\; cmpw\tax, %h2\; sk%0\; br\t!!%3" + [(set (attr "update_Z") (const_string "clobber"))] ) (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" + "movw\tax, %H1\; cmpw\tax, %H2\; movw\tax, %h1\; sknz\; cmpw\tax, %h2\; sk%C0\; br\t!!%3" + [(set (attr "update_Z") (const_string "clobber"))] ) ;; Peephole to match: ;; ;; (set (mem (sp)) (ax)) ;; (set (ax) (mem (sp))) @@ -477,23 +549,25 @@ (match_operand 0 "immediate_operand" "n")) (const_int 0)) (label_ref (match_operand 1 "" "")) (pc)))] "" "bf\tA.%B0, $%1" + [(set (attr "update_Z") (const_string "clobber"))] ) (define_insn "bt" [(set (pc) (if_then_else (ne (and (reg:QI A_REG) (match_operand 0 "immediate_operand" "n")) (const_int 0)) (label_ref (match_operand 1 "" "")) (pc)))] "" "bt\tA.%B0, $%1" + [(set (attr "update_Z") (const_string "clobber"))] ) ;; NOTE: These peepholes are fragile. They rely upon GCC generating ;; a specific sequence on insns, based upon examination of test code. ;; Improvements to GCC or using code other than the test code can result ;; in the peephole not matching and the optimization being missed. @@ -562,7 +636,8 @@ [(set (match_operand:HI 0 "register_operand" "=A") (and:HI (neg:HI (match_operand:HI 1 "register_operand" "0")) (match_operand:HI 2 "immediate_operand" "n"))) ] "rl78_real_insns_ok ()" "xor a, #0xff @ xch a, x @ xor a, #0xff @ xch a, x @ addw ax, #1 @ and a, %Q2 @ xch a, x @ and a, %q2 @ xch a, x" + [(set (attr "update_Z") (const_string "clobber"))] ) Index: config/rl78/rl78-c.c =================================================================== --- config/rl78/rl78-c.c (revision 219790) +++ config/rl78/rl78-c.c (working copy) @@ -36,8 +36,9 @@ #include "rl78-protos.h" /* Implements REGISTER_TARGET_PRAGMAS. */ void rl78_register_pragmas (void) { + c_register_addr_space ("__near", ADDR_SPACE_NEAR); c_register_addr_space ("__far", ADDR_SPACE_FAR); } Index: config/rl78/rl78-virt.md =================================================================== --- config/rl78/rl78-virt.md (revision 219790) +++ config/rl78/rl78-virt.md (working copy) @@ -85,22 +85,22 @@ ;;---------- Arithmetic ------------------------ (define_insn "*add<mode>3_virt" [(set (match_operand:QHI 0 "rl78_nonfar_nonimm_operand" "=vY,S") (plus:QHI (match_operand:QHI 1 "rl78_nonfar_operand" "viY,0") - (match_operand:QHI 2 "general_operand" "vim,i"))) + (match_operand:QHI 2 "rl78_general_operand" "vim,i"))) ] "rl78_virt_insns_ok ()" "v.add\t%0, %1, %2" ) (define_insn "*sub<mode>3_virt" [(set (match_operand:QHI 0 "rl78_nonfar_nonimm_operand" "=vm,S") (minus:QHI (match_operand:QHI 1 "rl78_nonfar_operand" "vim,0") - (match_operand:QHI 2 "general_operand" "vim,i"))) + (match_operand:QHI 2 "rl78_general_operand" "vim,i"))) ] "rl78_virt_insns_ok ()" "v.sub\t%0, %1, %2" ) (define_insn "*umulhi3_shift_virt" @@ -121,31 +121,31 @@ [(set_attr "valloc" "umul")] ) (define_insn "*andqi3_virt" [(set (match_operand:QI 0 "rl78_nonfar_nonimm_operand" "=vm") (and:QI (match_operand:QI 1 "rl78_nonfar_operand" "vim") - (match_operand:QI 2 "general_operand" "vim"))) + (match_operand:QI 2 "rl78_general_operand" "vim"))) ] "rl78_virt_insns_ok ()" "v.and\t%0, %1, %2" ) (define_insn "*iorqi3_virt" [(set (match_operand:QI 0 "rl78_nonfar_nonimm_operand" "=vm") (ior:QI (match_operand:QI 1 "rl78_nonfar_operand" "vim") - (match_operand:QI 2 "general_operand" "vim"))) + (match_operand:QI 2 "rl78_general_operand" "vim"))) ] "rl78_virt_insns_ok ()" "v.or\t%0, %1, %2" ) -(define_insn "*xor3_virt" +(define_insn "*xorqi3_virt" [(set (match_operand:QI 0 "rl78_nonfar_nonimm_operand" "=v,vm,m") (xor:QI (match_operand:QI 1 "rl78_nonfar_operand" "%0,vm,vm") - (match_operand 2 "general_operand" "i,vm,vim"))) + (match_operand 2 "rl78_general_operand" "i,vm,vim"))) ] "rl78_virt_insns_ok ()" "v.xor\t%0, %1, %2" ) ;;---------- Shifts ------------------------ @@ -340,14 +340,14 @@ [(set_attr "valloc" "cmp")] ) (define_insn "*cbranchqi4_virt" [(set (pc) (if_then_else (match_operator 0 "rl78_cmp_operator_real" - [(match_operand:QI 1 "general_operand" "vim") - (match_operand:QI 2 "general_operand" "vim")]) + [(match_operand:QI 1 "rl78_general_operand" "vim") + (match_operand:QI 2 "rl78_general_operand" "vim")]) (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")] ) @@ -364,14 +364,14 @@ [(set_attr "valloc" "cmp")] ) (define_insn "*cbranchhi4_virt" [(set (pc) (if_then_else (match_operator 0 "rl78_cmp_operator_real" - [(match_operand:HI 1 "general_operand" "vim") - (match_operand:HI 2 "general_operand" "vim")]) + [(match_operand:HI 1 "rl78_general_operand" "vim") + (match_operand:HI 2 "rl78_general_operand" "vim")]) (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")] ) Index: config/rl78/rl78.c =================================================================== --- config/rl78/rl78.c (revision 219790) +++ config/rl78/rl78.c (working copy) @@ -82,16 +82,20 @@ #include "dumpfile.h" #include "tree-pass.h" #include "context.h" #include "tm-constrs.h" /* for satisfies_constraint_*(). */ #include "insn-flags.h" /* for gen_*(). */ #include "builtins.h" +#include "stringpool.h" static inline bool is_interrupt_func (const_tree decl); static inline bool is_brk_interrupt_func (const_tree decl); static void rl78_reorg (void); +static const char *rl78_strip_name_encoding (const char *); +static const char *rl78_strip_nonasm_name_encoding (const char *); +static section * rl78_select_section (tree, int, unsigned HOST_WIDE_INT); /* Debugging statements are tagged with DEBUG0 only so that they can be easily enabled individually, by replacing the '0' with '1' as needed. */ #define DEBUG0 0 @@ -315,12 +319,35 @@ rl78_asm_file_start (void) }; register_pass (& rl78_devirt_info); register_pass (& rl78_move_elim_info); } +void +rl78_output_symbol_ref (FILE * file, rtx sym) +{ + tree type = SYMBOL_REF_DECL (sym); + const char *str = XSTR (sym, 0); + + if (str[0] == '*') + { + fputs (str + 1, file); + } + else + { + str = rl78_strip_nonasm_name_encoding (str); + if (type && TREE_CODE (type) == FUNCTION_DECL) + { + fprintf (file, "%%code("); + assemble_name (file, str); + fprintf (file, ")"); + } + else + assemble_name (file, str); + } +} #undef TARGET_OPTION_OVERRIDE #define TARGET_OPTION_OVERRIDE rl78_option_override static void rl78_option_override (void) @@ -335,12 +362,19 @@ rl78_option_override (void) { int i; for (i = 24; i < 32; i++) fixed_regs[i] = 0; } + + if (TARGET_ES0 + && strcmp (lang_hooks.name, "GNU C") + /* Compiling with -flto results in a language of GNU GIMPLE being used... */ + && strcmp (lang_hooks.name, "GNU GIMPLE")) + /* Address spaces are currently only supported by C. */ + error ("-mes0 can only be used with C"); } /* Most registers are 8 bits. Some are 16 bits because, for example, gcc doesn't like dealing with $FP as a register pair (the second half of $fp is also 2 to keep reload happy wrt register pairs, but no register class includes it). This table maps register numbers @@ -692,25 +726,72 @@ rl78_handle_func_attribute (tree * node, /* FIXME: We ought to check that the interrupt and exception handler attributes have been applied to void functions. */ return NULL_TREE; } +/* Check "naked" attributes. */ +static tree +rl78_handle_naked_attribute (tree * node, + tree name ATTRIBUTE_UNUSED, + tree args, + int flags ATTRIBUTE_UNUSED, + bool * no_add_attrs) +{ + gcc_assert (DECL_P (* node)); + gcc_assert (args == NULL_TREE); + + if (TREE_CODE (* node) != FUNCTION_DECL) + { + warning (OPT_Wattributes, "naked attribute only applies to functions"); + * no_add_attrs = true; + } + + /* Disable warnings about this function - eg reaching the end without + seeing a return statement - because the programmer is doing things + that gcc does not know about. */ + TREE_NO_WARNING (* node) = 1; + + return NULL_TREE; +} + +/* Check "saddr" attributes. */ +static tree +rl78_handle_saddr_attribute (tree * node, + tree name, + tree args ATTRIBUTE_UNUSED, + int flags ATTRIBUTE_UNUSED, + bool * no_add_attrs) +{ + gcc_assert (DECL_P (* node)); + + if (TREE_CODE (* node) == FUNCTION_DECL) + { + warning (OPT_Wattributes, "%qE attribute doesn't apply to functions", + name); + * no_add_attrs = true; + } + + return NULL_TREE; +} + #undef TARGET_ATTRIBUTE_TABLE #define TARGET_ATTRIBUTE_TABLE rl78_attribute_table /* Table of RL78-specific attributes. */ const struct attribute_spec rl78_attribute_table[] = { /* Name, min_len, max_len, decl_req, type_req, fn_type_req, handler, affects_type_identity. */ { "interrupt", 0, 0, true, false, false, rl78_handle_func_attribute, false }, { "brk_interrupt", 0, 0, true, false, false, rl78_handle_func_attribute, false }, - { "naked", 0, 0, true, false, false, rl78_handle_func_attribute, + { "naked", 0, 0, true, false, false, rl78_handle_naked_attribute, + false }, + { "saddr", 0, 0, true, false, false, rl78_handle_saddr_attribute, false }, { NULL, 0, 0, false, false, false, NULL, false } }; @@ -745,12 +826,24 @@ characterize_address (rtx x, rtx *base, if (GET_CODE (x) == PLUS) { *base = XEXP (x, 0); x = XEXP (x, 1); + if (GET_CODE (*base) == SUBREG) + { + if (GET_MODE (*base) == HImode + && GET_MODE (XEXP (*base, 0)) == SImode + && GET_CODE (XEXP (*base, 0)) == REG) + { + /* This is a throw-away rtx just to tell everyone + else what effective register we're using. */ + *base = gen_rtx_REG (HImode, REGNO (XEXP (*base, 0))); + } + } + if (GET_CODE (*base) != REG && GET_CODE (x) == REG) { rtx tmp = *base; *base = x; x = tmp; @@ -778,12 +871,24 @@ characterize_address (rtx x, rtx *base, } /* fall through */ case MEM: case REG: return false; + case SUBREG: + switch (GET_CODE (XEXP (x, 0))) + { + case CONST: + case SYMBOL_REF: + case CONST_INT: + *addend = x; + return true; + default: + return false; + } + case CONST: case SYMBOL_REF: case CONST_INT: *addend = x; return true; @@ -825,24 +930,45 @@ rl78_hl_b_c_addr_p (rtx op) return true; } #define REG_IS(r, regno) (((r) == (regno)) || ((r) >= FIRST_PSEUDO_REGISTER && !(strict))) +/* Return the appropriate mode for a named address address. */ + +#undef TARGET_ADDR_SPACE_ADDRESS_MODE +#define TARGET_ADDR_SPACE_ADDRESS_MODE rl78_addr_space_address_mode + +static enum machine_mode +rl78_addr_space_address_mode (addr_space_t addrspace) +{ + switch (addrspace) + { + case ADDR_SPACE_GENERIC: + return HImode; + case ADDR_SPACE_NEAR: + return HImode; + case ADDR_SPACE_FAR: + return SImode; + default: + gcc_unreachable (); + } +} + /* Used in various constraints and predicates to match operands in the "far" address space. */ int rl78_far_p (rtx x) { 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); #endif - return MEM_ADDR_SPACE (x) == ADDR_SPACE_FAR; + return GET_MODE_BITSIZE (rl78_addr_space_address_mode (MEM_ADDR_SPACE (x))) == 32; } /* Return the appropriate mode for a named address pointer. */ #undef TARGET_ADDR_SPACE_POINTER_MODE #define TARGET_ADDR_SPACE_POINTER_MODE rl78_addr_space_pointer_mode @@ -850,12 +976,14 @@ static machine_mode rl78_addr_space_pointer_mode (addr_space_t addrspace) { switch (addrspace) { case ADDR_SPACE_GENERIC: return HImode; + case ADDR_SPACE_NEAR: + return HImode; case ADDR_SPACE_FAR: return SImode; default: gcc_unreachable (); } } @@ -867,29 +995,12 @@ rl78_addr_space_pointer_mode (addr_space static bool rl78_valid_pointer_mode (machine_mode m) { return (m == HImode || m == SImode); } -/* Return the appropriate mode for a named address address. */ -#undef TARGET_ADDR_SPACE_ADDRESS_MODE -#define TARGET_ADDR_SPACE_ADDRESS_MODE rl78_addr_space_address_mode - -static machine_mode -rl78_addr_space_address_mode (addr_space_t addrspace) -{ - switch (addrspace) - { - case ADDR_SPACE_GENERIC: - return HImode; - case ADDR_SPACE_FAR: - return SImode; - default: - gcc_unreachable (); - } -} #undef TARGET_LEGITIMATE_CONSTANT_P #define TARGET_LEGITIMATE_CONSTANT_P rl78_is_legitimate_constant static bool rl78_is_legitimate_constant (machine_mode mode ATTRIBUTE_UNUSED, rtx x ATTRIBUTE_UNUSED) @@ -903,32 +1014,34 @@ rl78_is_legitimate_constant (machine_mod bool rl78_as_legitimate_address (machine_mode mode ATTRIBUTE_UNUSED, rtx x, bool strict ATTRIBUTE_UNUSED, addr_space_t as ATTRIBUTE_UNUSED) { rtx base, index, addend; bool is_far_addr = false; + int as_bits; + + as_bits = GET_MODE_BITSIZE (rl78_addr_space_address_mode (as)); if (GET_CODE (x) == UNSPEC && XINT (x, 1) == UNS_ES_ADDR) { x = XVECEXP (x, 0, 1); is_far_addr = true; } - if (as == ADDR_SPACE_GENERIC - && (GET_MODE (x) == SImode || is_far_addr)) + if (as_bits == 16 && is_far_addr) return false; if (! characterize_address (x, &base, &index, &addend)) return false; /* We can't extract the high/low portions of a PLUS address involving a register during devirtualization, so make sure all such __far addresses do not have addends. This forces GCC to do the sum separately. */ - if (addend && base && as == ADDR_SPACE_FAR) + if (addend && base && as_bits == 32 && GET_MODE (base) == SImode) return false; if (base && index) { int ir = REGNO (index); int br = REGNO (base); @@ -953,55 +1066,69 @@ rl78_as_legitimate_address (machine_mode #undef TARGET_ADDR_SPACE_SUBSET_P #define TARGET_ADDR_SPACE_SUBSET_P rl78_addr_space_subset_p static bool rl78_addr_space_subset_p (addr_space_t subset, addr_space_t superset) { - gcc_assert (subset == ADDR_SPACE_GENERIC || subset == ADDR_SPACE_FAR); - gcc_assert (superset == ADDR_SPACE_GENERIC || superset == ADDR_SPACE_FAR); + int subset_bits; + int superset_bits; - if (subset == superset) - return true; + subset_bits = GET_MODE_BITSIZE (rl78_addr_space_address_mode (subset)); + superset_bits = GET_MODE_BITSIZE (rl78_addr_space_address_mode (superset)); - else - return (subset == ADDR_SPACE_GENERIC && superset == ADDR_SPACE_FAR); + return (subset_bits <= superset_bits); } #undef TARGET_ADDR_SPACE_CONVERT #define TARGET_ADDR_SPACE_CONVERT rl78_addr_space_convert /* Convert from one address space to another. */ static rtx rl78_addr_space_convert (rtx op, tree from_type, tree to_type) { addr_space_t from_as = TYPE_ADDR_SPACE (TREE_TYPE (from_type)); addr_space_t to_as = TYPE_ADDR_SPACE (TREE_TYPE (to_type)); rtx result; + int to_bits; + int from_bits; - gcc_assert (from_as == ADDR_SPACE_GENERIC || from_as == ADDR_SPACE_FAR); - gcc_assert (to_as == ADDR_SPACE_GENERIC || to_as == ADDR_SPACE_FAR); + to_bits = GET_MODE_BITSIZE (rl78_addr_space_address_mode (to_as)); + from_bits = GET_MODE_BITSIZE (rl78_addr_space_address_mode (from_as)); - if (to_as == ADDR_SPACE_GENERIC && from_as == ADDR_SPACE_FAR) + if (to_bits < from_bits) { + rtx tmp; /* This is unpredictable, as we're truncating off usable address bits. */ + warning (OPT_Waddress, "converting far pointer to near pointer"); result = gen_reg_rtx (HImode); - emit_move_insn (result, simplify_subreg (HImode, op, SImode, 0)); + if (GET_CODE (op) == SYMBOL_REF + || (GET_CODE (op) == REG && REGNO (op) >= FIRST_PSEUDO_REGISTER)) + tmp = gen_rtx_raw_SUBREG (HImode, op, 0); + else + tmp = simplify_subreg (HImode, op, SImode, 0); + gcc_assert (tmp != NULL_RTX); + emit_move_insn (result, tmp); return result; } - else if (to_as == ADDR_SPACE_FAR && from_as == ADDR_SPACE_GENERIC) + else if (to_bits > from_bits) { /* This always works. */ result = gen_reg_rtx (SImode); emit_move_insn (rl78_subreg (HImode, result, SImode, 0), op); - emit_move_insn (rl78_subreg (HImode, result, SImode, 2), const0_rtx); + if (TREE_CODE (from_type) == POINTER_TYPE + && TREE_CODE (TREE_TYPE (from_type)) == FUNCTION_TYPE) + emit_move_insn (rl78_subreg (HImode, result, SImode, 2), const0_rtx); + else + emit_move_insn (rl78_subreg (HImode, result, SImode, 2), GEN_INT (0x0f)); return result; } else - gcc_unreachable (); + return op; + gcc_unreachable (); } /* Implements REGNO_MODE_CODE_OK_FOR_BASE_P. */ bool rl78_regno_mode_code_ok_for_base_p (int regno, machine_mode mode ATTRIBUTE_UNUSED, addr_space_t address_space ATTRIBUTE_UNUSED, @@ -1126,25 +1253,26 @@ rl78_expand_prologue (void) for (i = 0; i < 16; i++) if (cfun->machine->need_to_push [i]) { if (TARGET_G10) { if (i != 0) - emit_move_insn (gen_rtx_REG (HImode, 0), gen_rtx_REG (HImode, i * 2)); - F (emit_insn (gen_push (gen_rtx_REG (HImode, 0)))); + emit_move_insn (gen_rtx_REG (HImode, AX_REG), gen_rtx_REG (HImode, i * 2)); + F (emit_insn (gen_push (gen_rtx_REG (HImode, AX_REG)))); } else { - int need_bank = i/4; + int need_bank = i / 4; if (need_bank != rb) { emit_insn (gen_sel_rb (GEN_INT (need_bank))); rb = need_bank; } - F (emit_insn (gen_push (gen_rtx_REG (HImode, i*2)))); + F (emit_insn (gen_push (gen_rtx_REG (HImode, i * 2)))); + } } if (rb != 0) emit_insn (gen_sel_rb (GEN_INT (0))); @@ -1202,23 +1330,23 @@ rl78_expand_epilogue (void) } } if (is_interrupt_func (cfun->decl) && cfun->machine->uses_es) { emit_insn (gen_pop (gen_rtx_REG (HImode, AX_REG))); - emit_insn (gen_movqi_es (gen_rtx_REG (QImode, A_REG))); + emit_insn (gen_movqi_to_es (gen_rtx_REG (QImode, A_REG))); } for (i = 15; i >= 0; i--) if (cfun->machine->need_to_push [i]) { rtx dest = gen_rtx_REG (HImode, i * 2); if (TARGET_G10) { - rtx ax = gen_rtx_REG (HImode, 0); + rtx ax = gen_rtx_REG (HImode, AX_REG); emit_insn (gen_pop (ax)); if (i != 0) { emit_move_insn (dest, ax); /* Generate a USE of the pop'd register so that DCE will not eliminate the move. */ @@ -1412,13 +1540,14 @@ rl78_print_operand_1 (FILE * file, rtx o rl78_print_operand_1 (file, XEXP (op, 0), letter); else { if (rl78_far_p (op)) { fprintf (file, "es:"); - op = gen_rtx_MEM (GET_MODE (op), XVECEXP (XEXP (op, 0), 0, 1)); + if (GET_CODE (XEXP (op, 0)) == UNSPEC) + op = gen_rtx_MEM (GET_MODE (op), XVECEXP (XEXP (op, 0), 0, 1)); } if (letter == 'H') { op = adjust_address (op, HImode, 2); letter = 0; } @@ -1446,28 +1575,32 @@ rl78_print_operand_1 (FILE * file, rtx o { op = adjust_address (op, QImode, 3); letter = 0; } if (CONSTANT_P (XEXP (op, 0))) { - fprintf (file, "!"); + if (!rl78_saddr_p (op)) + 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, "!"); + if (!rl78_saddr_p (op)) + 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)) == REG && REGNO (XEXP (XEXP (op, 0), 0)) == 2) { rl78_print_operand_1 (file, XEXP (XEXP (op, 0), 1), 'u'); fprintf (file, "["); rl78_print_operand_1 (file, XEXP (XEXP (op, 0), 0), 0); + if (letter == 'p' && GET_CODE (XEXP (op, 0)) == REG) + fprintf (file, "+0"); fprintf (file, "]"); } else { fprintf (file, "["); rl78_print_operand_1 (file, XEXP (op, 0), letter); @@ -1510,13 +1643,21 @@ rl78_print_operand_1 (FILE * file, rtx o fprintf (file, "%ld", INTVAL (op) & 0xff); else if (letter == 'h') fprintf (file, "%ld", INTVAL (op) & 0xffff); else if (letter == 'e') fprintf (file, "%ld", (INTVAL (op) >> 16) & 0xff); else if (letter == 'B') - fprintf (file, "%d", exact_log2 (INTVAL (op))); + { + int ival = INTVAL (op); + if (ival == -128) + ival = 0x80; + if (exact_log2 (ival) >= 0) + fprintf (file, "%d", exact_log2 (ival)); + else + fprintf (file, "%d", exact_log2 (~ival & 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); @@ -1594,12 +1735,33 @@ rl78_print_operand_1 (FILE * file, rtx o rl78_print_operand_1 (file, XEXP (op, 1), letter); } if (need_paren) fprintf (file, ")"); break; + case SUBREG: + if (GET_MODE (op) == HImode + && SUBREG_BYTE (op) == 0) + { + fprintf (file, "%%lo16("); + rl78_print_operand_1 (file, SUBREG_REG (op), 0); + fprintf (file, ")"); + } + else if (GET_MODE (op) == HImode + && SUBREG_BYTE (op) == 2) + { + fprintf (file, "%%hi16("); + rl78_print_operand_1 (file, SUBREG_REG (op), 0); + fprintf (file, ")"); + } + else + { + fprintf (file, "(%s)", GET_RTX_NAME (GET_CODE (op))); + } + break; + case SYMBOL_REF: need_paren = 0; if (letter == 'H') { fprintf (file, "%%hi16("); need_paren = 1; @@ -1617,13 +1779,20 @@ rl78_print_operand_1 (FILE * file, rtx o need_paren = 1; letter = 0; } if (letter == 'q' || letter == 'Q') output_operand_lossage ("q/Q modifiers invalid for symbol references"); - output_addr_const (file, op); + if (SYMBOL_REF_DECL (op) && TREE_CODE (SYMBOL_REF_DECL (op)) == FUNCTION_DECL) + { + fprintf (file, "%%code("); + assemble_name (file, rl78_strip_nonasm_name_encoding (XSTR (op, 0))); + fprintf (file, ")"); + } + else + assemble_name (file, rl78_strip_nonasm_name_encoding (XSTR (op, 0))); if (need_paren) fprintf (file, ")"); break; case CODE_LABEL: case LABEL_REF: @@ -2485,94 +2654,93 @@ transcode_memory_rtx (rtx m, rtx newbase if (GET_MODE (XEXP (m, 0)) == SImode) { rtx new_m; rtx seg = rl78_hi8 (XEXP (m, 0)); -#if DEBUG_ALLOC - 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); + if (!TARGET_ES0) + { + emit_insn_before (EM (gen_movqi (A, seg)), before); + emit_insn_before (EM (gen_movqi_to_es (A)), before); + } + record_content (A, NULL_RTX); new_m = gen_rtx_MEM (GET_MODE (m), rl78_lo16 (XEXP (m, 0))); MEM_COPY_ATTRIBUTES (new_m, m); m = new_m; need_es = 1; } 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"); - debug_rtx (base); -#endif if (base == NULL_RTX) return m; if (addendr && GET_CODE (addendr) == CONST_INT) addend = INTVAL (addendr); gcc_assert (REG_P (base)); gcc_assert (REG_P (newbase)); + int limit = 256 - GET_MODE_SIZE (GET_MODE (m)); + if (REGNO (base) == SP_REG) { - if (addend >= 0 && addend <= 255) + if (addend >= 0 && addend <= limit) return m; } /* BASE should be a virtual register. We copy it to NEWBASE. If the addend is out of range for DE/HL, we use AX to compute the full address. */ if (addend < 0 - || (addend > 255 && REGNO (newbase) != 2) - || (addendr && GET_CODE (addendr) != CONST_INT)) + || (addend > limit && REGNO (newbase) != BC_REG) + || (addendr + && (GET_CODE (addendr) != CONST_INT) + && ((REGNO (newbase) != BC_REG)) + )) { /* mov ax, vreg add ax, #imm mov hl, ax */ 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; + addendr = 0; } else { base = gen_and_emit_move (newbase, base, before, true); } if (addend) { record_content (base, NULL_RTX); base = gen_rtx_PLUS (HImode, base, GEN_INT (addend)); } + else if (addendr) + { + record_content (base, NULL_RTX); + base = gen_rtx_PLUS (HImode, base, addendr); + } -#if DEBUG_ALLOC - fprintf (stderr, "\033[33m"); - debug_rtx (m); -#endif if (need_es) { m = change_address (m, GET_MODE (m), gen_es_addr (base)); cfun->machine->uses_es = true; } else m = change_address (m, GET_MODE (m), base); -#if DEBUG_ALLOC - debug_rtx (m); - fprintf (stderr, "\033[0m"); -#endif return m; } /* Copy SRC to accumulator (A or AX), placing any generated insns before BEFORE. Returns accumulator RTX. */ static rtx @@ -2721,13 +2889,19 @@ rl78_alloc_physical_registers_op1 (rtx_i OP (1) = transcode_memory_rtx (OP (1), DE, insn); } else { /* 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. */ + and if so, swap the order. + + It is tempting to perform this optimization when OP(0) does + not hold a MEM, but this leads to bigger code in general. + The problem is that if OP(1) holds a MEM then swapping it + into BC means a BC-relative load is used and these 3 bytes + long vs 1 byte for an HL load. */ 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); } @@ -3808,19 +3982,428 @@ static bool rl78_rtx_costs (rtx x, } } return false; } + + +static GTY(()) section * saddr_section; +static GTY(()) section * frodata_section; + +int +rl78_saddr_p (rtx x) +{ + const char * c; + + if (MEM_P (x)) + x = XEXP (x, 0); + if (GET_CODE (x) == PLUS) + x = XEXP (x, 0); + if (GET_CODE (x) != SYMBOL_REF) + return 0; + + c = XSTR (x, 0); + if (memcmp (c, "@s.", 3) == 0) + return 1; + + return 0; +} + +int +rl78_sfr_p (rtx x) +{ + if (MEM_P (x)) + x = XEXP (x, 0); + if (GET_CODE (x) != CONST_INT) + return 0; + + if ((INTVAL (x) & 0xFF00) != 0xFF00) + return 0; + + return 1; +} + +#undef TARGET_STRIP_NAME_ENCODING +#define TARGET_STRIP_NAME_ENCODING rl78_strip_name_encoding + +static const char * +rl78_strip_name_encoding (const char * sym) +{ + while (1) + { + if (*sym == '*') + sym++; + else if (*sym == '@' && sym[2] == '.') + sym += 3; + else + return sym; + } +} + +/* Like rl78_strip_name_encoding, but does not strip leading asterisks. This + is important if the stripped name is going to be passed to assemble_name() + as that handles asterisk prefixed names in a special manner. */ + +static const char * +rl78_strip_nonasm_name_encoding (const char * sym) +{ + while (1) + { + if (*sym == '@' && sym[2] == '.') + sym += 3; + else + return sym; + } +} + + +static int +rl78_attrlist_to_encoding (tree list, tree decl ATTRIBUTE_UNUSED) +{ + while (list) + { + if (is_attribute_p ("saddr", TREE_PURPOSE (list))) + return 's'; + list = TREE_CHAIN (list); + } + + return 0; +} + +#define RL78_ATTRIBUTES(decl) \ + (TYPE_P (decl)) ? TYPE_ATTRIBUTES (decl) \ + : DECL_ATTRIBUTES (decl) \ + ? (DECL_ATTRIBUTES (decl)) \ + : TYPE_ATTRIBUTES (TREE_TYPE (decl)) + +#undef TARGET_ENCODE_SECTION_INFO +#define TARGET_ENCODE_SECTION_INFO rl78_encode_section_info + +static void +rl78_encode_section_info (tree decl, rtx rtl, int first) +{ + rtx rtlname; + const char * oldname; + char encoding; + char * newname; + tree idp; + tree type; + tree rl78_attributes; + + if (!first) + return; + + rtlname = XEXP (rtl, 0); + + if (GET_CODE (rtlname) == SYMBOL_REF) + oldname = XSTR (rtlname, 0); + else if (GET_CODE (rtlname) == MEM + && GET_CODE (XEXP (rtlname, 0)) == SYMBOL_REF) + oldname = XSTR (XEXP (rtlname, 0), 0); + else + gcc_unreachable (); + + type = TREE_TYPE (decl); + if (type == error_mark_node) + return; + if (! DECL_P (decl)) + return; + rl78_attributes = RL78_ATTRIBUTES (decl); + + encoding = rl78_attrlist_to_encoding (rl78_attributes, decl); + + if (encoding) + { + newname = (char *) alloca (strlen (oldname) + 4); + sprintf (newname, "@%c.%s", encoding, oldname); + idp = get_identifier (newname); + XEXP (rtl, 0) = + gen_rtx_SYMBOL_REF (Pmode, IDENTIFIER_POINTER (idp)); + SYMBOL_REF_WEAK (XEXP (rtl, 0)) = DECL_WEAK (decl); + SET_SYMBOL_REF_DECL (XEXP (rtl, 0), decl); + } +} + +#undef TARGET_ASM_INIT_SECTIONS +#define TARGET_ASM_INIT_SECTIONS rl78_asm_init_sections + +static void +rl78_asm_init_sections (void) +{ + saddr_section + = get_unnamed_section (SECTION_WRITE, output_section_asm_op, + "\t.section .saddr,\"aw\",@progbits"); + frodata_section + = get_unnamed_section (SECTION_WRITE, output_section_asm_op, + "\t.section .frodata,\"aw\",@progbits"); +} + +#undef TARGET_ASM_SELECT_SECTION +#define TARGET_ASM_SELECT_SECTION rl78_select_section + +static section * +rl78_select_section (tree decl, + int reloc ATTRIBUTE_UNUSED, + unsigned HOST_WIDE_INT align ATTRIBUTE_UNUSED) +{ + int readonly = 1; + + switch (TREE_CODE (decl)) + { + case VAR_DECL: + if (!TREE_READONLY (decl) + || TREE_SIDE_EFFECTS (decl) + || !DECL_INITIAL (decl) + || (DECL_INITIAL (decl) != error_mark_node + && !TREE_CONSTANT (DECL_INITIAL (decl)))) + readonly = 0; + break; + case CONSTRUCTOR: + if (! TREE_CONSTANT (decl)) + readonly = 0; + break; + + default: + break; + } + + if (TREE_CODE (decl) == VAR_DECL) + { + const char *name = XSTR (XEXP (DECL_RTL (decl), 0), 0); + + if (name[0] == '@' && name[2] == '.') + switch (name[1]) + { + case 's': + return saddr_section; + } + + if (TYPE_ADDR_SPACE (TREE_TYPE (decl)) == ADDR_SPACE_FAR + && readonly) + { + return frodata_section; + } + } + + if (readonly) + return readonly_data_section; + + return data_section; +} + +void +rl78_output_labelref (FILE *file, const char *str) +{ + const char *str2; + + str2 = targetm.strip_name_encoding (str); + if (str2[0] != '.') + fputs (user_label_prefix, file); + fputs (str2, file); +} + +void +rl78_output_aligned_common (FILE *stream, + tree decl ATTRIBUTE_UNUSED, + const char *name, + int size, int align, int global) +{ + /* We intentionally don't use rl78_section_tag() here. */ + if (name[0] == '@' && name[2] == '.') + { + const char *sec = 0; + switch (name[1]) + { + case 's': + switch_to_section (saddr_section); + sec = ".saddr"; + break; + } + if (sec) + { + const char *name2; + int p2align = 0; + + while (align > BITS_PER_UNIT) + { + align /= 2; + p2align ++; + } + name2 = targetm.strip_name_encoding (name); + if (global) + fprintf (stream, "\t.global\t_%s\n", name2); + fprintf (stream, "\t.p2align %d\n", p2align); + fprintf (stream, "\t.type\t_%s,@object\n", name2); + fprintf (stream, "\t.size\t_%s,%d\n", name2, size); + fprintf (stream, "_%s:\n\t.zero\t%d\n", name2, size); + return; + } + } + + if (!global) + { + fprintf (stream, "\t.local\t"); + assemble_name (stream, name); + fprintf (stream, "\n"); + } + fprintf (stream, "\t.comm\t"); + assemble_name (stream, name); + fprintf (stream, ",%u,%u\n", size, align / BITS_PER_UNIT); +} + +#undef TARGET_INSERT_ATTRIBUTES +#define TARGET_INSERT_ATTRIBUTES rl78_insert_attributes + +static void +rl78_insert_attributes (tree decl, tree *attributes ATTRIBUTE_UNUSED) +{ + if (TARGET_ES0 + && TREE_CODE (decl) == VAR_DECL + && TREE_READONLY (decl) + && TREE_ADDRESSABLE (decl) + && TYPE_ADDR_SPACE (TREE_TYPE (decl)) == ADDR_SPACE_GENERIC) + { + tree type = TREE_TYPE (decl); + tree attr = TYPE_ATTRIBUTES (type); + int q = TYPE_QUALS_NO_ADDR_SPACE (type) | ENCODE_QUAL_ADDR_SPACE (ADDR_SPACE_FAR); + + TREE_TYPE (decl) = build_type_attribute_qual_variant (type, attr, q); + } +} + +#undef TARGET_ASM_INTEGER +#define TARGET_ASM_INTEGER rl78_asm_out_integer + +static bool +rl78_asm_out_integer (rtx x, unsigned int size, int aligned_p) +{ + if (default_assemble_integer (x, size, aligned_p)) + return true; + + if (size == 4) + { + assemble_integer_with_op (".long\t", x); + return true; + } + + return false; +} + + #undef TARGET_UNWIND_WORD_MODE #define TARGET_UNWIND_WORD_MODE rl78_unwind_word_mode static machine_mode rl78_unwind_word_mode (void) { return HImode; } - +#ifndef USE_COLLECT2 +#undef TARGET_ASM_CONSTRUCTOR +#define TARGET_ASM_CONSTRUCTOR rl78_asm_constructor +#undef TARGET_ASM_DESTRUCTOR +#define TARGET_ASM_DESTRUCTOR rl78_asm_destructor + +static void +rl78_asm_ctor_dtor (rtx symbol, int priority, bool is_ctor) +{ + section *sec; + + if (priority != DEFAULT_INIT_PRIORITY) + { + /* This section of the function is based upon code copied + from: gcc/varasm.c:get_cdtor_priority_section(). */ + char buf[16]; + + sprintf (buf, "%s.%.5u", is_ctor ? ".ctors" : ".dtors", + MAX_INIT_PRIORITY - priority); + sec = get_section (buf, 0, NULL); + } + else + sec = is_ctor ? ctors_section : dtors_section; + + assemble_addr_to_section (symbol, sec); +} + +static void +rl78_asm_constructor (rtx symbol, int priority) +{ + rl78_asm_ctor_dtor (symbol, priority, true); +} + +static void +rl78_asm_destructor (rtx symbol, int priority) +{ + rl78_asm_ctor_dtor (symbol, priority, false); +} +#endif /* ! USE_COLLECT2 */ + +/* Scan backwards through the insn chain looking to see if the flags + have been set for a comparison of OP against OPERAND. Start with + the insn *before* the current insn. */ + +bool +rl78_flags_already_set (rtx op, rtx operand) +{ + /* We only track the Z flag. */ + if (GET_CODE (op) != EQ && GET_CODE (op) != NE) + return false; + + /* This should not happen, but let's be paranoid. */ + if (current_output_insn == NULL_RTX) + return false; + + rtx_insn *insn; + bool res = false; + + for (insn = prev_nonnote_nondebug_insn (current_output_insn); + insn != NULL_RTX; + insn = prev_nonnote_nondebug_insn (insn)) + { + if (LABEL_P (insn)) + break; + + if (! INSN_P (insn)) + continue; + + /* Make sure that the insn can be recognized. */ + if (recog_memoized (insn) == -1) + continue; + + enum attr_update_Z updated = get_attr_update_Z (insn); + + rtx set = single_set (insn); + bool must_break = (set != NULL_RTX && rtx_equal_p (operand, SET_DEST (set))); + + switch (updated) + { + case UPDATE_Z_NO: + break; + case UPDATE_Z_CLOBBER: + must_break = true; + break; + case UPDATE_Z_UPDATE_Z: + res = must_break; + must_break = true; + break; + default: + gcc_unreachable (); + } + + if (must_break) + break; + } + + /* We have to re-recognize the current insn as the call(s) to + get_attr_update_Z() above will have overwritten the recog_data cache. */ + recog_memoized (current_output_insn); + cleanup_subreg_operands (current_output_insn); + constrain_operands_cached (current_output_insn, 1); + + return res; +} + struct gcc_target targetm = TARGET_INITIALIZER; #include "gt-rl78.h" Index: config/rl78/rl78.opt =================================================================== --- config/rl78/rl78.opt (revision 219790) +++ config/rl78/rl78.opt (working copy) @@ -50,6 +50,10 @@ mrelax Target Report Optimization Enable assembler and linker relaxation. Enabled by default at -Os. mg10 Target Mask(G10) Report Target the RL78/G10 series + +mes0 +Target Mask(ES0) +Assume ES is zero throughout program execution, use ES: for read-only data.