diff -upNr orig-gcc/config/cr16/cr16.c gcc/config/cr16/cr16.c
--- orig-gcc/config/cr16/cr16.c	2012-05-14 17:36:34.000000000 +0530
+++ gcc/config/cr16/cr16.c	2012-05-10 18:47:27.000000000 +0530
@@ -128,6 +128,12 @@ static enum data_model_type data_model =
 static void cr16_print_operand (FILE *, rtx, int);
 static void cr16_print_operand_address (FILE *, rtx);
 
+static tree cr16_handle_data_memory_attribute (tree *, tree, tree, int, bool *);
+int cr16_data16_mem_p (rtx);
+int cr16_data20_mem_p (rtx);
+int cr16_data24_mem_p (rtx);
+int cr16_data32_mem_p (rtx);
+
 /* Stack layout and calling conventions.  */
 #undef  TARGET_STRUCT_VALUE_RTX
 #define TARGET_STRUCT_VALUE_RTX		cr16_struct_value_rtx
@@ -204,9 +210,103 @@ static const struct attribute_spec cr16_
   /* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler,
        affects_type_identity }.  */
   {"interrupt", 0, 0, false, true, true, NULL, false},
+  {"data16", 0, 0, true, false, false, cr16_handle_data_memory_attribute},
+  {"data20", 0, 0, true, false, false, cr16_handle_data_memory_attribute},
+  {"data24", 0, 0, true, false, false, cr16_handle_data_memory_attribute},
+  {"data32", 0, 0, true, false, false, cr16_handle_data_memory_attribute},
   {NULL, 0, 0, false, false, false, NULL, false}
 };
 
+static tree
+cr16_handle_data_memory_attribute (tree *node, tree name,
+                                   tree args ATTRIBUTE_UNUSED,
+                                   int flags ATTRIBUTE_UNUSED,
+                                   bool *no_add_attrs)
+{
+  tree decl = *node;
+
+  if (TREE_STATIC (decl) || DECL_EXTERNAL (decl))
+    {
+      const char *prefix;
+      size_t  plen;
+
+      /* if variable has already assigned one section, then keep it. */
+      if (DECL_SECTION_NAME (decl) != NULL_TREE)
+        return NULL_TREE;
+
+      if (is_attribute_p ("data16", name))
+        {
+          if (TREE_READONLY (decl))
+            prefix = ".rodata16";
+          else if (DECL_INITIAL (decl))
+            prefix = ".data16";
+          else
+            prefix = ".bss16";
+        }
+
+       else if (is_attribute_p ("data20", name))
+         {
+           if (TREE_READONLY (decl))
+             prefix = ".rodata20";
+           else if (DECL_INITIAL (decl))
+             prefix = ".data20";
+           else
+             prefix = ".bss20";
+         } 
+
+       else if (is_attribute_p ("data24", name))
+         {
+           if (TREE_READONLY (decl))
+             prefix = ".rodata24";
+           else if (DECL_INITIAL (decl))
+             prefix = ".data24";
+         else
+           prefix = ".bss24";
+       }
+
+       else if (is_attribute_p ("data32", name))
+         {
+           if (TREE_READONLY (decl))
+           prefix = ".rodata32";
+         else if (DECL_INITIAL (decl))
+           prefix = ".data32";
+         else
+           prefix = ".bss32";
+       }
+
+     plen = strlen (prefix);
+
+     if (flag_data_sections)
+       {
+          const char *name;
+          char *string;
+          size_t nlen;
+
+          name = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl));
+          name = (* targetm.strip_name_encoding) (name);
+          nlen = strlen (name);
+
+          string = alloca (nlen + plen + 2);
+          memcpy (string, prefix, plen);
+          string[plen] = '.';
+          memcpy (string + plen + 1, name, nlen + 1);
+
+          DECL_SECTION_NAME (decl) = build_string (nlen + plen + 1, string);
+       }
+     else
+       {
+           DECL_SECTION_NAME (decl) = build_string (plen, prefix);
+       }
+    }
+  else
+    {
+      warning (OPT_Wattributes, "%qE attribute ignored",
+               name);
+      *no_add_attrs = true;
+    }
+  return NULL_TREE;
+}
+
 /* TARGET_ASM_UNALIGNED_xx_OP generates .?byte directive
    .?byte directive along with @c is not understood by assembler.
    Therefore, make all TARGET_ASM_UNALIGNED_xx_OP same
@@ -323,6 +423,94 @@ cr16_interrupt_function_p (void)
   return (lookup_attribute ("interrupt", attributes) != NULL_TREE);
 }
 
+/* Returns TRUE if given variable has "data16" attribute assigned. */
+int
+cr16_data16_mem_p (rtx x)
+{
+  tree t, a; 
+
+  if (GET_CODE (x) != SYMBOL_REF)
+    return 0;
+
+  t = SYMBOL_REF_DECL (x);
+
+  if ((t == NULL) || (TREE_CODE (t) != VAR_DECL))
+    return 0;
+
+  a=lookup_attribute ("data16", DECL_ATTRIBUTES (t));
+
+  if (a != NULL_TREE)
+    return 1;
+  else 
+    return 0;
+}
+
+/* Returns TRUE if given variable has "data20" attribute assigned. */
+int
+cr16_data20_mem_p (rtx x)
+{
+  tree t, a;
+  
+  if (GET_CODE (x) != SYMBOL_REF)
+    return 0;
+
+  t = SYMBOL_REF_DECL (x);
+
+  if ((t == NULL) || (TREE_CODE (t) != VAR_DECL))
+    return 0;
+
+  a=lookup_attribute ("data20", DECL_ATTRIBUTES (t));
+
+  if (a != NULL_TREE)
+    return 1;
+  else
+    return 0;
+}
+
+/* Returns TRUE if given variable has "data24" attribute assigned. */
+int
+cr16_data24_mem_p (rtx x)
+{
+  tree t, a;
+  
+  if (GET_CODE (x) != SYMBOL_REF)
+    return 0;
+
+  t = SYMBOL_REF_DECL (x);
+
+  if ((t == NULL) || (TREE_CODE (t) != VAR_DECL))
+    return 0;
+
+  a=lookup_attribute ("data24", DECL_ATTRIBUTES (t));
+
+  if (a != NULL_TREE)
+    return 1;
+  else
+    return 0;
+}
+
+/* Returns TRUE if given variable has "data32" attribute assigned. */
+int
+cr16_data32_mem_p (rtx x)
+{
+  tree t, a;
+ 
+  if (GET_CODE (x) != SYMBOL_REF)
+    return 0;
+
+  t = SYMBOL_REF_DECL (x);
+
+  if ((t == NULL) || (TREE_CODE (t) != VAR_DECL))
+    return 0;
+
+  a=lookup_attribute ("data32", DECL_ATTRIBUTES (t));
+
+  if (a != NULL_TREE)
+    return 1;
+  else
+    return 0;
+}
+
 /* Compute values for the array current_frame_info.save_regs and the variable 
    current_frame_info.reg_size. The index of current_frame_info.save_regs 
    is numbers of register, each will get 1 if we need to save it in the 
@@ -720,12 +908,21 @@ cr16_decompose_const (rtx x, int *code, 
       /* 2 indicates func sym.  */
       if (*code == 0)
 	{
-	  if (CR16_TARGET_DATA_NEAR)
-	    *data = DM_DEFAULT;
-	  else if (CR16_TARGET_DATA_MEDIUM)
-	    *data = DM_FAR;
-	  else if (CR16_TARGET_DATA_FAR)
-	    {
+          if ((CR16_TARGET_DATA_NEAR
+                && (cr16_data20_mem_p (x) == 0)
+                && (cr16_data24_mem_p (x) == 0)
+                && (cr16_data32_mem_p (x) == 0))
+              || (cr16_data16_mem_p (x) == 1))
+            *data = DM_DEFAULT;
+          else if (((CR16_TARGET_DATA_MEDIUM)
+                    && (cr16_data16_mem_p (x) == 0)
+                    && (cr16_data32_mem_p (x) == 0))
+                   || ((cr16_data20_mem_p (x) == 1)
+                        || (cr16_data24_mem_p (x) == 1)))
+            *data = DM_FAR;
+          else if (CR16_TARGET_DATA_FAR
+                   || (cr16_data32_mem_p (x) == 1))
+            {
 	      if (treat_as_const)
 		/* This will be used only for printing 
 		   the qualifier. This call is (may be)
@@ -909,12 +1106,21 @@ cr16_decompose_address (rtx addr, struct
       /* If not function ref then check if valid data ref.  */
       if (code == 0)
 	{
-	  if (CR16_TARGET_DATA_NEAR)
-	    data = DM_DEFAULT;
-	  else if (CR16_TARGET_DATA_MEDIUM)
-	    data = DM_FAR;
-	  else if (CR16_TARGET_DATA_FAR)
-	    {
+          if ((CR16_TARGET_DATA_NEAR
+                && (cr16_data20_mem_p (addr) == 0)
+                && (cr16_data24_mem_p (addr) == 0)
+                && (cr16_data32_mem_p (addr) == 0))
+              || (cr16_data16_mem_p (addr) == 1))
+            data = DM_DEFAULT;
+          else if (((CR16_TARGET_DATA_MEDIUM)
+                    && (cr16_data16_mem_p (addr) == 0)
+                    && (cr16_data32_mem_p (addr) == 0))
+                   || ((cr16_data20_mem_p (addr) == 1)
+                        || (cr16_data24_mem_p (addr) == 1)))
+            data = DM_FAR;
+          else if (CR16_TARGET_DATA_FAR
+                   || (cr16_data32_mem_p (addr) == 1))
+            {
 	      if (treat_as_const)
 		/* This will be used only for printing the 
 		   qualifier. This call is (may be) made
diff -upNr orig-gcc/doc/extend.texi gcc/doc/extend.texi
--- orig-gcc/doc/extend.texi	2012-05-14 17:36:53.000000000 +0530
+++ gcc/doc/extend.texi	2012-05-14 17:31:04.000000000 +0530
@@ -4826,6 +4826,44 @@ Variables with @code{l2} attribute will 
 named @code{.l2.data}.
 @end table
 
+
+@subsection CR16 Variable Attributes
+
+Four attributes are currently defined for the CR16.
+
+@table @code
+@item data16
+@itemx data20
+@itemx data24
+@itemx data32
+@cindex @code{data16} variable attribute
+@cindex @code{data20} variable attribute
+@cindex @code{data24} variable attribute
+@cindex @code{data32} variable attribute
+Memory allocation of the global data variables can be controlled using
+these attributes. @code{data16}, @code{data20}, @code{data24} and @code{data32}
+attributes specify the maximum allocatable data memory range as 16bit, 20bit,
+24bit and 32bit respectively.
+
+Variables declared with these attributes are allocated to the special sections,
+e.g. uninitialized global variables declared with say @code{data16} attributes are
+allocated to the section @code{'.bss16'}. Other special sections that are used to
+allocate attributed variables are @code{'.bss20'}, @code{'.bss24'}, @code{'.bss32'},
+@code{'.data16'}, @code{'.data20'}, @code{'.data24'}, @code{'.data32'}, @code{'.rodata16'},
+@code{'.rodata20'}, @code{'.rodata24'} and @code{'.rodata32'}.
+
+The order of declaration is important while using these attributes along with
+the 'section' atttribute. e.g.
+@smallexample
+int var4 __attribute__ ((section (".mysec"), data32));
+@end smallexample
+Here, 'var4' gets allocated to the section @code{'.mysec'} and still treated as @code{data32}
+variable while generating load/store instructions. Reversal of the attribute order
+results in compilation error.
+
+@end table
+
+
 @subsection M32R/D Variable Attributes
 
 One attribute is currently defined for the M32R/D@.
