rl78-real.md (addqi3_real): Allow volatiles.
authorDJ Delorie <dj@redhat.com>
Sat, 17 Jan 2015 02:57:53 +0000 (21:57 -0500)
committerDJ Delorie <dj@gcc.gnu.org>
Sat, 17 Jan 2015 02:57:53 +0000 (21:57 -0500)
* 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.

Co-Authored-By: Nick Clifton <nickc@redhat.com>
From-SVN: r219791

gcc/ChangeLog
gcc/config/rl78/constraints.md
gcc/config/rl78/predicates.md
gcc/config/rl78/rl78-c.c
gcc/config/rl78/rl78-expand.md
gcc/config/rl78/rl78-protos.h
gcc/config/rl78/rl78-real.md
gcc/config/rl78/rl78-virt.md
gcc/config/rl78/rl78.c
gcc/config/rl78/rl78.h
gcc/config/rl78/rl78.opt

index 4f0414a6b1651f10b9891b26c2f2c03996c87805..9b9053a81b321548ff5258da3f1aad3f1c8a9fd2 100644 (file)
@@ -1,3 +1,105 @@
+2015-01-16  DJ Delorie  <dj@redhat.com>
+           Nick Clifton  <nickc@redhat.com>
+
+       * 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.
+
 2015-01-17  Maxim Kuvyrkov  <maxim.kuvyrkov@linaro.org>
 
        * config/arm/arm-protos.h (struct tune_params): New field
index c6cc1a8f5b87d1137643b99b0fa63383425d7495..209f1e660a176c343f15671005278484a6ff40eb 100644 (file)
   (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")
        (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)))
        (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")
 (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 af10ebd2c3af39a8d941361757737883eda6bc91..b89eed22400a3b0c92a9e67d244dd38a540bcd1f 100644 (file)
 ;; along with GCC; see the file COPYING3.  If not see
 ;; <http://www.gnu.org/licenses/>.
 \f
-(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)")))
 )
 
        (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"))
@@ -73,4 +94,6 @@
            (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 8c5d00c0584715648cbd13c55fb1d7df56585971..c8410cdb4cc92ef2d49490e1ab47367399f13cbb 100644 (file)
@@ -39,5 +39,6 @@
 void
 rl78_register_pragmas (void)
 {
+  c_register_addr_space ("__near", ADDR_SPACE_NEAR);
   c_register_addr_space ("__far", ADDR_SPACE_FAR);
 }
index 219f2c0d494168c1941d59199c1392f0bd821617..ac3939d3ea994808d7ffca5616386de2e9c824a8 100644 (file)
 )
 
 (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))
 )
 
 (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))
 )
 
 (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))
index 0a5934e9022c829b1f620da1b957a16c2e41dec2..56d3649376affb98d39345b8e5c5d20953f3de08 100644 (file)
@@ -45,3 +45,11 @@ 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 f92a075658fdc885116f96b95da7c63c0d7760b4..8ec2f3d6a6f5a2f91bbb7f522aaa3dceb179a100 100644 (file)
 ;; 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"))]
   ""
@@ -51,8 +59,8 @@
 )
 
 (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
    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
 ;;---------- 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"
    ]
   "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"
 )
 
 (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 ------------------------
    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"
    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")]
 )
 
 ;;----------
    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"
    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")]
 )
 
 ;;----------
    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"
    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 ------------------------
   "@
    call\t!!%A0
    call\t%A0"
+  [(set (attr "update_Z") (const_string "clobber"))]
   )
 
 (define_insn "*call_value_real"
   "@
    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"
              (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)))
    ]
   "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)))
    ]
   "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"
    ]
   "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"
    (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:
                      (pc)))]
   ""
   "bf\tA.%B0, $%1"
+  [(set (attr "update_Z") (const_string "clobber"))]
 )
 
 (define_insn "bt"
                      (pc)))]
   ""
   "bt\tA.%B0, $%1"
+  [(set (attr "update_Z") (const_string "clobber"))]
 )
 
 ;; NOTE: These peepholes are fragile.  They rely upon GCC generating
    ]
   "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 c24b939f5d7cb2ca18e00e6eedc1fdfce0eeefd6..fadcbc5043301a0cf306ca4930851b35b9e4c74b 100644 (file)
@@ -88,7 +88,7 @@
 (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"
@@ -97,7 +97,7 @@
 (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 "*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"
 (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 ()"
 (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 ()"
index 6b199a6ea0ff6072c45a9f5f7594d888cc566b94..4cf271c9b8372d8bfb1484dc0f3c621f6c4dab28 100644 (file)
 #include "tm-constrs.h" /* for satisfies_constraint_*().  */
 #include "insn-flags.h" /* for gen_*().  */
 #include "builtins.h"
+#include "stringpool.h"
 \f
 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);
 \f
 
 /* Debugging statements are tagged with DEBUG0 only so that they can
@@ -318,6 +322,29 @@ rl78_asm_file_start (void)
   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);
+    }
+}
 \f
 #undef  TARGET_OPTION_OVERRIDE
 #define TARGET_OPTION_OVERRIDE         rl78_option_override
@@ -338,6 +365,13 @@ rl78_option_override (void)
       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,
@@ -695,6 +729,51 @@ rl78_handle_func_attribute (tree * node,
   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
 
@@ -707,7 +786,9 @@ const struct attribute_spec rl78_attribute_table[] =
     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 }
 };
@@ -748,6 +829,18 @@ characterize_address (rtx x, rtx *base, rtx *index, rtx *addend)
       *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)
        {
@@ -781,6 +874,18 @@ characterize_address (rtx x, rtx *base, rtx *index, rtx *addend)
     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:
@@ -828,6 +933,27 @@ rl78_hl_b_c_addr_p (rtx op)
 
 #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
@@ -839,7 +965,7 @@ rl78_far_p (rtx x)
   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.  */
@@ -853,6 +979,8 @@ rl78_addr_space_pointer_mode (addr_space_t addrspace)
     {
     case ADDR_SPACE_GENERIC:
       return HImode;
+    case ADDR_SPACE_NEAR:
+      return HImode;
     case ADDR_SPACE_FAR:
       return SImode;
     default:
@@ -870,23 +998,6 @@ 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
@@ -906,6 +1017,9 @@ rl78_as_legitimate_address (machine_mode mode ATTRIBUTE_UNUSED, rtx x,
 {
   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)
@@ -914,8 +1028,7 @@ rl78_as_legitimate_address (machine_mode mode ATTRIBUTE_UNUSED, rtx x,
       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))
@@ -925,7 +1038,7 @@ rl78_as_legitimate_address (machine_mode mode ATTRIBUTE_UNUSED, rtx x,
      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)
@@ -956,14 +1069,13 @@ rl78_as_legitimate_address (machine_mode mode ATTRIBUTE_UNUSED, rtx x,
 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
@@ -976,29 +1088,44 @@ 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.  */
@@ -1129,19 +1256,20 @@ rl78_expand_prologue (void)
        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))));
+
          }
       }
 
@@ -1205,7 +1333,7 @@ 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--)
@@ -1215,7 +1343,7 @@ rl78_expand_epilogue (void)
 
        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)
@@ -1415,7 +1543,8 @@ rl78_print_operand_1 (FILE * file, rtx op, int letter)
          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')
            {
@@ -1449,13 +1578,15 @@ rl78_print_operand_1 (FILE * file, rtx op, int letter)
            }
          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
@@ -1465,6 +1596,8 @@ rl78_print_operand_1 (FILE * file, rtx op, int letter)
              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
@@ -1513,7 +1646,15 @@ rl78_print_operand_1 (FILE * file, rtx op, int letter)
       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')
@@ -1597,6 +1738,27 @@ rl78_print_operand_1 (FILE * file, rtx op, int letter)
        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')
@@ -1620,7 +1782,14 @@ rl78_print_operand_1 (FILE * file, rtx op, int letter)
       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;
@@ -2488,12 +2657,12 @@ transcode_memory_rtx (rtx m, rtx newbase, rtx before)
       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)));
@@ -2505,10 +2674,6 @@ transcode_memory_rtx (rtx m, rtx newbase, rtx before)
   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;
 
@@ -2518,9 +2683,11 @@ transcode_memory_rtx (rtx m, rtx newbase, rtx before)
   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;
     }
 
@@ -2529,8 +2696,11 @@ transcode_memory_rtx (rtx m, rtx newbase, rtx before)
      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
@@ -2543,6 +2713,7 @@ transcode_memory_rtx (rtx m, rtx newbase, rtx before)
 
       base = newbase;
       addend = 0;
+      addendr = 0;
     }
   else
     {
@@ -2554,11 +2725,12 @@ transcode_memory_rtx (rtx m, rtx newbase, rtx before)
       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));
@@ -2566,10 +2738,6 @@ transcode_memory_rtx (rtx m, rtx newbase, rtx before)
     }
   else
     m = change_address (m, GET_MODE (m), base);
-#if DEBUG_ALLOC
-  debug_rtx (m);
-  fprintf (stderr, "\033[0m");
-#endif
   return m;
 }
 
@@ -2724,7 +2892,13 @@ rl78_alloc_physical_registers_op1 (rtx_insn * 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.  */
+        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)))
        {
@@ -3811,6 +3985,311 @@ static bool rl78_rtx_costs (rtx   x,
 }
 \f
 
+\f
+
+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;
+}
+\f
 #undef  TARGET_UNWIND_WORD_MODE
 #define TARGET_UNWIND_WORD_MODE rl78_unwind_word_mode
 
@@ -3820,7 +4299,111 @@ rl78_unwind_word_mode (void)
   return HImode;
 }
 
-\f
+#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;
+}
\f
 struct gcc_target targetm = TARGET_INITIALIZER;
 
 #include "gt-rl78.h"
index f1f719a6cddab2f74196d690102670409c40e336..d7ec21c0c8535164f299e314db918078aff6068c 100644 (file)
 
 #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
@@ -241,6 +242,8 @@ enum reg_class
   "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,  */            \
@@ -424,6 +427,16 @@ typedef unsigned int CUMULATIVE_ARGS;
   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                                           \
     {                                          \
index ba94201bfd4bc3158d3d8dea10d4f623d3b771d8..1e4c14c706e0774619d9eb9dfb1c113dc05ec78f 100644 (file)
@@ -53,3 +53,7 @@ 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.