I have redone the implementation of the eeprom attribute in my prototype. It is now a cleaner solution, but requires larger changes in the core, but the changes in the core should not affect any backend/frontend, if it does not uses them (except a missing case in tree_copy_mem_area, which will cause an assertion to fail).
The patches are against the CVS of 20050412. The changes in the core are: 1) MEM_REF_FLAGS introduced (http://www.auto.tuwien.ac.at/~mkoegler/gcc/memref.patch) The flags are stored in u.fld[2].rt_int of MEM. A new target hook is introduced, which takes an expression, decl or type and calculates the target specific MEM_REF_FLAGS. In set_mem_attributes_minus_bitops (as well es set_mem_attr_from reg), MEM_REF_FLAGS is initialized from the provided expression. The most relevant diffs are: Index: rtl.def =================================================================== RCS file: /cvs/gcc/gcc/gcc/rtl.def,v retrieving revision 1.100 diff -u -r1.100 rtl.def --- rtl.def 22 Jan 2005 22:48:57 -0000 1.100 +++ rtl.def 27 Apr 2005 17:46:53 -0000 @@ -385,8 +385,9 @@ /* A memory location; operand is the address. The second operand is the alias set to which this MEM belongs. We use `0' instead of `w' for this - field so that the field need not be specified in machine descriptions. */ -DEF_RTL_EXPR(MEM, "mem", "e0", RTX_OBJ) + field so that the field need not be specified in machine descriptions. + the third the memory flags */ +DEF_RTL_EXPR(MEM, "mem", "e00", RTX_OBJ) /* Reference to an assembler label in the code for this function. The operand is a CODE_LABEL found in the insn chain. Index: rtl.h =================================================================== RCS file: /cvs/gcc/gcc/gcc/rtl.h,v retrieving revision 1.543 diff -u -r1.543 rtl.h --- rtl.h 25 Mar 2005 02:23:57 -0000 1.543 +++ rtl.h 27 Apr 2005 17:46:53 -0000 @@ -1080,6 +1080,9 @@ in the block and provide defaults if none specified. */ #define MEM_ATTRS(RTX) X0MEMATTR (RTX, 1) +/* A set of flags on a mem */ +#define MEM_REF_FLAGS(RTX) X0INT ((RTX), 2) + /* The register attribute block. We provide access macros for each value in the block and provide defaults if none specified. */ #define REG_ATTRS(RTX) X0REGATTR (RTX, 2) Index: target.h =================================================================== RCS file: /cvs/gcc/gcc/gcc/target.h,v retrieving revision 1.131 diff -u -r1.131 target.h --- target.h 12 Apr 2005 06:33:23 -0000 1.131 +++ target.h 27 Apr 2005 17:46:53 -0000 @@ -514,6 +514,9 @@ to be checked for va_list references. */ bool (*stdarg_optimize_hook) (struct stdarg_info *ai, tree lhs, tree rhs); + /* extracts MEM_REF_FLAGS out of a tree expression */ + int (*extract_mem_ref_flags) (tree t); + /* Functions relating to calls - argument passing, returns, etc. */ struct calls { bool (*promote_function_args) (tree fntype); Index: emit-rtl.c =================================================================== RCS file: /cvs/gcc/gcc/gcc/emit-rtl.c,v retrieving revision 1.436 diff -u -r1.436 emit-rtl.c --- emit-rtl.c 25 Mar 2005 02:23:57 -0000 1.436 +++ emit-rtl.c 27 Apr 2005 17:46:50 -0000 @@ -1449,6 +1453,8 @@ if (t == NULL_TREE) return; + MEM_REF_FLAGS(ref) = targetm.extract_mem_ref_flags (t); + type = TYPE_P (t) ? t : TREE_TYPE (t); if (type == error_mark_node) return; @@ -1685,6 +1691,10 @@ = get_mem_attrs (MEM_ALIAS_SET (mem), REG_EXPR (reg), GEN_INT (REG_OFFSET (reg)), MEM_SIZE (mem), MEM_ALIGN (mem), GET_MODE (mem)); + + if(REG_EXPR (reg)) + MEM_REF_FLAGS(mem) = targetm.extract_mem_ref_flags (REG_EXPR (reg)); + } /* Set the alias set of MEM to SET. */ 2) Handling of the eeprom attribute (http://www.auto.tuwien.ac.at/~mkoegler/gcc/addr.patch) As my old solution had too much problem, I tried a clean implementation, which provided something, like in DTR18037. First a new type for storing memory address spaces was introduced. At the moment, it is implemented as an integer. The value 0 is used as NO_MEM_AREA, which means, that no memory has been assiged. This value is useful for finding missing initialization of a memory address space variable. Value 1 is DEFAULT_MEM_AREA, which is the usually adress space, including stack and data segement. As the memory area is only used in the backend code, the EEPROM address space is not defined here. As I have not changed the parser, the address space is initialized using an attribute. The address space attribute has been adden to the following tree constructs: *TYPE_MEM_AREA: memory area of the pointer target, for other types unused *DECL_MEM_AREA: memory area, where a variable is located (used for var_decls) *EXPR_MEM_AREA: current memory area. Basically it is only needed for component_ref, indirect_ref or an array_ref. As eg. a compound_expr may appear in place of a of a decl, such expression inherit the MEM_AREA from their "return" expression For copying the MEM_AREA from a DECL or EXPR to a EXPR, tree_copy_mem_area was written. It takes care of all possiblities, I have noticed. As each creation of a INDIRECT_REF, ARRAY_REF or COMPONENT_REF in an optimizer need also to copy the MEM_AREA, special build function (build*_REF) were written, which set MEM_AREA. So most changes in the patch consists only of a change of the function call. To build1_INDIRECT_REF, as first argument, not the element type, but the complete pointer type or the evaluation expression is passed. In few cases, the memory area of the pointer is not available. For these, another solution to get the memory area, is needed. So far, I have tested it with a part of C frontend. It need more testing (as well as correction of missing MEM_AREAs in expressions). Other frontends will propably also need some modifications, if they should provide the correct value for MEM_AREA. Important part of the patch: Index: tree.h =================================================================== RCS file: /cvs/gcc/gcc/gcc/tree.h,v retrieving revision 1.714 diff -u -r1.714 tree.h --- tree.h 9 Apr 2005 17:19:03 -0000 1.714 +++ tree.h 27 Apr 2005 17:46:55 -0000 @@ -27,6 +27,10 @@ #include "statistics.h" #include "vec.h" +#define NO_MEM_AREA 0 +#define DEFAULT_MEM_AREA 1 +typedef int memory_area_t; + /* Codes of tree nodes */ #define DEFTREECODE(SYM, STRING, TYPE, NARGS) SYM, @@ -1173,6 +1177,8 @@ /* In a LOOP_EXPR node. */ #define LOOP_EXPR_BODY(NODE) TREE_OPERAND_CHECK_CODE (NODE, LOOP_EXPR, 0) +#define EXPR_MEM_AREA(NODE) (EXPR_CHECK (NODE)->exp.area) + #ifdef USE_MAPPED_LOCATION /* The source location of this expression. Non-tree_exp nodes such as decls and constants can be shared among multiple locations, so @@ -1292,6 +1298,7 @@ struct tree_common common; source_locus locus; int complexity; + memory_area_t area; tree block; tree GTY ((special ("tree_exp"), desc ("TREE_CODE ((tree) &%0)"))) @@ -1543,6 +1550,7 @@ #define TYPE_MAIN_VARIANT(NODE) (TYPE_CHECK (NODE)->type.main_variant) #define TYPE_CONTEXT(NODE) (TYPE_CHECK (NODE)->type.context) #define TYPE_LANG_SPECIFIC(NODE) (TYPE_CHECK (NODE)->type.lang_specific) +#define TYPE_MEM_AREA(NODE) (TYPE_CHECK (NODE)->type.area) /* For a VECTOR_TYPE node, this describes a different type which is emitted in the debugging output. We use this to describe a vector as a @@ -1740,6 +1748,7 @@ HOST_WIDE_INT alias_set; /* Points to a structure whose details depend on the language in use. */ struct lang_type *lang_specific; + memory_area_t area; }; ^L /* Define accessor macros for information about type inheritance @@ -1921,6 +1930,8 @@ NULL_TREE or a TRANSLATION_UNIT_DECL if the given decl has "file scope". */ #define DECL_CONTEXT(NODE) (DECL_CHECK (NODE)->decl.context) Index: tree.c =================================================================== RCS file: /cvs/gcc/gcc/gcc/tree.c,v retrieving revision 1.472 diff -u -r1.472 tree.c --- tree.c 30 Mar 2005 21:34:29 -0000 1.472 +++ tree.c 27 Apr 2005 17:46:55 -0000 @@ -6664,4 +6676,47 @@ return result; } +void +tree_copy_mem_area (tree to, tree from) +{ + if(!from) + EXPR_MEM_AREA(to)=NO_MEM_AREA; + else if(TREE_CODE(from)==INTEGER_CST) + EXPR_MEM_AREA(to)=DEFAULT_MEM_AREA; + else if(TREE_CODE(from)==STRING_CST) + EXPR_MEM_AREA(to)=DEFAULT_MEM_AREA; + else if(DECL_P(from)) + EXPR_MEM_AREA(to)=DECL_MEM_AREA(from); + else + EXPR_MEM_AREA(to)=EXPR_MEM_AREA(from); +} + +tree +build1_INDIRECT_REF (tree type, tree pointer) +{ + tree t = build1 (INDIRECT_REF, TREE_TYPE (type), pointer); + if(TREE_CODE(type)==ARRAY_REF||TREE_CODE(type)==ARRAY_RANGE_REF||TREE_CODE(type)==INDIRECT_REF||TREE_CODE(type)==COMPONENT_REF) + EXPR_MEM_AREA(t) = EXPR_MEM_AREA(type); + else + EXPR_MEM_AREA(t) = TYPE_MEM_AREA(type); + return t; +} + +tree +build3_COMPONENT_REF (tree a, tree b, tree c, tree d) +{ + tree t; + t = build3 (COMPONENT_REF, a, b, c, d); + tree_copy_mem_area (t, b); + return t; +} +tree build4_ARRAY_REF (tree a, tree b, tree c, tree d, tree e) +{ + tree t; + t = build4 (ARRAY_REF, a, b, c, d, e); + tree_copy_mem_area (t, b); + return t; +} + + Index: c-typeck.c =================================================================== RCS file: /cvs/gcc/gcc/gcc/c-typeck.c,v retrieving revision 1.431 diff -u -r1.431 c-typeck.c --- c-typeck.c 9 Apr 2005 03:18:07 -0000 1.431 +++ c-typeck.c 27 Apr 2005 17:46:50 -0000 @@ -1595,6 +1597,8 @@ if (TREE_THIS_VOLATILE (datum) || TREE_THIS_VOLATILE (subdatum)) TREE_THIS_VOLATILE (ref) = 1; + tree_copy_mem_area(ref,datum); + if (TREE_DEPRECATED (subdatum)) warn_deprecated_use (subdatum); @@ -1658,6 +1662,7 @@ TREE_SIDE_EFFECTS (ref) = TYPE_VOLATILE (t) || TREE_SIDE_EFFECTS (pointer); TREE_THIS_VOLATILE (ref) = TYPE_VOLATILE (t); + EXPR_MEM_AREA (ref) = TYPE_MEM_AREA(type); return ref; } } @@ -1784,6 +1789,9 @@ in an inline function. Hope it doesn't break something else. */ | TREE_THIS_VOLATILE (array)); + + tree_copy_mem_area(rval,array); + return require_complete_type (fold (rval)); } else @@ -2070,6 +2078,7 @@ result = build3 (CALL_EXPR, TREE_TYPE (fntype), function, coerced_params, NULL_TREE); + EXPR_MEM_AREA (result) = DEFAULT_MEM_AREA; TREE_SIDE_EFFECTS (result) = 1; if (require_constant_value) 3) Use of this function in the port: As I have not change the frontend, I created two attributes: 1) A decl attribute eeprom 2) A type attribute eepromt for marking pointers: Usage example: struct x y __attribute__ ((eeprom)); typedef struct x* ax __attribute__ ((eepromt)); important code: /* Handle a "eeprom" attribute; arguments as in struct attribute_spec.handler. */ static tree m68hc05_handle_eeprom_attribute (tree * node, tree name, tree args ATTRIBUTE_UNUSED, int flags ATTRIBUTE_UNUSED, bool * no_add_attrs) { if(POINTER_TYPE_P(*node)) { *node = copy_node (*node); TYPE_MEM_AREA(*node)=2; } else if(DECL_P(*node)&&TREE_CODE(*node)!=TYPE_DECL) { *node = copy_node (*node); DECL_MEM_AREA(*node)=2; } else warning ("%qs attribute does not apply", IDENTIFIER_POINTER (name)); return NULL_TREE; } const struct attribute_spec m68hc05_attribute_table[] = { /* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler } */ {"eepromt", 0, 0, false, true, false, m68hc05_handle_eeprom_attribute}, {"eeprom", 0, 0, true, false, false, m68hc05_handle_eeprom_attribute}, }; /* HOOK for TARGET_EXTRACT_MEM_REF_FLAGS, does the following: *check the memory area for eeprom, and return 1, if it is set. *stop at unset memory areas */ static int m68hc05_extract_mem_ref_flags (tree expr) { tree t; int ref=0; if(TREE_CODE(expr)==IMAGPART_EXPR||TREE_CODE(expr)==REALPART_EXPR) expr=TREE_OPERAND (expr, 0); if(TYPE_P(expr)||TREE_CODE(expr)==STRING_CST||TREE_CODE(expr)==COMPLEX_CST) { ref=DEFAULT_MEM_AREA; } else if(DECL_P(expr)) { ref=DECL_MEM_AREA(expr); } else if(EXPR_P(expr)) { ref=EXPR_MEM_AREA(expr); } gcc_assert(ref); if(ref==2) return 1; else return 0; } // my predicate to check for eeprom address space int eeprom_operand (op, mode) rtx op; enum machine_mode mode; { tree t = 0; int deref = 0; if (mode == VOIDmode) mode = GET_MODE (op); if (GET_MODE (op) != mode) return 0; if (!MEM_P (op)) return 0; if (MEM_P (op) && (MEM_REF_FLAGS (op) & 1)) return 1; else return 0; } The rest is the same, as I described it before. I hope, that it is understandable, what I am doing. Adding a syntax for in the C frontend for the address space modifiers is not an priority for me, as the two attribute solution should work. An important part, that is still missing, is the type compatibility checking between pointers to different memory areas. At the moment, even no warning is issued. I itend to introduce a new target hook for this, which checks, if two memory areas are compatible. Comments? mfg Martin Kögler PS: Please CC me on replies.