--- /gcc/config/m32c/addsub.md	2008-01-15 11:37:31.000000000 +0530
+++ /gcc/config/m32c/addsub.md	2008-01-15 12:02:42.000000000 +0530
@@ -35,25 +35,44 @@
 
 (define_insn "addhi3"
   [(set (match_operand:HI 0 "m32c_nonimmediate_operand"
-	 	  "=SdRhi,SdRhi,??Rmm,??Rmm, SdRhi,??Rmm, Rhi, Raw, Raw, !Rsp")
-	(plus:HI (match_operand:HI 1 "m32c_any_operand"
-		  "%0,0,0,0, 0,0, Raw, Rfb, Rfb, 0")
-		 (match_operand:HI 2 "m32c_any_operand"
-		  "IU2sSdRhi,?Rmm,IU2sSdRhi,?Rmm, IM2,IM2, IS2IU2, I00, IS1, i")))]
+                  "=SdRhi,SdRhi,??Rmm,??Rmm, SdRhi,??Rmm, Rhi, Raw, Raw, !Rsp")
+        (plus:HI (match_operand:HI 1 "m32c_any_operand"
+                  "%0,0,0,0, 0,0, Raw, Rfb, Rfb, 0")
+                 (match_operand:HI 2 "m32c_any_operand"
+                  "IU2sSdRhi,?Rmm,IU2sSdRhi,?Rmm, IM2,IM2, IS2IU2, I00, IS1, i")))]
   ""
-  "@
-   add.w\t%2,%0
-   add.w\t%2,%0
-   add.w\t%2,%0
-   add.w\t%2,%0
-   sub.w\t%m2,%0
-   sub.w\t%m2,%0
-   mova\t%d2[%1],%0
-   stc\t%1,%0
-   mova\t%D2[%1],%0
-   add.w\t%2,%0"
-  [(set_attr "flags" "oszc,oszc,oszc,oszc,oszc,oszc,n,n,n,oszc")]
-  )
+  "*
+   switch (which_alternative)
+    {
+    case 0:
+      if (TARGET_A16 
+	  && GET_CODE (operands[2]) == SYMBOL_REF
+	  && far_data_p (operands[2])== 1
+	  && near_data_p (operands[2])== 0)
+        return m32c_disp_pattern (insn, operands);
+      else 
+        return \"add.w\t%2,%0\";
+    case 1:
+      return \"add.w\t%2,%0\";
+    case 2:
+     return \"add.w\t%2,%0\";
+    case 3:
+      return \"add.w\t%2,%0\";
+    case 4:
+      return \"sub.w\t%m2,%0\";
+    case 5:
+      return \"sub.w\t%m2,%0\";
+    case 6:
+      return \"mova\t%d2[%1],%0\";
+    case 7:
+      return \"stc\t%1,%0\";
+    case 8:
+      return \"mova\t%D2[%1],%0\";
+    case 9:
+      return \"add.w\t%2,%0\";
+}"
+   [(set_attr "flags" "oszc,oszc,oszc,oszc,oszc,oszc,n,n,n,oszc")]
+   )
 
 (define_insn "addpsi3"
   [(set (match_operand:PSI 0 "m32c_nonimmediate_operand" "=Rpi,Raa,SdRpi,SdRpi,Rsp*Rmm, Rpi,Rpi")
--- /gcc/config/m32c/m32c.c	2008-01-15 12:05:59.000000000 +0530
+++ /gcc/config/m32c/m32c.c	2008-01-15 12:02:05.000000000 +0530
@@ -61,6 +61,8 @@ typedef enum
 static tree interrupt_handler (tree *, tree, tree, int, bool *);
 static tree function_vector_handler (tree *, tree, tree, int, bool *);
 static int interrupt_p (tree node);
+static tree far_data_handler (tree *, tree, tree, int, bool *);
+static tree near_data_handler (tree *, tree, tree, int, bool *);
 static bool m32c_asm_integer (rtx, unsigned int, int);
 static int m32c_comp_type_attributes (tree, tree);
 static bool m32c_fixed_condition_code_regs (unsigned int *, unsigned int *);
@@ -74,6 +76,7 @@ static bool m32c_strict_argument_naming 
 static rtx m32c_struct_value_rtx (tree, int);
 static rtx m32c_subreg (enum machine_mode, rtx, enum machine_mode, int);
 static int need_to_save (int);
+static section * m32c_select_section (tree, int, unsigned HOST_WIDE_INT);
 int current_function_special_page_vector (rtx);
 
 #define SYMBOL_FLAG_FUNCVEC_FUNCTION    (SYMBOL_FLAG_MACH_DEP << 0)
@@ -980,6 +983,18 @@ m32c_extra_constraint_p2 (rtx value, cha
 	return 0;
       return m32c_legitimate_address_p (GET_MODE (value), XEXP (value, 0), 1);
     }
+  else if (memcmp (str, "Sc", 2) == 0)
+    {
+      rtx r;
+      if (RTX_IS ("m+rs"))
+        {
+          if (REGNO (patternr[2]) == A0_REGNO)
+            return 1;
+          else
+            return 0;
+        }
+      return 0;
+    }
   else if (memcmp (str, "Sa", 2) == 0)
     {
       rtx r;
@@ -995,6 +1010,10 @@ m32c_extra_constraint_p2 (rtx value, cha
     {
       return (RTX_IS ("mi") || RTX_IS ("ms") || RTX_IS ("m+si"));
     }
+  else if (memcmp (str, "Sn", 2) == 0)
+    {
+      return (RTX_IS ("ms") || RTX_IS ("m+si"));
+    }
   else if (memcmp (str, "Ss", 2) == 0)
     {
       return ((RTX_IS ("mr")
@@ -2318,6 +2337,29 @@ m32c_print_operand (FILE * file, rtx x, 
       unsigned_const = 1;
       code = 0;
     }
+  if (code == 'z')
+    {
+      assemble_name (file, XSTR (x, 0));
+      return;
+    }
+  if (code == 'Z')
+    {
+      assemble_name (file, XSTR (x, 0));
+      fprintf (file,"+2");
+      return;
+    }
+  if (code == 'y')
+    {
+      assemble_name (file, XSTR (x, 0));
+      fprintf (file,"+4");
+      return;
+    }
+  if (code == 'Y')
+    {
+      assemble_name (file, XSTR (x, 0));
+      fprintf (file,"+6");
+      return;
+    }
   /* This one is only for debugging; you can put it in a pattern to
      force this error.  */
   if (code == '!')
@@ -2714,6 +2756,514 @@ interrupt_p (tree node ATTRIBUTE_UNUSED)
   return 0;
 }
 
+/* Returns TRUE if given tree has the "far" attribute.  */
+int
+far_data_p (rtx x)
+{
+  tree t = SYMBOL_REF_DECL (x);
+  if (t == NULL)
+    return 0;
+  if (GET_CODE (x) == SYMBOL_REF)
+    {
+      if (TREE_CODE (t) != VAR_DECL)
+        return 0;
+      if (TARGET_M16C && TREE_READONLY (t) && (!TYPE_VOLATILE (t)))
+        {
+          return 1;
+        }
+      tree list = M32C_ATTRIBUTES (t);
+      while (list)
+        {
+          if (is_attribute_p ("far", TREE_PURPOSE (list)))
+            return 1;
+
+          list = TREE_CHAIN (list);
+        }
+    }
+  return 0;
+}
+
+/* Returns TRUE if given tree has the "far" attribute.  */
+int
+far_data_a1a0 (rtx x)
+{
+  tree t = MEM_EXPR (x);
+  if (t == NULL)
+    return 0;
+  if (GET_CODE (XEXP (x, 0)) == REG)
+    {
+      if (TREE_CODE (t) != VAR_DECL)
+        return 0;
+
+      if (TARGET_M16C && TREE_READONLY (t) && (!TYPE_VOLATILE (t)))
+        {
+          return 1;
+        }
+
+      tree list = M32C_ATTRIBUTES (t);
+      while (list)
+        {
+          if (is_attribute_p ("far", TREE_PURPOSE (list)))
+            return 1;
+          list = TREE_CHAIN (list);
+        }
+    }
+  return 0;
+}
+
+static tree
+far_data_handler (tree * node, tree name,
+                  tree args ATTRIBUTE_UNUSED,
+                  int flags ATTRIBUTE_UNUSED, bool * no_add_attrs)
+{
+  if (!TARGET_R8C && !TARGET_M16C)
+    {
+      warning (OPT_Wattributes,
+               "%qs attribute is supported only for R8C and M16C targets, attribute ignored",
+               IDENTIFIER_POINTER (name));
+      *no_add_attrs = true;
+      return NULL_TREE;
+    }
+  if (TREE_CODE (*node) != VAR_DECL)
+    {
+      warning (OPT_Wattributes, "%qs attribute only applies to variables",
+               IDENTIFIER_POINTER (name));
+      *no_add_attrs = true;
+      return NULL_TREE;
+    }
+  if (TARGET_R8C)
+    {
+      if (TREE_STATIC (*node) || DECL_EXTERNAL (*node))
+        {
+          if (!TREE_READONLY (*node) || (TYPE_VOLATILE (*node)))
+            {
+              warning (OPT_Wattributes,
+                       "for R8C targets %qs attribute applies only for constants, attribute ignored",
+                       IDENTIFIER_POINTER (name));
+              *no_add_attrs = true;
+              return NULL_TREE;
+            }
+        }
+    }
+  if (TREE_STATIC (*node) || DECL_EXTERNAL (*node))
+    {
+      if (TREE_READONLY (*node) && (!TYPE_VOLATILE (*node)))
+        DECL_SECTION_NAME (*node) = build_string (9, ".frodata");
+      else if (DECL_INITIAL (*node))
+        DECL_SECTION_NAME (*node) = build_string (7, ".fdata");
+      else if (*node && TREE_CODE (*node) == VAR_DECL
+               && DECL_INITIAL (*node) == NULL_TREE)
+        DECL_SECTION_NAME (*node) = build_string (6, ".fbss");
+    }
+  return NULL_TREE;
+}
+
+/* Returns TRUE if given tree has the "near" attribute.  */
+int
+near_data_p (rtx x)
+{
+  tree t = SYMBOL_REF_DECL (x);
+  if (t == NULL)
+    return 0;
+  if (GET_CODE (x) == SYMBOL_REF)
+    {
+      if (TREE_CODE (t) != VAR_DECL)
+        return 0;
+      tree list = M32C_ATTRIBUTES (t);
+
+      while (list)
+        {
+          if (is_attribute_p ("near", TREE_PURPOSE (list)))
+            return 1;
+          list = TREE_CHAIN (list);
+        }
+    }
+  return 0;
+}
+
+/* Returns TRUE if given tree has the "near" attribute.  */
+near_data_a1a0 (rtx x)
+{
+  tree t = MEM_EXPR (x);
+  if (t == NULL)
+    return 0;
+
+  if (GET_CODE (XEXP (x, 0)) == REG)
+    {
+
+      if (TREE_CODE (t) != VAR_DECL)
+        return 0;
+      tree list = M32C_ATTRIBUTES (t);
+      while (list)
+        {
+          if (is_attribute_p ("near", TREE_PURPOSE (list)))
+            return 1;
+
+          list = TREE_CHAIN (list);
+        }
+    }
+  return 0;
+}
+
+static tree
+near_data_handler (tree * node, tree name,
+                   tree args ATTRIBUTE_UNUSED,
+                   int flags ATTRIBUTE_UNUSED, bool * no_add_attrs)
+{
+  if (!TARGET_M16C)
+    {
+      warning (OPT_Wattributes,
+               "%qs attribute is supported only for M16C targets, attribute ignored",
+               IDENTIFIER_POINTER (name));
+      *no_add_attrs = true;
+      return NULL_TREE;
+    }
+  if (TREE_CODE (*node) != VAR_DECL)
+    {
+      warning (OPT_Wattributes, "%qs attribute only applies to variables",
+               IDENTIFIER_POINTER (name));
+      *no_add_attrs = true;
+      return NULL_TREE;
+    }
+  if (TREE_STATIC (*node) || DECL_EXTERNAL (*node))
+    {
+      if (TREE_READONLY (*node) && (!TYPE_VOLATILE (*node)))
+        DECL_SECTION_NAME (*node) = build_string (9, ".nrodata");
+      else if (DECL_INITIAL (*node))
+        DECL_SECTION_NAME (*node) = build_string (7, ".ndata");
+      else if (*node && TREE_CODE (*node) == VAR_DECL
+               && DECL_INITIAL (*node) == NULL_TREE)
+        DECL_SECTION_NAME (*node) = build_string (6, ".nbss");
+    }
+  return NULL_TREE;
+}
+
+/* Copy the constant string from '.rodata' section in far memory to
+ 'data' section in near memory  */
+section *
+m32c_select_section (tree decl, int reloc,
+                     unsigned HOST_WIDE_INT align ATTRIBUTE_UNUSED)
+{
+  if (DECL_P (decl))
+    {
+      if (decl_readonly_section (decl, reloc))
+        return readonly_data_section;
+    }
+  else if (TREE_CODE (decl) == CONSTRUCTOR)
+    {
+      if (!((flag_pic && reloc)
+            || !TREE_READONLY (decl)
+            || TREE_SIDE_EFFECTS (decl) || !TREE_CONSTANT (decl)))
+        return readonly_data_section;
+    }
+  else if (TREE_CODE (decl) == STRING_CST)
+    {
+      if (TARGET_M16C)
+        {
+          return data_section;
+        }
+      else
+        {
+          return readonly_data_section;
+        }
+    }
+  else if (!(flag_pic && reloc))
+    return readonly_data_section;
+
+  return data_section;
+}
+
+/* Returns the instructions to access array elements using the
+   displacement.  */
+char *
+m32c_disp_pattern (rtx insn, rtx * operands)
+{
+  rtx x, y, z, start, end, start1, start2, start3;
+  start = NEXT_INSN (insn);
+  start1 = NEXT_INSN (start);
+  start2 = NEXT_INSN (start1);
+  start3 = NEXT_INSN (start2);
+  x = (operands[2]);
+  end = PATTERN (start);
+  if (TARGET_A16 && INSN_CODE (insn) == CODE_FOR_addhi3
+      && (INSN_CODE (start) == CODE_FOR_movhi_op
+          || INSN_CODE (start) == CODE_FOR_movsi_splittable)
+      && GET_CODE (x) == SYMBOL_REF && far_data_p (x) == 1
+      && near_data_p (x) == 0 && GET_CODE (operands[0]) == REG
+      && REGNO (operands[0]) == A0_REGNO)
+    {
+      if ((INSN_CODE (start1) == CODE_FOR_movhi_op)
+          && (INSN_CODE (start2) == CODE_FOR_movhi_op)
+          && (INSN_CODE (start3) == CODE_FOR_movhi_op)
+          && REGNO (XEXP (PATTERN (start), 0)) == R0_REGNO
+          && GET_CODE (XEXP (PATTERN (start), 1)) == MEM
+          && REGNO (XEXP (XEXP (PATTERN (start), 1), 0)) == A0_REGNO
+          && REGNO (XEXP (PATTERN (start1), 0)) == R2_REGNO
+          && GET_CODE (XEXP (PATTERN (start1), 1)) == MEM
+          && GET_CODE (XEXP (XEXP (PATTERN (start1), 1), 0)) == PLUS
+          && REGNO (XEXP (XEXP (XEXP (PATTERN (start1), 1), 0), 0)) ==
+          A0_REGNO)
+        {
+          output_asm_insn ("lde.w  %z2[a0],r0", operands);
+          output_asm_insn ("lde.w  %Z2[a0],r2", operands);
+          output_asm_insn ("lde.w  %y2[a0],r1", operands);
+          output_asm_insn ("lde.w  %Y2[a0],r3", operands);
+          delete_insn (insn);
+          delete_insn (start);
+          delete_insn (start1);
+          delete_insn (start2);
+          delete_insn (start3);
+          return "";
+        }
+      else if ((INSN_CODE (start1) == CODE_FOR_movhi_op)
+               && (INSN_CODE (start2) == CODE_FOR_movhi_op)
+               && (INSN_CODE (start3) == CODE_FOR_movhi_op)
+               && REGNO (XEXP (PATTERN (start3), 0)) == R0_REGNO
+               && REGNO (XEXP (PATTERN (start2), 0)) == R2_REGNO
+               && GET_CODE (XEXP (PATTERN (start2), 1)) == MEM
+               && GET_CODE (XEXP (XEXP (PATTERN (start2), 1), 0)) == PLUS
+               && REGNO (XEXP (XEXP (XEXP (PATTERN (start2), 1), 0), 0)) ==
+               A0_REGNO)
+        {
+          output_asm_insn ("lde.w  %Y2[a0],r0", operands);
+          output_asm_insn ("lde.w  %y2[a0],r2", operands);
+          output_asm_insn ("lde.w  %Z2[a0],r1", operands);
+          output_asm_insn ("lde.w  %z2[a0],r3", operands);
+          delete_insn (insn);
+          delete_insn (start);
+          delete_insn (start1);
+          delete_insn (start2);
+          delete_insn (start3);
+          return "";
+        }
+      else if ((INSN_CODE (start1) == CODE_FOR_movhi_op)
+               && (REGNO (XEXP (PATTERN (start), 0)) == R0_REGNO
+                   || REGNO (XEXP (PATTERN (start), 0)) == R1_REGNO)
+               && GET_CODE (XEXP (PATTERN (start), 1)) == MEM
+               && REGNO (XEXP (XEXP (PATTERN (start), 1), 0)) == A0_REGNO
+               && (REGNO (XEXP (PATTERN (start1), 0)) == R2_REGNO
+                   || REGNO (XEXP (PATTERN (start1), 0)) == R3_REGNO))
+        {
+          if (REGNO (XEXP (PATTERN (start), 0)) == R0_REGNO)
+            {
+              output_asm_insn ("lde.w  %z2[a0],r0", operands);
+              output_asm_insn ("lde.w  %Z2[a0],r2", operands);
+            }
+          else
+            {
+              output_asm_insn ("lde.w  %z2[a0],r1", operands);
+              output_asm_insn ("lde.w  %Z2[a0],r3", operands);
+            }
+          delete_insn (insn);
+          delete_insn (start);
+          delete_insn (start1);
+          return "";
+        }
+      else if ((INSN_CODE (start1) == CODE_FOR_movhi_op)
+               && (REGNO (XEXP (PATTERN (start1), 0)) == R0_REGNO
+                   || REGNO (XEXP (PATTERN (start1), 0)) == R1_REGNO)
+               && (REGNO (XEXP (PATTERN (start), 0)) == R2_REGNO
+                   || REGNO (XEXP (PATTERN (start), 0)) == R3_REGNO)
+               && GET_CODE (XEXP (XEXP (PATTERN (start), 1), 0)) == PLUS
+               && REGNO (XEXP (XEXP (XEXP (PATTERN (start), 1), 0), 0)) ==
+               A0_REGNO)
+        {
+          if (REGNO (XEXP (PATTERN (start1), 0)) == R0_REGNO)
+            {
+              output_asm_insn ("lde.w  %Z2[a0],r0", operands);
+              output_asm_insn ("lde.w  %z2[a0],r2", operands);
+            }
+          else
+            {
+              output_asm_insn ("lde.w  %Z2[a0],r1", operands);
+              output_asm_insn ("lde.w  %z2[a0],r3", operands);
+            }
+          delete_insn (insn);
+          delete_insn (start);
+          delete_insn (start1);
+          return "";
+        }
+      else if (INSN_CODE (start) == CODE_FOR_movsi_splittable
+               && GET_MODE (XEXP (PATTERN (start), 0)) == SImode
+               && GET_CODE (XEXP (PATTERN (start), 0)) == REG
+               && (REGNO (XEXP (PATTERN (start), 0)) == R0_REGNO
+                   || REGNO (XEXP (PATTERN (start), 0)) == R1_REGNO)
+               && GET_CODE (XEXP (PATTERN (start), 1)) == MEM
+               && GET_CODE (XEXP (XEXP (PATTERN (start), 1), 0)) == REG
+               && REGNO (XEXP (XEXP (PATTERN (start), 1), 0)) == A0_REGNO)
+        {
+          if (REGNO (XEXP (PATTERN (start), 0)) == R0_REGNO)
+            {
+              output_asm_insn ("lde.w   %Z2[a0],r2", operands);
+              output_asm_insn ("lde.w   %z2[a0],r0", operands);
+            }
+          else
+            {
+              output_asm_insn ("lde.w   %Z2[a0],r3", operands);
+              output_asm_insn ("lde.w   %z2[a0],r1", operands);
+            }
+          delete_insn (insn);
+          delete_insn (start);
+          return "";
+        }
+      else if ((INSN_CODE (start) == CODE_FOR_movhi_op)
+               && GET_CODE (XEXP (PATTERN (start), 1)) == MEM
+               && GET_CODE (XEXP (XEXP (PATTERN (start), 1), 0)) == REG
+               && REGNO (XEXP (XEXP (PATTERN (start), 1), 0)) == A0_REGNO
+               && GET_CODE (XEXP (PATTERN (start), 0)) == REG)
+        {
+          operands[0] = XEXP (PATTERN (start), 0);
+          output_asm_insn ("lde.w  %z2[a0],%0", operands);
+          delete_insn (insn);
+          delete_insn (start);
+          return "";
+        }
+      else if ((INSN_CODE (start1) == CODE_FOR_movhi_op)
+               && (INSN_CODE (start2) == CODE_FOR_movhi_op)
+               && (INSN_CODE (start3) == CODE_FOR_movhi_op)
+               && REGNO (XEXP (PATTERN (start), 1)) == R0_REGNO
+               && GET_CODE (XEXP (PATTERN (start), 0)) == MEM
+               && REGNO (XEXP (XEXP (PATTERN (start), 0), 0)) == A0_REGNO
+               && REGNO (XEXP (PATTERN (start1), 1)) == R2_REGNO
+               && GET_CODE (XEXP (PATTERN (start1), 0)) == MEM
+               && GET_CODE (XEXP (XEXP (PATTERN (start1), 0), 0)) == PLUS
+               && REGNO (XEXP (XEXP (XEXP (PATTERN (start1), 0), 0), 0)) ==
+               A0_REGNO)
+        {
+          output_asm_insn ("ste.w   r0,%z2[a0]", operands);
+          output_asm_insn ("ste.w   r2,%Z2[a0]", operands);
+          output_asm_insn ("ste.w   r1,%y2[a0]", operands);
+          output_asm_insn ("ste.w   r3,%Y2[a0]", operands);
+          delete_insn (insn);
+          delete_insn (start);
+          delete_insn (start1);
+          delete_insn (start2);
+          delete_insn (start3);
+          return "";
+        }
+      else if ((INSN_CODE (start1) == CODE_FOR_movhi_op)
+               && (INSN_CODE (start2) == CODE_FOR_movhi_op)
+               && (INSN_CODE (start3) == CODE_FOR_movhi_op)
+               && REGNO (XEXP (PATTERN (start3), 1)) == R0_REGNO
+               && REGNO (XEXP (PATTERN (start2), 1)) == R2_REGNO
+               && GET_CODE (XEXP (PATTERN (start2), 0)) == MEM
+               && GET_CODE (XEXP (XEXP (PATTERN (start2), 0), 0)) == PLUS
+               && REGNO (XEXP (XEXP (XEXP (PATTERN (start2), 0), 0), 0)) ==
+               A0_REGNO)
+        {
+          output_asm_insn ("ste.w   r0,%Y2[a0]", operands);
+          output_asm_insn ("ste.w   r2,%y2[a0]", operands);
+          output_asm_insn ("ste.w   r1,%Z2[a0]", operands);
+          output_asm_insn ("ste.w   r3,%z2[a0]", operands);
+          delete_insn (insn);
+          delete_insn (start);
+          delete_insn (start1);
+          delete_insn (start2);
+          delete_insn (start3);
+          return "";
+        }
+      else if ((INSN_CODE (start1) == CODE_FOR_movhi_op)
+               && (REGNO (XEXP (PATTERN (start), 1)) == R0_REGNO
+                   || REGNO (XEXP (PATTERN (start), 1)) == R1_REGNO)
+               && GET_CODE (XEXP (PATTERN (start), 0)) == MEM
+               && REGNO (XEXP (XEXP (PATTERN (start), 0), 0)) == A0_REGNO
+               && (REGNO (XEXP (PATTERN (start1), 1)) == R2_REGNO
+                   || REGNO (XEXP (PATTERN (start1), 1)) == R3_REGNO)
+               && GET_CODE (XEXP (PATTERN (start1), 0)) == MEM
+               && GET_CODE (XEXP (XEXP (PATTERN (start1), 0), 0)) == PLUS
+               && REGNO (XEXP (XEXP (XEXP (PATTERN (start1), 0), 0), 0)) ==
+               A0_REGNO)
+        {
+          if (REGNO (XEXP (PATTERN (start), 1)) == R0_REGNO)
+            {
+              output_asm_insn ("ste.w   r0,%z2[a0]", operands);
+              output_asm_insn ("ste.w   r2,%Z2[a0]", operands);
+            }
+          else
+            {
+              output_asm_insn ("ste.w   r1,%z2[a0]", operands);
+              output_asm_insn ("ste.w   r3,%Z2[a0]", operands);
+            }
+          delete_insn (insn);
+          delete_insn (start);
+          delete_insn (start1);
+          return "";
+        }
+      else if ((INSN_CODE (start1) == CODE_FOR_movhi_op)
+               && (REGNO (XEXP (PATTERN (start1), 1)) == R0_REGNO
+                   || REGNO (XEXP (PATTERN (start1), 1)) == R1_REGNO)
+               && (REGNO (XEXP (PATTERN (start), 1)) == R2_REGNO
+                   || REGNO (XEXP (PATTERN (start), 1)) == R3_REGNO)
+               && GET_CODE (XEXP (PATTERN (start), 0)) == MEM
+               && GET_CODE (XEXP (XEXP (PATTERN (start), 0), 0)) == PLUS
+               && REGNO (XEXP (XEXP (XEXP (PATTERN (start), 0), 0), 0)) ==
+               A0_REGNO)
+        {
+          if (REGNO (XEXP (PATTERN (start1), 1)) == R0_REGNO)
+            {
+              output_asm_insn ("ste.w   r0,%Z2[a0]", operands);
+              output_asm_insn ("ste.w   r2,%z2[a0]", operands);
+            }
+          else
+            {
+              output_asm_insn ("ste.w   r1,%Z2[a0]", operands);
+              output_asm_insn ("ste.w   r3,%z2[a0]", operands);
+            }
+          delete_insn (insn);
+          delete_insn (start);
+          delete_insn (start1);
+          return "";
+        }
+      else if (INSN_CODE (start) == CODE_FOR_movsi_splittable
+               && GET_MODE (XEXP (PATTERN (start), 1)) == SImode
+               && GET_CODE (XEXP (PATTERN (start), 1)) == REG
+               && (REGNO (XEXP (PATTERN (start), 1)) == R0_REGNO
+                   || REGNO (XEXP (PATTERN (start), 1)) == R1_REGNO)
+               && GET_CODE (XEXP (PATTERN (start), 0)) == MEM
+               && GET_CODE (XEXP (XEXP (PATTERN (start), 0), 0)) == REG
+               && REGNO (XEXP (XEXP (PATTERN (start), 0), 0)) == A0_REGNO)
+        {
+          if (REGNO (XEXP (PATTERN (start), 1)) == R0_REGNO)
+            {
+              output_asm_insn ("ste.w   r2,%Z2[a0]", operands);
+              output_asm_insn ("ste.w   r0,%z2[a0]", operands);
+            }
+          else
+            {
+              output_asm_insn ("ste.w   r3,%Z2[a0]", operands);
+              output_asm_insn ("ste.w   r1,%z2[a0]", operands);
+            }
+          delete_insn (insn);
+          delete_insn (start);
+          return "";
+        }
+      else if ((INSN_CODE (start) == CODE_FOR_movhi_op)
+               && GET_CODE (XEXP (PATTERN (start), 0)) == MEM
+               && GET_CODE (XEXP (XEXP (PATTERN (start), 0), 0)) == REG
+               && REGNO (XEXP (XEXP (PATTERN (start), 0), 0)) == A0_REGNO
+               && GET_CODE (XEXP (PATTERN (start), 1)) == REG)
+        {
+          operands[1] = XEXP (PATTERN (start), 1);
+          output_asm_insn ("ste.w   %1,%z2[a0]", operands);
+          delete_insn (insn);
+          delete_insn (start);
+          return "";
+        }
+      else
+        {
+          output_asm_insn ("add.w  %2,%0", operands);
+          delete_insn (insn);
+          return "";
+        }
+    }
+  else
+    {
+      output_asm_insn ("add.w  %2,%0", operands);
+      delete_insn (insn);
+      return "";
+    }
+}
+
 static tree
 interrupt_handler (tree * node ATTRIBUTE_UNUSED,
 		   tree name ATTRIBUTE_UNUSED,
@@ -2821,6 +3371,8 @@ current_function_special_page_vector (rt
 #define TARGET_ATTRIBUTE_TABLE m32c_attribute_table
 static const struct attribute_spec m32c_attribute_table[] = {
   {"interrupt", 0, 0, false, false, false, interrupt_handler},
+  {"far", 0, 0, false, false, false, far_data_handler},
+  {"near", 0, 0, false, false, false, near_data_handler},
   {"function_vector", 1, 1, true,  false, false, function_vector_handler},
   {0, 0, 0, 0, 0, 0, 0}
 };
@@ -4206,6 +4758,11 @@ m32c_output_compare (rtx insn, rtx *oper
 #undef TARGET_ENCODE_SECTION_INFO
 #define TARGET_ENCODE_SECTION_INFO m32c_encode_section_info
 
+#if 1 
+#undef  TARGET_ASM_SELECT_SECTION
+#define TARGET_ASM_SELECT_SECTION  m32c_select_section
+#endif 
+
 /* The Global `targetm' Variable. */
 
 struct gcc_target targetm = TARGET_INITIALIZER;
--- /gcc/config/m32c/m32c-protos.h	2008-01-15 12:06:45.000000000 +0530
+++ /gcc/config/m32c/m32c-protos.h	2008-01-08 17:37:34.000000000 +0530
@@ -87,6 +87,7 @@ int  m32c_mode_dependent_address (rtx);
 int  m32c_modes_tieable_p (MM, MM);
 bool m32c_mov_ok (rtx *, MM);
 char * m32c_output_compare (rtx, rtx *);
+char * m32c_disp_pattern (rtx, rtx *);
 void m32c_pend_compare (rtx *);
 int  m32c_preferred_output_reload_class (rtx, int);
 int  m32c_preferred_reload_class (rtx, int);
@@ -111,6 +112,10 @@ void m32c_function_arg_advance (CUMULATI
 tree m32c_gimplify_va_arg_expr (tree, tree, tree *, tree *);
 void m32c_init_cumulative_args (CUMULATIVE_ARGS *, tree, rtx, tree, int);
 bool m32c_promote_function_return (tree);
+int  far_data_p (rtx);
+int  near_data_p (rtx);
+int  far_data_a1a0 (rtx);
+int  near_data_a1a0 (rtx);
 int  m32c_special_page_vector_p (tree);
 
 #endif
--- /gcc/config/m32c/mov.md	2008-01-15 11:37:37.000000000 +0530
+++ /gcc/config/m32c/mov.md	2008-01-15 17:41:04.000000000 +0530
@@ -30,6 +30,159 @@
 
 ;; Match push/pop before mov.b for passing char as arg,
 ;; e.g. stdlib/efgcvt.c.
+
+;; M16C-20bit Access
+(define_insn "movqildabs_op"
+  [(set (match_operand:QI 0 "mra_nopp_operand" "=Rqi*Rmm")
+        (match_operand:QI 1 "m32c_20babsqi_operand" "Sn"))]
+  "TARGET_A16 && m32c_mov_ok (operands, QImode)"
+  "*
+{
+  HOST_WIDE_INT a = 0, b = 0;
+  if (GET_CODE (XEXP (operands[1], 0)) == SYMBOL_REF)
+    {
+      a = far_data_p (XEXP (operands[1], 0));
+      b = near_data_p (XEXP (operands[1], 0));
+    }
+  else if (GET_CODE (XEXP (operands[1], 0)) == CONST)
+    {
+      a = far_data_p (XEXP (XEXP (XEXP (operands[1], 0), 0), 0));
+      b = near_data_p (XEXP (XEXP (XEXP (operands[1], 0), 0), 0));
+    }
+
+  if ((a == 1) && (b == 0))
+    return \"lde.b\\t%1,%0\";
+  else
+    return \"mov.b\\t%1,%0\";
+}"
+  [(set_attr "flags" "n")]
+)
+
+(define_insn "movqistabs_op"
+  [(set (match_operand:QI 0 "m32c_20babsqi_operand" "=Sn")
+        (match_operand:QI 1 "mrai_nopp_operand" "Rqi*Rmm"))]
+  "TARGET_M16C && m32c_mov_ok (operands, QImode)"
+  "*
+{
+  HOST_WIDE_INT a = 0, b = 0;
+  if (GET_CODE (XEXP (operands[0], 0)) == SYMBOL_REF)
+    {
+      a = far_data_p (XEXP (operands[0], 0));
+      b = near_data_p (XEXP (operands[0], 0));
+    }
+  else if (GET_CODE (XEXP (operands[0], 0)) == CONST)
+    {
+      a = far_data_p (XEXP (XEXP (XEXP (operands[0], 0), 0), 0));
+      b = near_data_p (XEXP (XEXP (XEXP (operands[0], 0), 0), 0));
+    }
+
+  if ((a == 1) && (b == 0))
+    return \"ste.b\\t%1,%0\";
+  else
+    return \"mov.b\\t%1,%0\";
+}"
+  [(set_attr "flags" "n")]
+)
+
+(define_insn "movqilddisp_op"
+  [(set (match_operand:QI 0 "mra_nopp_operand" "=Rqi*Rmm")
+        (match_operand:QI 1 "m32c_20bdisp_operand" "Sd"))]
+ "TARGET_A16 && m32c_mov_ok (operands, QImode)
+  && GET_CODE (XEXP (XEXP (operands[1], 0), 1)) == SYMBOL_REF"
+ "*
+{
+  HOST_WIDE_INT a = 0, b = 0;
+  if (GET_CODE (XEXP (XEXP (operands[1], 0), 1)) == SYMBOL_REF)
+    {
+      a = far_data_p (XEXP (XEXP (operands[1], 0),1));
+      b = near_data_p (XEXP (XEXP (operands[1], 0),1));
+    }
+  if ((a == 1) && (b == 0) && REGNO (XEXP (XEXP (operands[1], 0), 0)) == A0_REGNO)
+    return \"lde.b\\t%1,%0\";
+  else if (REGNO (XEXP (XEXP (operands[1], 0), 0)) == A0_REGNO)
+    return \"mov.b\\t%1,%0\";
+  else 
+    {
+      operands[1] = XEXP (XEXP (operands[1], 0), 0);
+      output_asm_insn (\"mov.b\\t%1,a0\",operands);
+      operands[1] = XEXP (XEXP (operands[1], 0), 1);
+      return \"mov.b\\t%z1[a0],%0\";
+    }
+}"
+  [(set_attr "flags" "n")]
+)
+
+(define_insn "movqistdisp_op"
+  [(set (match_operand:QI 0 "m32c_20bdisp_operand" "=Sd")
+      (match_operand:QI 1 "mra_nopp_operand" "Rqi*Rmm"))]
+  "TARGET_M16C && m32c_mov_ok (operands, QImode)
+   && GET_CODE (XEXP (XEXP (operands[0], 0), 1)) == SYMBOL_REF"
+  "*
+{
+  HOST_WIDE_INT a = 0, b = 0;
+  if (GET_CODE (XEXP (XEXP (operands[0], 0), 1)) == SYMBOL_REF)
+    {
+      a = far_data_p (XEXP (XEXP (operands[0], 0),1));
+      b = near_data_p (XEXP (XEXP (operands[0], 0),1));
+    }
+  if ((a == 1) && (b == 0) && REGNO (XEXP (XEXP (operands[0], 0), 0)) == A0_REGNO)
+    return \"ste.b\\t%1,%0\";
+  else if (REGNO (XEXP (XEXP (operands[0], 0), 0)) == A0_REGNO)
+    return \"mov.b\\t%1,%0\";
+  else
+    {
+      operands[0] = XEXP (XEXP (operands[0], 0), 0);
+      output_asm_insn (\"mov.b\\t%0,a0\",operands);
+      operands[0] = XEXP (XEXP (operands[0], 0), 1);
+      return \"mov.b\\t%1,%z0[a0]\";
+    }
+}"
+  [(set_attr "flags" "n")]
+)
+
+(define_insn "movqildA1A0_op"
+[(set (match_operand:QI 0 "mra_nopp_operand" "=Rqi*Rmm")
+      (match_operand:QI 1 "m32c_20bA1A0_operand" ""))]
+  "TARGET_A16 && m32c_mov_ok (operands, QImode)
+   && REGNO (XEXP (operands[1], 0)) == A0_REGNO"
+  "*
+{
+  HOST_WIDE_INT a = 0, b = 0;
+  if (GET_CODE (XEXP (operands[1], 0)) == REG)
+    {
+      a = far_data_a1a0 (operands[1]);
+      b = near_data_a1a0 (operands[1]);
+    }
+  if ((a == 1) && (b == 0))
+    return \"lde.b\\t%1,%0\";
+  else
+    return \"mov.b\\t%1,%0\";
+}"
+  [(set_attr "flags" "n")]
+)
+
+(define_insn "movqistA1A0_op"
+  [(set (match_operand:QI 0 "m32c_20bA1A0_operand" "")
+        (match_operand:QI 1 "mra_nopp_operand" "Rqi*Rmm"))]
+  "TARGET_M16C && m32c_mov_ok (operands, QImode)"
+  "*
+{
+  HOST_WIDE_INT a = 0, b = 0;
+  if (GET_CODE (XEXP (operands[0], 0)) == REG)
+    {
+      a = far_data_a1a0 (operands[0]);
+      b = near_data_a1a0 (operands[0]);
+    }
+  if ((a == 1) && (b == 0))
+    return \"ste.b\\t%1,%0\";
+  else
+    return \"mov.b\\t%1,%0\";
+}"
+  [(set_attr "flags" "n")]
+)
+
+; M16C-20bit Access 
+
 (define_insn "movqi_op"
   [(set (match_operand:QI 0 "m32c_nonimmediate_operand"
 			  "=Rqi*Rmm, <,          RqiSd*Rmm, SdSs,    Rqi*Rmm, Sd")
@@ -53,12 +206,168 @@
   "if (m32c_prepare_move (operands, QImode)) DONE;"
   )
 
+;; M16C-20bit Access
+(define_insn "movhildabs_op"
+  [(set (match_operand:HI 0 "mra_nopp_operand" "=Rhi*Rmm")
+        (match_operand:HI 1 "m32c_20babshi_operand" ""))]
+ "TARGET_A16 && m32c_mov_ok (operands, HImode)"
+ "*
+{
+ HOST_WIDE_INT a = 0, b = 0;
+  if (GET_CODE (XEXP (operands[1], 0)) == SYMBOL_REF)
+    {
+      a = far_data_p (XEXP (operands[1], 0));
+      b = near_data_p (XEXP (operands[1], 0));
+   }
+  else if (GET_CODE (XEXP (operands[1], 0)) == CONST)
+    {
+     a = far_data_p (XEXP (XEXP (XEXP (operands[1], 0), 0), 0));
+     b = near_data_p (XEXP (XEXP (XEXP (operands[1], 0), 0), 0));
+   }
+
+  if ((a == 1) && (b == 0))
+    return \"lde.w\\t%1,%0\";
+  else
+   return \"mov.w\\t%1,%0\";
+}"
+  [(set_attr "flags" "n")]
+)
+
+(define_insn "movhistabs_op"
+ [(set (match_operand:HI 0 "m32c_20babshi_operand" "")
+       (match_operand:HI 1 "mrai_nopp_operand" "iRhi*Rmm"))]
+  "TARGET_M16C && m32c_mov_ok (operands, HImode)"
+  "*
+{
+  HOST_WIDE_INT a = 0, b = 0;
+ if (GET_CODE (XEXP (operands[0], 0)) == SYMBOL_REF)
+    {
+     a = far_data_p (XEXP (operands[0], 0));
+     b = near_data_p (XEXP (operands[0], 0));
+    }
+ else if (GET_CODE (XEXP (operands[0], 0)) == CONST)
+    {
+      a = far_data_p (XEXP (XEXP (XEXP (operands[0], 0), 0), 0));
+      b = near_data_p (XEXP (XEXP (XEXP (operands[0], 0), 0), 0));
+    }
+  if ((a == 1) && (b == 0) && GET_CODE (operands[1]) == CONST_INT)
+    return \"mov.w\\t%1,mem14\;ste.w\\tmem14,%0\";
+  else if ((a == 1) && (b == 0))
+    return \"ste.w\\t%1,%0\";
+  else
+    return \"mov.w\\t%1,%0\";
+}"
+  [(set_attr "flags" "n")]
+)
+
+(define_insn "movhilddisp_op"
+[(set (match_operand:HI 0 "mra_nopp_operand" "=Rhi*Rmm")
+      (match_operand:HI 1 "m32c_20bdisphi_operand" ""))]
+  "TARGET_A16 && m32c_mov_ok (operands, HImode)
+  && REGNO (XEXP (XEXP (operands[1], 0), 0)) == A0_REGNO"
+  "*
+{
+  HOST_WIDE_INT a = 0, b = 0;
+  if (GET_CODE (XEXP (XEXP (operands[1], 0), 1)) == SYMBOL_REF)
+    {
+       a = far_data_p (XEXP (XEXP (operands[1], 0), 1));
+       b = near_data_p (XEXP (XEXP (operands[1], 0), 1));
+    }
+   else if (GET_CODE (XEXP (XEXP (operands[1], 0), 1)) == CONST)
+    {
+      a = far_data_p (XEXP (XEXP (XEXP (XEXP (operands[1], 0), 1), 0), 0));
+      b = near_data_p (XEXP (XEXP (XEXP (XEXP (operands[1], 0), 1), 0), 0));
+    }
+  if ((a == 1) && (b == 0))
+    return \"lde.w\\t%1,%0\";
+  else
+    return \"mov.w\\t%1,%0\";
+}"
+  [(set_attr "flags" "n")]
+)
+
+(define_insn "movhistdisp_op"
+ [(set (match_operand:HI 0 "m32c_20bdisphi_operand" "")
+       (match_operand:HI 1 "mra_nopp_operand" "Rhi*Rmm"))]
+ "TARGET_M16C && m32c_mov_ok (operands, HImode)
+  && (REGNO (XEXP (XEXP (operands[0], 0), 0)) == A0_REGNO
+      || REGNO (XEXP (XEXP (operands[0], 0), 0)) == A1_REGNO)"
+  "*
+{
+  HOST_WIDE_INT a = 0, b = 0;
+  if (GET_CODE (XEXP (XEXP (operands[0], 0), 1)) == SYMBOL_REF)
+    {
+       a = far_data_p (XEXP (XEXP (operands[0], 0), 1));
+       b = near_data_p (XEXP (XEXP (operands[0], 0), 1));
+    }
+   else if (GET_CODE (XEXP (XEXP (operands[0], 0), 1)) == CONST)
+    {
+       a = far_data_p (XEXP (XEXP (XEXP (XEXP (operands[0], 0), 1), 0), 0));
+       b = near_data_p (XEXP (XEXP (XEXP (XEXP (operands[0], 0), 1), 0), 0));
+    }
+  if ((a == 1) && (b == 0) && REGNO (XEXP (XEXP (operands[0], 0), 0)) == A0_REGNO)
+    return \"ste.w\\t%1,%0\";
+  else if ((a == 1) && (b == 0) && REGNO (XEXP (XEXP (operands[0], 0), 0)) == A1_REGNO)
+    {
+      output_asm_insn (\"mov.w\\ta1,a0\",operands);
+      operands[0] = XEXP (XEXP (operands[0], 0), 1);
+      return \"ste.w\\t%1,%z0[a0]\";
+    }
+  else
+    return \"mov.w\\t%1,%0\";
+}"
+  [(set_attr "flags" "n")]
+)
+
+(define_insn "movhildA1A0_op"
+ [(set (match_operand:HI 0 "mra_nopp_operand" "=Rhi*Rmm")
+       (match_operand:HI 1 "m32c_20bA1A0_operand" ""))]
+  "TARGET_A16 && m32c_mov_ok (operands, HImode)
+   && REGNO (XEXP (operands[1], 0)) == A0_REGNO"
+  "*
+{
+  HOST_WIDE_INT a = 0, b = 0;
+ if (GET_CODE (XEXP (operands[1], 0)) == REG)
+    {
+      a = far_data_a1a0 (operands[1]);
+      b = near_data_a1a0 (operands[1]);
+    }
+  if ((a == 1) && (b == 0))
+    return \"lde.w\\t%1,%0\";
+  else
+    return \"mov.w\\t%1,%0\";
+}"
+  [(set_attr "flags" "n")]
+)
+
+(define_insn "movhistA1A0_op"
+  [(set (match_operand:HI 0 "m32c_20bA1A0_operand" "")
+        (match_operand:HI 1 "mra_nopp_operand" "Rhi*Rmm"))]
+ "TARGET_M16C && m32c_mov_ok (operands, HImode)"
+  "*
+{
+  HOST_WIDE_INT a = 0, b = 0;
+ if (GET_CODE (XEXP (operands[0], 0)) == REG
+     && REGNO (XEXP (operands[0], 0)) == A0_REGNO)
+    {
+      a = far_data_a1a0 (operands[0]);
+      b = near_data_a1a0 (operands[0]);
+    }
+  if ((a == 1) && (b == 0))
+    return \"ste.w\\t%1,%0\";
+  else
+    return \"mov.w\\t%1,%0\";
+}"
+  [(set_attr "flags" "n")]
+)
+
+;; M16C-20bit Access
 
 (define_insn "movhi_op"
   [(set (match_operand:HI 0 "m32c_nonimmediate_operand"
-			  "=Rhi*Rmm,     Sd, SdSs,   *Rcr, RhiSd*Rmm, <, RhiSd*Rmm, <, *Rcr")
-	(match_operand:HI 1 "m32c_any_operand"
-			  "iRhi*RmmSdSs, i, Rhi*Rmm, RhiSd*Rmm, *Rcr, iRhiSd*Rmm, >, *Rcr, >"))]
+                          "=Rhi*Rmm,     Sd, SdSs,   *Rcr, RhiSd*Rmm, <, RhiSd*Rmm, <, *Rcr")
+        (match_operand:HI 1 "m32c_any_operand"
+                          "iRhi*RmmSdSs, i, Rhi*Rmm, RhiSd*Rmm, *Rcr, iRhiSd*Rmm, >, *Rcr, >"))]
   "m32c_mov_ok (operands, HImode)"
   "@
    mov.w\t%1,%0
--- /gcc/config/m32c/predicates.md	2008-01-15 11:37:38.000000000 +0530
+++ /gcc/config/m32c/predicates.md	2008-01-15 17:22:32.000000000 +0530
@@ -157,6 +157,17 @@
 	    (not (match_operand 1 "cr_operand" "")))
        (not (match_operand 2 "m32c_wide_subreg" ""))))
 
+; As above, but no push/pop operations
+(define_predicate "mrai_nopp_operand"
+  (match_operand 0 "mrai_operand" "")
+{
+  if (GET_CODE (op) == MEM
+      && (GET_CODE (XEXP (op, 0)) == PRE_DEC
+          || (GET_CODE (XEXP (op, 0)) == POST_INC)))
+    return 0;
+  return 1;
+})
+
 ; Likewise, plus true for subregs.
 (define_predicate "mrasi_operand"
   (and (match_operand 0 "general_operand" "")
@@ -285,3 +296,83 @@
 (define_predicate "m32c_1mask16_operand"
   (and (match_operand 0 "const_int_operand")
        (match_test "m32c_const_ok_for_constraint_p(INTVAL(op), 'I', \"Imw\")")))
+
+; TRUE for memory values that satisfy ABS in HImode for 20 bit memory
+(define_predicate "m32c_20babshi_operand"
+  (match_operand 0 "memory_operand" "")
+{
+  HOST_WIDE_INT a = 0, b = 0;
+  if (GET_CODE (XEXP (op, 0)) == SYMBOL_REF
+      && far_data_p (XEXP (op, 0)) == 0
+      && near_data_p (XEXP (op, 0)) == 0)
+    return 0;
+
+  if (GET_CODE (op) == MEM
+     && (GET_CODE (XEXP (op, 0)) == PRE_DEC
+          || (GET_CODE (XEXP (op, 0)) == POST_INC)
+          || (GET_CODE (XEXP (op, 0)) == PLUS)
+          || (GET_CODE (XEXP (op, 0)) == REG)))
+    return 0;
+  return 1;
+})
+
+; TRUE for memory values that satisfy ABS in QImode for 20 bit memory
+(define_predicate "m32c_20babsqi_operand"
+  (and (match_operand 0 "memory_operand" "")
+       (match_test "m32c_extra_constraint_p (op, 'S', \"Sn\")")))
+; M16C-20bit Access
+
+; TRUE for memory values that satisfy [A1A0] for 20 bit memory
+(define_predicate "m32c_20bA1A0_operand"
+  (match_operand 0 "memory_operand" "")
+{
+  if (GET_CODE (op) == MEM
+      && GET_CODE (XEXP (op, 0)) == REG
+      && far_data_a1a0 (op) == 1
+      && REGNO (XEXP (op, 0)) == A0_REGNO
+      && (GET_MODE_SIZE (GET_MODE (XEXP (op, 0))) == 3
+          || GET_MODE_SIZE (GET_MODE (XEXP (op, 0))) == 4))
+    return 1;
+  return 0;
+})
+
+; TRUE for memory values that satisfy disp:20[A0] in QImode for 20 bit
+; memory
+(define_predicate "m32c_20bdisp_operand"
+  (match_operand 0 "memory_operand" "")
+{
+  if (GET_CODE (XEXP (op, 0)) == PLUS
+      && GET_CODE (XEXP (XEXP (op, 0), 0)) == REG
+      && far_data_p (XEXP (XEXP (op, 0), 1)) == 1
+      && GET_CODE (XEXP (XEXP (op, 0), 1)) == SYMBOL_REF
+      && (INTVAL (XEXP (XEXP (op, 0), 1)) > 0))
+  return 1;
+    return 0;
+})
+
+; TRUE for memory values that satisfy disp:20[A0] in HImode for 20 bit
+; memory
+(define_predicate "m32c_20bdisphi_operand"
+  (match_operand 0 "memory_operand" "")
+{
+  if (GET_CODE (XEXP (op, 0)) == PLUS
+      && GET_CODE (XEXP (XEXP (op, 0), 0)) == REG
+      && (REGNO (XEXP (XEXP (op, 0), 0)) == A0_REGNO
+          || REGNO (XEXP (XEXP (op, 0), 0)) == A1_REGNO)
+      && ((GET_CODE (XEXP (XEXP (op, 0), 1)) == CONST
+      && far_data_p (XEXP (XEXP (XEXP (XEXP (op, 0), 1), 0), 0)) == 1)
+           || (GET_CODE (XEXP (XEXP (op, 0), 1)) == SYMBOL_REF
+               && far_data_p (XEXP (XEXP (op, 0), 1)) == 1)))
+  return 1;
+    return 0;
+})
+
+; TRUE for memory values which contains base address in SYMBOL-REF
+(define_predicate "sym_operand"
+  (match_operand 0 "immediate_operand" "")
+{
+  if (GET_CODE (op) == SYMBOL_REF
+      && far_data_p (op) == 1)
+   return 1;
+ return 0;
+})
--- /gcc/config/m32c/t-m32c	2008-01-15 11:37:39.000000000 +0530
+++ /gcc/config/m32c/t-m32c	2008-01-08 17:37:34.000000000 +0530
@@ -65,8 +65,8 @@ m32c-pragma.o: $(srcdir)/config/m32c/m32
 # We support four CPU series, but R8C and M16C share one multilib, and
 # M32C and M32CM share another.
 
-MULTILIB_OPTIONS = mcpu=m32cm
-MULTILIB_DIRNAMES = m32cm
-MULTILIB_MATCHES = mcpu?m32cm=mcpu?m32c mcpu?r8c=mcpu?m16c
+MULTILIB_OPTIONS = mcpu=m16c/mcpu=m32cm
+MULTILIB_DIRNAMES = m16c m32cm
+MULTILIB_MATCHES = mcpu?m32cm=mcpu?m32c
 
 EXTRA_MULTILIB_PARTS = crtbegin.o crtend.o
--- /gcc/doc/extend.texi	2008-01-15 11:37:40.000000000 +0530
+++ /gcc/doc/extend.texi	2007-12-24 17:40:44.000000000 +0530
@@ -1854,6 +1854,16 @@ At the end of a function, it will jump t
 instead of using @code{rts}.  The board-specific return routine simulates
 the @code{rtc}.
 
+On M16C target the @code{far} attribute causes the compiler to
+place the variables in different sections as:-
+1. non-initialized non-constant data varaibles in ".fbss" section.
+2. initialized non-constant data varaibles in ".fdata" section.
+On R8C target the @code{far} attribute causes the compiler to
+place the constant variables in ".frodata" section.
+
+The compiler will use the @code{lde} and @code{ste} instructions
+to access the data from 20 bit (far)memory address.
+
 @item fastcall
 @cindex functions that pop the argument stack on the 386
 On the Intel 386, the @code{fastcall} attribute causes the compiler to
@@ -2151,6 +2161,13 @@ use the normal calling convention based 
 This attribute can be used to cancel the effect of the @option{-mlong-calls}
 option.
 
+On M16C target the @code{near} attribute causes the compiler to
+place the constant variables in ".nrodata" section. By default
+".rodata" section will be placed in far memory for m16C target.
+
+The compiler will use the @code{mov} instructions to access the
+data from near memory.
+
 @item nesting
 @cindex Allow nesting in an interrupt handler on the Blackfin processor.
 Use this attribute together with @code{interrupt_handler},
