diff options
author | steven <steven@138bc75d-0d04-0410-961f-82ee72b054a4> | 2005-10-24 19:28:18 +0000 |
---|---|---|
committer | steven <steven@138bc75d-0d04-0410-961f-82ee72b054a4> | 2005-10-24 19:28:18 +0000 |
commit | b549d2a563c4d3ac93efc5f11577b023a6d6f270 (patch) | |
tree | 3a890f87b8932e19f69eb45aa1082ec2a61e9711 /gcc/fortran | |
parent | 9aad078e179c1a01621c7e907cb7d2674bbc2017 (diff) | |
download | gcc-b549d2a563c4d3ac93efc5f11577b023a6d6f270.tar.gz |
Commit for Asher Langton
PR fortran/17031
PR fortran/22282
fortran/
* check.c (gfc_check_loc) : New function
* decl.c (variable_decl): New variables cp_as and sym. Added a
check for variables that have already been declared as Cray
Pointers, so we can get the necessary attributes without adding
a new symbol.
(attr_decl1): Added code to catch pointee symbols and "fix"
their array specs.
(cray_pointer_decl): New method.
(gfc_match_pointer): Added Cray pointer parsing code.
(gfc_mod_pointee_as): New method.
* expr.c (gfc_check_assign): added a check to catch vector-type
assignments to pointees with an unspecified final dimension.
* gfortran.h: (GFC_ISYM_LOC): New.
(symbol_attribute): Added cray_pointer and cray_pointee bits.
(gfc_array_spec): Added cray_pointee and cp_was_assumed bools.
(gfc_symbol): Added gfc_symbol *cp_pointer.
(gfc_option): Added flag_cray_pointer.
(gfc_add_cray_pointee): Declare.
(gfc_add_cray_pointer ): Declare.
(gfc_mod_pointee_as): Declare.
* intrinsic.c (add_functions): Add code for loc() intrinsic.
* intrinsic.h (gfc_check_loc): Declare.
(gfc_resolve_loc): Declare.
* iresolve.c (gfc_resolve_loc): New.
* lang.opt: Added fcray-pointer flag.
* options.c (gfc_init_options): Intialized
gfc_match_option.flag_cray_pointer.
(gfc_handle_option): Deal with -fcray-pointer.
* parse.c:(resolve_equivalence): Added code prohibiting Cray
pointees in equivalence statements.
* resolve.c (resolve_array_ref): Added code to prevent bounds
checking for Cray Pointee arrays.
(resolve_equivalence): Prohibited pointees in equivalence
statements.
* symbol.c (check_conflict): Added Cray pointer/pointee
attribute checking.
(gfc_add_cray_pointer): New
(gfc_add_cray_pointee): New
(gfc_copy_attr): New code for Cray pointers and pointees
* trans-array.c (gfc_trans_auto_array_allocation): Added code to
prevent space from being allocated for pointees.
(gfc_conv_array_parameter): Added code to catch pointees and
correctly set their base address.
* trans-decl.c (gfc_finish_var_decl): Added code to prevent
pointee declarations from making it to the back end.
(gfc_create_module_variable): Same.
* trans-expr.c (gfc_conv_variable): added code to detect and
translate pointees.
(gfc_conv_cray_pointee): New.
* trans-intrinsic.c (gfc_conv_intrinsic_loc): New.
(gfc_conv_intrinsic_function): added entry point for loc
translation.
* trans.h (gfc_conv_cray_pointee): Declare.
* gfortran.texi: Added section on Cray pointers, removed Cray
pointers from list of proposed extensions
* intrinsic.texi: Added documentation for loc intrinsic.
* invoke.texi: Documented -fcray-pointer flag
testsuite/
PR fortran/17031
PR fortran/22282
* gfortran.dg/cray_pointers_1.f90: New test.
* gfortran.dg/cray_pointers_2.f90: New test.
* gfortran.dg/cray_pointers_3.f90: New test.
* gfortran.dg/loc_1.f90: New test.
* gfortran.dg/loc_2.f90: New test.
git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@105859 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'gcc/fortran')
-rw-r--r-- | gcc/fortran/ChangeLog | 63 | ||||
-rw-r--r-- | gcc/fortran/check.c | 6 | ||||
-rw-r--r-- | gcc/fortran/decl.c | 258 | ||||
-rw-r--r-- | gcc/fortran/expr.c | 10 | ||||
-rw-r--r-- | gcc/fortran/gfortran.h | 18 | ||||
-rw-r--r-- | gcc/fortran/gfortran.texi | 141 | ||||
-rw-r--r-- | gcc/fortran/intrinsic.c | 7 | ||||
-rw-r--r-- | gcc/fortran/intrinsic.h | 2 | ||||
-rw-r--r-- | gcc/fortran/intrinsic.texi | 37 | ||||
-rw-r--r-- | gcc/fortran/invoke.texi | 8 | ||||
-rw-r--r-- | gcc/fortran/iresolve.c | 9 | ||||
-rw-r--r-- | gcc/fortran/lang.opt | 4 | ||||
-rw-r--r-- | gcc/fortran/options.c | 5 | ||||
-rw-r--r-- | gcc/fortran/resolve.c | 10 | ||||
-rw-r--r-- | gcc/fortran/symbol.c | 64 | ||||
-rw-r--r-- | gcc/fortran/trans-array.c | 18 | ||||
-rw-r--r-- | gcc/fortran/trans-decl.c | 41 | ||||
-rw-r--r-- | gcc/fortran/trans-expr.c | 6 | ||||
-rw-r--r-- | gcc/fortran/trans-intrinsic.c | 34 | ||||
-rw-r--r-- | gcc/fortran/trans.h | 3 |
20 files changed, 729 insertions, 15 deletions
diff --git a/gcc/fortran/ChangeLog b/gcc/fortran/ChangeLog index a019a1b2512..87c993e1c17 100644 --- a/gcc/fortran/ChangeLog +++ b/gcc/fortran/ChangeLog @@ -1,5 +1,68 @@ 2005-10-24 Asher Langton <langton2@llnl.gov> + PR fortran/17031 + PR fortran/22282 + * check.c (gfc_check_loc) : New function + * decl.c (variable_decl): New variables cp_as and sym. Added a + check for variables that have already been declared as Cray + Pointers, so we can get the necessary attributes without adding + a new symbol. + (attr_decl1): Added code to catch pointee symbols and "fix" + their array specs. + (cray_pointer_decl): New method. + (gfc_match_pointer): Added Cray pointer parsing code. + (gfc_mod_pointee_as): New method. + * expr.c (gfc_check_assign): added a check to catch vector-type + assignments to pointees with an unspecified final dimension. + * gfortran.h: (GFC_ISYM_LOC): New. + (symbol_attribute): Added cray_pointer and cray_pointee bits. + (gfc_array_spec): Added cray_pointee and cp_was_assumed bools. + (gfc_symbol): Added gfc_symbol *cp_pointer. + (gfc_option): Added flag_cray_pointer. + (gfc_add_cray_pointee): Declare. + (gfc_add_cray_pointer ): Declare. + (gfc_mod_pointee_as): Declare. + * intrinsic.c (add_functions): Add code for loc() intrinsic. + * intrinsic.h (gfc_check_loc): Declare. + (gfc_resolve_loc): Declare. + * iresolve.c (gfc_resolve_loc): New. + * lang.opt: Added fcray-pointer flag. + * options.c (gfc_init_options): Intialized + gfc_match_option.flag_cray_pointer. + (gfc_handle_option): Deal with -fcray-pointer. + * parse.c:(resolve_equivalence): Added code prohibiting Cray + pointees in equivalence statements. + * resolve.c (resolve_array_ref): Added code to prevent bounds + checking for Cray Pointee arrays. + (resolve_equivalence): Prohibited pointees in equivalence + statements. + * symbol.c (check_conflict): Added Cray pointer/pointee + attribute checking. + (gfc_add_cray_pointer): New + (gfc_add_cray_pointee): New + (gfc_copy_attr): New code for Cray pointers and pointees + * trans-array.c (gfc_trans_auto_array_allocation): Added code to + prevent space from being allocated for pointees. + (gfc_conv_array_parameter): Added code to catch pointees and + correctly set their base address. + * trans-decl.c (gfc_finish_var_decl): Added code to prevent + pointee declarations from making it to the back end. + (gfc_create_module_variable): Same. + * trans-expr.c (gfc_conv_variable): added code to detect and + translate pointees. + (gfc_conv_cray_pointee): New. + * trans-intrinsic.c (gfc_conv_intrinsic_loc): New. + (gfc_conv_intrinsic_function): added entry point for loc + translation. + * trans.h (gfc_conv_cray_pointee): Declare. + + * gfortran.texi: Added section on Cray pointers, removed Cray + pointers from list of proposed extensions + * intrinsic.texi: Added documentation for loc intrinsic. + * invoke.texi: Documented -fcray-pointer flag + +2005-10-24 Asher Langton <langton2@llnl.gov> + * decl.c (gfc_match_save): Changed duplicate SAVE errors to warnings in the absence of strict standard conformance * symbol.c (gfc_add_save): Same. diff --git a/gcc/fortran/check.c b/gcc/fortran/check.c index 49a7505be6f..25601f7001d 100644 --- a/gcc/fortran/check.c +++ b/gcc/fortran/check.c @@ -1211,6 +1211,12 @@ gfc_check_link_sub (gfc_expr * path1, gfc_expr * path2, gfc_expr * status) return SUCCESS; } +try +gfc_check_loc (gfc_expr *expr) +{ + return variable_check (expr, 0); +} + try gfc_check_symlnk (gfc_expr * path1, gfc_expr * path2) diff --git a/gcc/fortran/decl.c b/gcc/fortran/decl.c index 2ecd143190b..8102fa6b38d 100644 --- a/gcc/fortran/decl.c +++ b/gcc/fortran/decl.c @@ -912,13 +912,16 @@ variable_decl (int elem) char name[GFC_MAX_SYMBOL_LEN + 1]; gfc_expr *initializer, *char_len; gfc_array_spec *as; + gfc_array_spec *cp_as; /* Extra copy for Cray Pointees. */ gfc_charlen *cl; locus var_locus; match m; try t; + gfc_symbol *sym; initializer = NULL; as = NULL; + cp_as = NULL; /* When we get here, we've just matched a list of attributes and maybe a type and a double colon. The next thing we expect to see @@ -931,7 +934,9 @@ variable_decl (int elem) /* Now we could see the optional array spec. or character length. */ m = gfc_match_array_spec (&as); - if (m == MATCH_ERROR) + if (gfc_option.flag_cray_pointer && m == MATCH_YES) + cp_as = gfc_copy_array_spec (as); + else if (m == MATCH_ERROR) goto cleanup; if (m == MATCH_NO) as = gfc_copy_array_spec (current_as); @@ -972,6 +977,49 @@ variable_decl (int elem) } } + /* If this symbol has already shown up in a Cray Pointer declaration, + then we want to set the type & bail out. */ + if (gfc_option.flag_cray_pointer) + { + gfc_find_symbol (name, gfc_current_ns, 1, &sym); + if (sym != NULL && sym->attr.cray_pointee) + { + sym->ts.type = current_ts.type; + sym->ts.kind = current_ts.kind; + sym->ts.cl = cl; + sym->ts.derived = current_ts.derived; + m = MATCH_YES; + + /* Check to see if we have an array specification. */ + if (cp_as != NULL) + { + if (sym->as != NULL) + { + gfc_error ("Duplicate array spec for Cray pointee at %C."); + gfc_free_array_spec (cp_as); + m = MATCH_ERROR; + goto cleanup; + } + else + { + if (gfc_set_array_spec (sym, cp_as, &var_locus) == FAILURE) + gfc_internal_error ("Couldn't set pointee array spec."); + + /* Fix the array spec. */ + m = gfc_mod_pointee_as (sym->as); + if (m == MATCH_ERROR) + goto cleanup; + } + } + goto cleanup; + } + else + { + gfc_free_array_spec (cp_as); + } + } + + /* OK, we've successfully matched the declaration. Now put the symbol in the current namespace, because it might be used in the optional initialization expression for this symbol, e.g. this is @@ -2875,6 +2923,14 @@ attr_decl1 (void) m = MATCH_ERROR; goto cleanup; } + + if (sym->attr.cray_pointee && sym->as != NULL) + { + /* Fix the array spec. */ + m = gfc_mod_pointee_as (sym->as); + if (m == MATCH_ERROR) + goto cleanup; + } if ((current_attr.external || current_attr.intrinsic) && sym->attr.flavor != FL_PROCEDURE @@ -2928,6 +2984,157 @@ attr_decl (void) } +/* This routine matches Cray Pointer declarations of the form: + pointer ( <pointer>, <pointee> ) + or + pointer ( <pointer1>, <pointee1> ), ( <pointer2>, <pointee2> ), ... + The pointer, if already declared, should be an integer. Otherwise, we + set it as BT_INTEGER with kind gfc_index_integer_kind. The pointee may + be either a scalar, or an array declaration. No space is allocated for + the pointee. For the statement + pointer (ipt, ar(10)) + any subsequent uses of ar will be translated (in C-notation) as + ar(i) => ((<type> *) ipt)(i) + By the time the code is translated into GENERIC, the pointee will + have disappeared from the code entirely. */ + +static match +cray_pointer_decl (void) +{ + match m; + gfc_array_spec *as; + gfc_symbol *cptr; /* Pointer symbol. */ + gfc_symbol *cpte; /* Pointee symbol. */ + locus var_locus; + bool done = false; + + while (!done) + { + if (gfc_match_char ('(') != MATCH_YES) + { + gfc_error ("Expected '(' at %C"); + return MATCH_ERROR; + } + + /* Match pointer. */ + var_locus = gfc_current_locus; + gfc_clear_attr (¤t_attr); + gfc_add_cray_pointer (¤t_attr, &var_locus); + current_ts.type = BT_INTEGER; + current_ts.kind = gfc_index_integer_kind; + + m = gfc_match_symbol (&cptr, 0); + if (m != MATCH_YES) + { + gfc_error ("Expected variable name at %C"); + return m; + } + + if (gfc_add_cray_pointer (&cptr->attr, &var_locus) == FAILURE) + return MATCH_ERROR; + + gfc_set_sym_referenced (cptr); + + if (cptr->ts.type == BT_UNKNOWN) /* Override the type, if necessary. */ + { + cptr->ts.type = BT_INTEGER; + cptr->ts.kind = gfc_index_integer_kind; + } + else if (cptr->ts.type != BT_INTEGER) + { + gfc_error ("Cray pointer at %C must be an integer."); + return MATCH_ERROR; + } + else if (cptr->ts.kind < gfc_index_integer_kind) + gfc_warning ("Cray pointer at %C has %d bytes of precision;" + " memory addresses require %d bytes.", + cptr->ts.kind, + gfc_index_integer_kind); + + if (gfc_match_char (',') != MATCH_YES) + { + gfc_error ("Expected \",\" at %C"); + return MATCH_ERROR; + } + + /* Match Pointee. */ + var_locus = gfc_current_locus; + gfc_clear_attr (¤t_attr); + gfc_add_cray_pointee (¤t_attr, &var_locus); + current_ts.type = BT_UNKNOWN; + current_ts.kind = 0; + + m = gfc_match_symbol (&cpte, 0); + if (m != MATCH_YES) + { + gfc_error ("Expected variable name at %C"); + return m; + } + + /* Check for an optional array spec. */ + m = gfc_match_array_spec (&as); + if (m == MATCH_ERROR) + { + gfc_free_array_spec (as); + return m; + } + else if (m == MATCH_NO) + { + gfc_free_array_spec (as); + as = NULL; + } + + if (gfc_add_cray_pointee (&cpte->attr, &var_locus) == FAILURE) + return MATCH_ERROR; + + gfc_set_sym_referenced (cpte); + + if (cpte->as == NULL) + { + if (gfc_set_array_spec (cpte, as, &var_locus) == FAILURE) + gfc_internal_error ("Couldn't set Cray pointee array spec."); + } + else if (as != NULL) + { + gfc_error ("Duplicate array spec for Cray pointee at %C."); + gfc_free_array_spec (as); + return MATCH_ERROR; + } + + as = NULL; + + if (cpte->as != NULL) + { + /* Fix array spec. */ + m = gfc_mod_pointee_as (cpte->as); + if (m == MATCH_ERROR) + return m; + } + + /* Point the Pointee at the Pointer. */ + cpte->cp_pointer=cptr; + + if (gfc_match_char (')') != MATCH_YES) + { + gfc_error ("Expected \")\" at %C"); + return MATCH_ERROR; + } + m = gfc_match_char (','); + if (m != MATCH_YES) + done = true; /* Stop searching for more declarations. */ + + } + + if (m == MATCH_ERROR /* Failed when trying to find ',' above. */ + || gfc_match_eos () != MATCH_YES) + { + gfc_error ("Expected \",\" or end of statement at %C"); + return MATCH_ERROR; + } + return MATCH_YES; +} + + match gfc_match_external (void) { @@ -2981,11 +3188,24 @@ gfc_match_optional (void) match gfc_match_pointer (void) { - - gfc_clear_attr (¤t_attr); - gfc_add_pointer (¤t_attr, NULL); - - return attr_decl (); + gfc_gobble_whitespace (); + if (gfc_peek_char () == '(') + { + if (!gfc_option.flag_cray_pointer) + { + gfc_error ("Cray pointer declaration at %C requires -fcray-pointer" + " flag."); + return MATCH_ERROR; + } + return cray_pointer_decl (); + } + else + { + gfc_clear_attr (¤t_attr); + gfc_add_pointer (¤t_attr, NULL); + + return attr_decl (); + } } @@ -3493,3 +3713,29 @@ loop: return MATCH_YES; } + + +/* Cray Pointees can be declared as: + pointer (ipt, a (n,m,...,*)) + By default, this is treated as an AS_ASSUMED_SIZE array. We'll + cheat and set a constant bound of 1 for the last dimension, if this + is the case. Since there is no bounds-checking for Cray Pointees, + this will be okay. */ + +try +gfc_mod_pointee_as (gfc_array_spec *as) +{ + as->cray_pointee = true; /* This will be useful to know later. */ + if (as->type == AS_ASSUMED_SIZE) + { + as->type = AS_EXPLICIT; + as->upper[as->rank - 1] = gfc_int_expr (1); + as->cp_was_assumed = true; + } + else if (as->type == AS_ASSUMED_SHAPE) + { + gfc_error ("Cray Pointee at %C cannot be assumed shape array"); + return MATCH_ERROR; + } + return MATCH_YES; +} diff --git a/gcc/fortran/expr.c b/gcc/fortran/expr.c index ebfd8486a13..80099df5ad4 100644 --- a/gcc/fortran/expr.c +++ b/gcc/fortran/expr.c @@ -1841,6 +1841,16 @@ gfc_check_assign (gfc_expr * lvalue, gfc_expr * rvalue, int conform) return FAILURE; } + if (sym->attr.cray_pointee + && lvalue->ref != NULL + && lvalue->ref->u.ar.type != AR_ELEMENT + && lvalue->ref->u.ar.as->cp_was_assumed) + { + gfc_error ("Vector assignment to assumed-size Cray Pointee at %L" + " is illegal.", &lvalue->where); + return FAILURE; + } + /* This is possibly a typo: x = f() instead of x => f() */ if (gfc_option.warn_surprising && rvalue->expr_type == EXPR_FUNCTION diff --git a/gcc/fortran/gfortran.h b/gcc/fortran/gfortran.h index 894761367be..56d008c9797 100644 --- a/gcc/fortran/gfortran.h +++ b/gcc/fortran/gfortran.h @@ -360,6 +360,7 @@ enum gfc_generic_isym_id GFC_ISYM_LLE, GFC_ISYM_LLT, GFC_ISYM_LOG, + GFC_ISYM_LOC, GFC_ISYM_LOG10, GFC_ISYM_LOGICAL, GFC_ISYM_MATMUL, @@ -476,6 +477,9 @@ typedef struct ENUM_BITFIELD (ifsrc) if_source:2; ENUM_BITFIELD (procedure_type) proc:3; + + /* Special attributes for Cray pointers, pointees. */ + unsigned cray_pointer:1, cray_pointee:1; } symbol_attribute; @@ -573,6 +577,13 @@ typedef struct int rank; /* A rank of zero means that a variable is a scalar. */ array_type type; struct gfc_expr *lower[GFC_MAX_DIMENSIONS], *upper[GFC_MAX_DIMENSIONS]; + + /* These two fields are used with the Cray Pointer extension. */ + bool cray_pointee; /* True iff this spec belongs to a cray pointee. */ + bool cp_was_assumed; /* AS_ASSUMED_SIZE cp arrays are converted to + AS_EXPLICIT, but we want to remember that we + did this. */ + } gfc_array_spec; @@ -717,6 +728,9 @@ typedef struct gfc_symbol struct gfc_symbol *result; /* function result symbol */ gfc_component *components; /* Derived type components */ + /* Defined only for Cray pointees; points to their pointer. */ + struct gfc_symbol *cp_pointer; + struct gfc_symbol *common_next; /* Links for COMMON syms */ /* This is in fact a gfc_common_head but it is only used for pointer @@ -1458,6 +1472,7 @@ typedef struct int flag_f2c; int flag_automatic; int flag_backslash; + int flag_cray_pointer; int flag_d_lines; int q_kind; @@ -1642,6 +1657,9 @@ try gfc_add_external (symbol_attribute *, locus *); try gfc_add_intrinsic (symbol_attribute *, locus *); try gfc_add_optional (symbol_attribute *, locus *); try gfc_add_pointer (symbol_attribute *, locus *); +try gfc_add_cray_pointer (symbol_attribute *, locus *); +try gfc_add_cray_pointee (symbol_attribute *, locus *); +try gfc_mod_pointee_as (gfc_array_spec *as); try gfc_add_result (symbol_attribute *, const char *, locus *); try gfc_add_save (symbol_attribute *, const char *, locus *); try gfc_add_saved_common (symbol_attribute *, locus *); diff --git a/gcc/fortran/gfortran.texi b/gcc/fortran/gfortran.texi index a4ecee3d9a0..b4e672eea50 100644 --- a/gcc/fortran/gfortran.texi +++ b/gcc/fortran/gfortran.texi @@ -491,9 +491,6 @@ Flag to generate @code{Makefile} info. Automatically extend single precision constants to double. @item -Cray pointers (this was high on the @command{g77} wishlist). - -@item Compile code that conserves memory by dynamically allocating common and module storage either on stack or heap. @@ -633,6 +630,7 @@ of extensions, and @option{-std=legacy} allows both without warning. * Unary operators:: * Implicitly interconvert LOGICAL and INTEGER:: * Hollerith constants support:: +* Cray pointers:: @end menu @node Old-style kind specifications @@ -843,6 +841,143 @@ a = 8H12345678 ! The Hollerith constant is too long. It will be truncated. a = 0H ! At least one character needed. @end smallexample +@node Cray pointers +@section Cray pointers +@cindex Cray pointers + +Cray pointers are part of a non-standard extension that provides a +C-like pointer in Fortran. This is accomplished through a pair of +variables: an integer "pointer" that holds a memory address, and a +"pointee" that is used to dereference the pointer. + +Pointer/pointee pairs are declared in statements of the form: +@smallexample + pointer ( <pointer> , <pointee> ) +@end smallexample +or, +@smallexample + pointer ( <pointer1> , <pointee1> ), ( <pointer2> , <pointee2> ), ... +@end smallexample +The pointer is an integer that is intended to hold a memory address. +The pointee may be an array or scalar. A pointee can be an assumed +size array -- that is, the last dimension may be left unspecified by +using a '*' in place of a value -- but a pointee cannot be an assumed +shape array. No space is allocated for the pointee. + +The pointee may have its type declared before or after the pointer +statement, and its array specification (if any) may be declared +before, during, or after the pointer statement. The pointer may be +declared as an integer prior to the pointer statement. However, some +machines have default integer sizes that are different than the size +of a pointer, and so the following code is not portable: +@smallexample + integer ipt + pointer (ipt, iarr) +@end smallexample +If a pointer is declared with a kind that is too small, the compiler +will issue a warning; the resulting binary will probably not work +correctly, because the memory addresses stored in the pointers may be +truncated. It is safer to omit the first line of the above example; +if explicit declaration of ipt's type is omitted, then the compiler +will ensure that ipt is an integer variable large enough to hold a +pointer. + +Pointer arithmetic is valid with Cray pointers, but it is not the same +as C pointer arithmetic. Cray pointers are just ordinary integers, so +the user is responsible for determining how many bytes to add to a +pointer in order to increment it. Consider the following example: +@smallexample + real target(10) + real pointee(10) + pointer (ipt, pointee) + ipt = loc (target) + ipt = ipt + 1 +@end smallexample +The last statement does not set ipt to the address of +@code{target(1)}, as one familiar with C pointer arithmetic might +expect. Adding 1 to ipt just adds one byte to the address stored in +ipt. + +Any expression involving the pointee will be translated to use the +value stored in the pointer as the base address. This translation is +done in the front end, and so the pointees are not present in the +GENERIC tree that is handed off to the backend. One disadvantage of +this is that pointees will not appear in gdb when debugging a Fortran +program that uses Cray pointers. + +To get the address of elements, this extension provides an intrinsic +function loc(), loc() is essentially the C '&' operator, except the +address is cast to an integer type: +@smallexample + real ar(10) + pointer(ipt, arpte(10)) + real arpte + ipt = loc(ar) ! Makes arpte is an alias for ar + arpte(1) = 1.0 ! Sets ar(1) to 1.0 +@end smallexample +The pointer can also be set by a call to a malloc-type +function. There is no malloc intrinsic implemented as part of the +Cray pointer extension, but it might be a useful future addition to +@command{gfortran}. Even without an intrinsic malloc function, +dynamic memory allocation can be combined with Cray pointers by +calling a short C function: +@smallexample +mymalloc.c: + + void mymalloc_(void **ptr, int *nbytes) + @{ + *ptr = malloc(*nbytes); + return; + @} + +caller.f: + + program caller + integer ipinfo; + real*4 data + pointer (ipdata, data(1024)) + call mymalloc(ipdata,4*1024) + end +@end smallexample +Cray pointees often are used to alias an existing variable. For +example: +@smallexample + integer target(10) + integer iarr(10) + pointer (ipt, iarr) + ipt = loc(target) +@end smallexample +As long as ipt remains unchanged, iarr is now an alias for target. +The optimizer, however, will not detect this aliasing, so it is unsafe +to use iarr and target simultaneously. Using a pointee in any way +that violates the Fortran aliasing rules or assumptions is illegal. +It is the user's responsibility to avoid doing this; the compiler +works under the assumption that no such aliasing occurs. + +Cray pointers will work correctly when there is no aliasing (i.e., +when they're used to access a dynamically allocated block of memory), +and also in any routine where a pointee is used, but any variable with +which it shares storage is not used. Code that violates these rules +may not run as the user intends. This is not a bug in the optimizer; +any code that violates the aliasing rules is illegal. (Note that this +is not unique to gfortran; any Fortran compiler that supports Cray +pointers will ``incorrectly'' optimize code with illegal aliasing.) + +There are a number of restrictions on the attributes that can be +applied to Cray pointers and pointees. Pointees may not have the +attributes ALLOCATABLE, INTENT, OPTIONAL, DUMMY, TARGET, EXTERNAL, +INTRINSIC, or POINTER. Pointers may not have the attributes +DIMENSION, POINTER, TARGET, ALLOCATABLE, EXTERNAL, or INTRINSIC. +Pointees may not occur in more than one pointer statement. A pointee +cannot be a pointer. Pointees cannot occur in equivalence, common, or +data statements. + +A pointer may be modified during the course of a program, and this +will change the location to which the pointee refers. However, when +pointees are passed as arguments, they are treated as ordinary +variables in the invoked function. Subsequent changes to the pointer +will not change the base address of the array that was passed. + @include intrinsic.texi @c --------------------------------------------------------------------- @c Contributing diff --git a/gcc/fortran/intrinsic.c b/gcc/fortran/intrinsic.c index be23556b39e..93dde153d10 100644 --- a/gcc/fortran/intrinsic.c +++ b/gcc/fortran/intrinsic.c @@ -2098,6 +2098,13 @@ add_functions (void) bck, BT_LOGICAL, dl, OPTIONAL); make_generic ("verify", GFC_ISYM_VERIFY, GFC_STD_F95); + + add_sym_1 ("loc", 0, 1, BT_INTEGER, ii, GFC_STD_GNU, + gfc_check_loc, NULL, gfc_resolve_loc, + ar, BT_UNKNOWN, 0, REQUIRED); + + make_generic ("loc", GFC_ISYM_LOC, GFC_STD_GNU); + } diff --git a/gcc/fortran/intrinsic.h b/gcc/fortran/intrinsic.h index c405ccedba2..950ac7dfbeb 100644 --- a/gcc/fortran/intrinsic.h +++ b/gcc/fortran/intrinsic.h @@ -77,6 +77,7 @@ try gfc_check_kill (gfc_expr *, gfc_expr *); try gfc_check_kind (gfc_expr *); try gfc_check_lbound (gfc_expr *, gfc_expr *); try gfc_check_link (gfc_expr *, gfc_expr *); +try gfc_check_loc (gfc_expr *); try gfc_check_logical (gfc_expr *, gfc_expr *); try gfc_check_min_max (gfc_actual_arglist *); try gfc_check_min_max_integer (gfc_actual_arglist *); @@ -327,6 +328,7 @@ void gfc_resolve_lbound (gfc_expr *, gfc_expr *, gfc_expr *); void gfc_resolve_len (gfc_expr *, gfc_expr *); void gfc_resolve_len_trim (gfc_expr *, gfc_expr *); void gfc_resolve_link (gfc_expr *, gfc_expr *, gfc_expr *); +void gfc_resolve_loc (gfc_expr *, gfc_expr *); void gfc_resolve_log (gfc_expr *, gfc_expr *); void gfc_resolve_log10 (gfc_expr *, gfc_expr *); void gfc_resolve_logical (gfc_expr *, gfc_expr *, gfc_expr *); diff --git a/gcc/fortran/intrinsic.texi b/gcc/fortran/intrinsic.texi index 2043c282e8e..5db2472590c 100644 --- a/gcc/fortran/intrinsic.texi +++ b/gcc/fortran/intrinsic.texi @@ -87,6 +87,7 @@ and editing. All contributions and corrections are strongly encouraged. * @code{EXPONENT}: EXPONENT, Exponent function * @code{FLOOR}: FLOOR, Integer floor function * @code{FNUM}: FNUM, File number function +* @code{LOC}: LOC, Returns the address of a variable * @code{LOG}: LOG, Logarithm function * @code{LOG10}: LOG10, Base 10 logarithm function * @code{REAL}: REAL, Convert to real type @@ -2724,7 +2725,43 @@ end program test_fnum @end smallexample @end table +@node LOC +@section @code{LOC} --- Returns the address of a variable +@findex @code{LOC} intrinsic +@cindex loc +@table @asis +@item @emph{Description}: +@code{LOC(X)} returns the address of @var{X} as an integer. + +@item @emph{Option}: +gnu + +@item @emph{Class}: +inquiry function + +@item @emph{Syntax}: +@code{I = LOC(X)} + +@item @emph{Arguments}: +@multitable @columnfractions .15 .80 +@item @var{X} @tab Variable of any type. +@end multitable + +@item @emph{Return value}: +The return value is of type @code{INTEGER(n)}, where @code{n} is the +size (in bytes) of a memory address on the target machine. + +@item @emph{Example}: +@smallexample +program test_loc + integer :: i + real :: r + i = loc(r) + print *, i +end program test_loc +@end smallexample +@end table @node LOG @section @code{LOG} --- Logarithm function diff --git a/gcc/fortran/invoke.texi b/gcc/fortran/invoke.texi index 88e8eefe969..db53302d0a3 100644 --- a/gcc/fortran/invoke.texi +++ b/gcc/fortran/invoke.texi @@ -119,7 +119,8 @@ by type. Explanations are in the following sections. -fdollar-ok -fimplicit-none -fmax-identifier-length @gol -std=@var{std} -fd-lines-as-code -fd-lines-as-comments @gol -ffixed-line-length-@var{n} -ffixed-line-length-none @gol --fdefault-double-8 -fdefault-integer-8 -fdefault-real-8 } +-fdefault-double-8 -fdefault-integer-8 -fdefault-real-8 @gol +-fcray-pointer } @item Warning Options @xref{Warning Options,,Options to Request or Suppress Warnings}. @@ -265,6 +266,11 @@ Specify that no implicit typing is allowed, unless overridden by explicit @samp{IMPLICIT} statements. This is the equivalent of adding @samp{implicit none} to the start of every procedure. +@cindex -fcray-pointer option +@cindex options, -fcray-pointer +@item -fcray-pointer +Enables the Cray pointer extension, which provides a C-like pointer. + @cindex -std=@var{std} option @cindex option, -std=@var{std} @item -std=@var{std} diff --git a/gcc/fortran/iresolve.c b/gcc/fortran/iresolve.c index 9cba18bd1ef..09d85e33974 100644 --- a/gcc/fortran/iresolve.c +++ b/gcc/fortran/iresolve.c @@ -871,6 +871,15 @@ gfc_resolve_link (gfc_expr * f, gfc_expr * p1 ATTRIBUTE_UNUSED, void +gfc_resolve_loc (gfc_expr *f, gfc_expr *x) +{ + f->ts.type= BT_INTEGER; + f->ts.kind = gfc_index_integer_kind; + f->value.function.name = gfc_get_string ("__loc_%d", x->ts.kind); +} + + +void gfc_resolve_log (gfc_expr * f, gfc_expr * x) { f->ts = x->ts; diff --git a/gcc/fortran/lang.opt b/gcc/fortran/lang.opt index 053cc3dbf70..b44c38b34a1 100644 --- a/gcc/fortran/lang.opt +++ b/gcc/fortran/lang.opt @@ -121,6 +121,10 @@ funderscoring Fortran Append underscores to externally visible names +fcray-pointer +Fortran +Use the Cray Pointer extension + fsecond-underscore Fortran Append a second underscore if the name already contains an underscore diff --git a/gcc/fortran/options.c b/gcc/fortran/options.c index 95720bf5105..53e8ec7b419 100644 --- a/gcc/fortran/options.c +++ b/gcc/fortran/options.c @@ -72,6 +72,7 @@ gfc_init_options (unsigned int argc ATTRIBUTE_UNUSED, gfc_option.flag_repack_arrays = 0; gfc_option.flag_automatic = 1; gfc_option.flag_backslash = 1; + gfc_option.flag_cray_pointer = 0; gfc_option.flag_d_lines = -1; gfc_option.q_kind = gfc_default_double_kind; @@ -364,6 +365,10 @@ gfc_handle_option (size_t scode, const char *arg, int value) case OPT_Wunused_labels: gfc_option.warn_unused_labels = value; break; + + case OPT_fcray_pointer: + gfc_option.flag_cray_pointer = value; + break; case OPT_ff2c: gfc_option.flag_f2c = value; diff --git a/gcc/fortran/resolve.c b/gcc/fortran/resolve.c index 26f11c50583..8ae1162b6ae 100644 --- a/gcc/fortran/resolve.c +++ b/gcc/fortran/resolve.c @@ -2013,7 +2013,7 @@ resolve_array_ref (gfc_array_ref * ar) } } - if (compare_spec_to_ref (ar) == FAILURE) + if (!ar->as->cray_pointee && compare_spec_to_ref (ar) == FAILURE) return FAILURE; return SUCCESS; @@ -5176,6 +5176,14 @@ resolve_equivalence (gfc_equiv *eq) sym->name, &e->where, sym->ns->proc_name->name); break; } + + /* Shall not be a Cray pointee. */ + if (sym->attr.cray_pointee) + { + gfc_error ("Cray Pointee '%s' at %L cannot be an EQUIVALENCE " + "object", sym->name, &e->where); + continue; + } /* Shall not be a named constant. */ if (e->expr_type == EXPR_CONSTANT) diff --git a/gcc/fortran/symbol.c b/gcc/fortran/symbol.c index c1221eb72a5..b9e76ef195c 100644 --- a/gcc/fortran/symbol.c +++ b/gcc/fortran/symbol.c @@ -263,7 +263,8 @@ check_conflict (symbol_attribute * attr, const char * name, locus * where) *public = "PUBLIC", *optional = "OPTIONAL", *entry = "ENTRY", *function = "FUNCTION", *subroutine = "SUBROUTINE", *dimension = "DIMENSION", *in_equivalence = "EQUIVALENCE", - *use_assoc = "USE ASSOCIATED"; + *use_assoc = "USE ASSOCIATED", *cray_pointer = "CRAY POINTER", + *cray_pointee = "CRAY POINTEE"; const char *a1, *a2; @@ -343,6 +344,31 @@ check_conflict (symbol_attribute * attr, const char * name, locus * where) conf (function, subroutine); + /* Cray pointer/pointee conflicts. */ + conf (cray_pointer, cray_pointee); + conf (cray_pointer, dimension); + conf (cray_pointer, pointer); + conf (cray_pointer, target); + conf (cray_pointer, allocatable); + conf (cray_pointer, external); + conf (cray_pointer, intrinsic); + conf (cray_pointer, in_namelist); + conf (cray_pointer, function); + conf (cray_pointer, subroutine); + conf (cray_pointer, entry); + + conf (cray_pointee, allocatable); + conf (cray_pointee, intent); + conf (cray_pointee, optional); + conf (cray_pointee, dummy); + conf (cray_pointee, target); + conf (cray_pointee, external); + conf (cray_pointee, intrinsic); + conf (cray_pointee, pointer); + conf (cray_pointee, function); + conf (cray_pointee, subroutine); + conf (cray_pointee, entry); + a1 = gfc_code2string (flavors, attr->flavor); if (attr->in_namelist @@ -653,6 +679,37 @@ gfc_add_pointer (symbol_attribute * attr, locus * where) try +gfc_add_cray_pointer (symbol_attribute * attr, locus * where) +{ + + if (check_used (attr, NULL, where) || check_done (attr, where)) + return FAILURE; + + attr->cray_pointer = 1; + return check_conflict (attr, NULL, where); +} + + +try +gfc_add_cray_pointee (symbol_attribute * attr, locus * where) +{ + + if (check_used (attr, NULL, where) || check_done (attr, where)) + return FAILURE; + + if (attr->cray_pointee) + { + gfc_error ("Cray Pointee at %L appears in multiple pointer()" + " statements.", where); + return FAILURE; + } + + attr->cray_pointee = 1; + return check_conflict (attr, NULL, where); +} + + +try gfc_add_result (symbol_attribute * attr, const char *name, locus * where) { @@ -1149,6 +1206,11 @@ gfc_copy_attr (symbol_attribute * dest, symbol_attribute * src, locus * where) if (gfc_missing_attr (dest, where) == FAILURE) goto fail; + if (src->cray_pointer && gfc_add_cray_pointer (dest, where) == FAILURE) + goto fail; + if (src->cray_pointee && gfc_add_cray_pointee (dest, where) == FAILURE) + goto fail; + /* The subroutines that set these bits also cause flavors to be set, and that has already happened in the original, so don't let it happen again. */ diff --git a/gcc/fortran/trans-array.c b/gcc/fortran/trans-array.c index c284dca5465..1a09121f87c 100644 --- a/gcc/fortran/trans-array.c +++ b/gcc/fortran/trans-array.c @@ -3240,6 +3240,15 @@ gfc_trans_auto_array_allocation (tree decl, gfc_symbol * sym, tree fnbody) size = gfc_trans_array_bounds (type, sym, &offset, &block); + /* Don't actually allocate space for Cray Pointees. */ + if (sym->attr.cray_pointee) + { + if (TREE_CODE (GFC_TYPE_ARRAY_OFFSET (type)) == VAR_DECL) + gfc_add_modify_expr (&block, GFC_TYPE_ARRAY_OFFSET (type), offset); + gfc_add_expr_to_block (&block, fnbody); + return gfc_finish_block (&block); + } + /* The size is the number of elements in the array, so multiply by the size of an element to get the total size. */ tmp = TYPE_SIZE_UNIT (gfc_get_element_type (type)); @@ -4074,7 +4083,13 @@ gfc_conv_array_parameter (gfc_se * se, gfc_expr * expr, gfc_ss * ss, int g77) && expr->ref->u.ar.type == AR_FULL && g77) { sym = expr->symtree->n.sym; - tmp = gfc_get_symbol_decl (sym); + + /* Check to see if we're dealing with a Cray Pointee. */ + if (sym->attr.cray_pointee) + tmp = gfc_conv_cray_pointee (sym); + else + tmp = gfc_get_symbol_decl (sym); + if (sym->ts.type == BT_CHARACTER) se->string_length = sym->ts.cl->backend_decl; if (!sym->attr.pointer && sym->as->type != AS_ASSUMED_SHAPE @@ -4625,4 +4640,3 @@ gfc_walk_expr (gfc_expr * expr) res = gfc_walk_subexpr (gfc_ss_terminator, expr); return gfc_reverse_ss (res); } - diff --git a/gcc/fortran/trans-decl.c b/gcc/fortran/trans-decl.c index 70e8e82856a..4b6e2265828 100644 --- a/gcc/fortran/trans-decl.c +++ b/gcc/fortran/trans-decl.c @@ -416,6 +416,11 @@ gfc_finish_var_decl (tree decl, gfc_symbol * sym) This is the equivalent of the TARGET variables. We also need to set this if the variable is passed by reference in a CALL statement. */ + + /* We don't want real declarations for Cray Pointees. */ + if (sym->attr.cray_pointee) + return; + if (sym->attr.target) TREE_ADDRESSABLE (decl) = 1; /* If it wasn't used we wouldn't be getting it. */ @@ -2251,6 +2256,10 @@ gfc_create_module_variable (gfc_symbol * sym) /* Create the decl. */ decl = gfc_get_symbol_decl (sym); + /* Don't create a "real" declaration for a Cray Pointee. */ + if (sym->attr.cray_pointee) + return; + /* Create the variable. */ pushdecl (decl); rest_of_decl_compilation (decl, 1, 0); @@ -2672,4 +2681,36 @@ gfc_generate_block_data (gfc_namespace * ns) rest_of_decl_compilation (decl, 1, 0); } +/* gfc_conv_cray_pointee takes a sym with attribute cray_pointee and + swaps in the backend_decl of its corresponding pointer. There are + 2 cases; one for variable size arrays, and one for everything else, + because variable-sized arrays require one fewer level of + indirection. */ + +tree +gfc_conv_cray_pointee(gfc_symbol *sym) +{ + tree decl = gfc_get_symbol_decl (sym->cp_pointer); + + /* Parameters need to be dereferenced. */ + if (sym->cp_pointer->attr.dummy) + decl = gfc_build_indirect_ref (decl); + + /* Check to see if we're dealing with a variable-sized array. */ + if (sym->attr.dimension + && TREE_CODE (TREE_TYPE (sym->backend_decl)) == POINTER_TYPE) + { + /* These decls will be derefenced later, so we don't dereference + them here. */ + decl = convert (TREE_TYPE (sym->backend_decl), decl); + } + else + { + decl = convert (build_pointer_type (TREE_TYPE (sym->backend_decl)), + decl); + decl = gfc_build_indirect_ref (decl); + } + return decl; +} + #include "gt-fortran-trans-decl.h" diff --git a/gcc/fortran/trans-expr.c b/gcc/fortran/trans-expr.c index fe5e24bdb07..4dc4d56b356 100644 --- a/gcc/fortran/trans-expr.c +++ b/gcc/fortran/trans-expr.c @@ -316,7 +316,11 @@ gfc_conv_variable (gfc_se * se, gfc_expr * expr) { tree se_expr = NULL_TREE; - se->expr = gfc_get_symbol_decl (sym); + /* Handle Cray Pointees. */ + if (sym->attr.cray_pointee) + se->expr = gfc_conv_cray_pointee (sym); + else + se->expr = gfc_get_symbol_decl (sym); /* Special case for assigning the return value of a function. Self recursive functions must have an explicit return value. */ diff --git a/gcc/fortran/trans-intrinsic.c b/gcc/fortran/trans-intrinsic.c index 1d958e18ad7..4905ac57381 100644 --- a/gcc/fortran/trans-intrinsic.c +++ b/gcc/fortran/trans-intrinsic.c @@ -2739,6 +2739,36 @@ gfc_conv_intrinsic_iargc (gfc_se * se, gfc_expr * expr) se->expr = tmp; } + +/* The loc intrinsic returns the address of its argument as + gfc_index_integer_kind integer. */ + +static void +gfc_conv_intrinsic_loc(gfc_se * se, gfc_expr * expr) +{ + tree temp_var; + gfc_expr *arg_expr; + gfc_ss *ss; + + gcc_assert (!se->ss); + + arg_expr = expr->value.function.actual->expr; + ss = gfc_walk_expr (arg_expr); + if (ss == gfc_ss_terminator) + gfc_conv_expr_reference (se, arg_expr); + else + gfc_conv_array_parameter (se, arg_expr, ss, 1); + se->expr= convert (gfc_unsigned_type (long_integer_type_node), + se->expr); + + /* Create a temporary variable for loc return value. Without this, + we get an error an ICE in gcc/expr.c(expand_expr_addr_expr_1). */ + temp_var = gfc_create_var (gfc_unsigned_type (long_integer_type_node), + NULL); + gfc_add_modify_expr (&se->pre, temp_var, se->expr); + se->expr = temp_var; +} + /* Generate code for an intrinsic function. Some map directly to library calls, others get special handling. In some cases the name of the function used depends on the type specifiers. */ @@ -3047,6 +3077,10 @@ gfc_conv_intrinsic_function (gfc_se * se, gfc_expr * expr) gfc_conv_intrinsic_bound (se, expr, 1); break; + case GFC_ISYM_LOC: + gfc_conv_intrinsic_loc (se, expr); + break; + case GFC_ISYM_CHDIR: case GFC_ISYM_DOT_PRODUCT: case GFC_ISYM_ETIME: diff --git a/gcc/fortran/trans.h b/gcc/fortran/trans.h index 16d0a37ed3f..16dd51747b9 100644 --- a/gcc/fortran/trans.h +++ b/gcc/fortran/trans.h @@ -406,6 +406,9 @@ void gfc_generate_block_data (gfc_namespace *); /* Output a decl for a module variable. */ void gfc_generate_module_vars (gfc_namespace *); +/* Translate the declaration for a Cray Pointee. */ +tree gfc_conv_cray_pointee (gfc_symbol *sym); + /* Get and set the current location. */ void gfc_set_backend_locus (locus *); void gfc_get_backend_locus (locus *); |