* [Patch, Fortran] -fcoarray=lib - add registering calls for nonallocatable coarrays
@ 2011-05-22 19:08 Tobias Burnus
2011-05-25 0:24 ` Tobias Burnus
0 siblings, 1 reply; 6+ messages in thread
From: Tobias Burnus @ 2011-05-22 19:08 UTC (permalink / raw)
To: gcc patches, gfortran
[-- Attachment #1: Type: text/plain, Size: 2821 bytes --]
The following applies to -fcoarray=lib; for -fcoarray=single there
should be no change.
The coarray communication library needs to know about the coarrays even
before the function containing them has been invoked. Thus, the coarrays
(of all translation units) need to be registered at start up.
This patch handles this by creating a _caf_init function with
constructor attribute, which is nested in the the parent's procedure if
the latter contains local nonallocatable (and thus: static/SAVE)
coarrays variables.
At the same time, all (nonallocatable) coarrays have been turned into
pointers - to allow the communication library to allocate the memory.
This allows optimizations, e.g., by allocating in memory which is
available for all images on the same node (cf. MPI_Alloc_mem).
Additionally, a "token" is saved with the coarray, which allows the
coarray library to identify the coarray. In a simple implementation, it
could simply use the base_addr of the coarray or enumerate them through.
Example: The small example program
------------- < test.f90 >-----------------
program caf_program
integer :: a[*] = 7
a = 8
end program caf_program
------------- </ test.f90 >-----------------
is turned into the following tree (-fdump-tree-original)
------------- < test.f90.003t.original >-----------------
_caf_init.1 ()
{
a = (integer(kind=4) * restrict) _gfortran_caf_register (4, 0,
&caf_token.0, 0B, 0B, 0);
*a = 7;
}
caf_program ()
{
static void * caf_token.0;
static integer(kind=4) * restrict a;
void _caf_init.1 (void);
(integer(kind=4)) *a = 8;
}
main (integer(kind=4) argc, character(kind=1) * * argv)
{
static integer(kind=4) options.2[8] = {68, 1023, 0, 0, 1, 1, 0, 1};
_gfortran_caf_init (&argc, &argv, &_gfortran_caf_this_image,
&_gfortran_caf_num_images);
_gfortran_set_args (argc, argv);
_gfortran_set_options (8, &options.2[0]);
_gfortran_caf_sync_all (0B, 0);
caf_program ();
__sync_synchronize ();
_gfortran_caf_finalize ();
return 0;
}
------------- </ test.f90.003t.original >-----------------
Note: By construction, _gfortran_caf_register is called before
_gfortran_caf_init; thus, the MPI library will be initialized by the
first _gfortran_caf_register call, unless the program does not have any
nonallocatable coarrays.
No test cases, but the ones in gfortran.dg/coarray/ should already test
this functionality.
To be done in later patches:
- Coarrays declared in modules (module variables)
- Allocatable coarrays
Note: As constructors are never optimized away [unless they are
pure/const], static coarrays and also uncalled functions containing
static coarrays will not be optimized away. (Cf. PRs middle-end/49106
and middle-end/49108.)
Bootstrapped and regtested on x86-64-linux.
OK for the trunk?
Tobias
[-- Attachment #2: caf_register.diff --]
[-- Type: text/x-patch, Size: 13104 bytes --]
2011-05-22 Tobias Burnus <burnus@net-b.de>
PR fortran/18918
* trans-array.c (gfc_conv_array_ref): Handle pointer coarrays.
* trans-decl.c (has_coarray_vars, caf_init_block,
gfor_fndecl_caf_register): New file-global variables.
(gfc_finish_var_decl): Make sure that coarrays in main are static.
(gfc_build_qualified_array): Generate coarray token variable.
(gfc_get_symbol_decl): Don't use a static initializer for coarrays.
(gfc_build_builtin_function_decls): Set gfor_fndecl_caf_register.
(gfc_trans_deferred_vars, gfc_emit_parameter_debug_info): Skip for
static coarrays.
(generate_local_decl): Check for local coarrays.
(create_main_function): SYNC ALL before calling MAIN.
(generate_coarray_sym_init): Register static coarray.
(generate_coarray_init): Generate CAF registering constructor
function.
(gfc_generate_function_code): Call it, if needed, do not create
cgraph twice.
* trans-types.c (gfc_get_nodesc_array_type): Generate pointers for
-fcoarray=lib.
* trans.h (gfor_fndecl_caf_register): New variable.
(lang_type): New element caf_token.
(GFC_TYPE_ARRAY_CAF_TOKEN): New macro.
diff --git a/gcc/fortran/trans-array.c b/gcc/fortran/trans-array.c
index 78d65a6..29c7f83 100644
--- a/gcc/fortran/trans-array.c
+++ b/gcc/fortran/trans-array.c
@@ -2623,6 +2623,10 @@ gfc_conv_array_ref (gfc_se * se, gfc_array_ref * ar, gfc_symbol * sym,
if (ar->dimen == 0)
{
gcc_assert (ar->codimen);
+ if (GFC_ARRAY_TYPE_P (TREE_TYPE (se->expr))
+ && TREE_CODE (TREE_TYPE (se->expr)) == POINTER_TYPE)
+ se->expr = build_fold_indirect_ref_loc (input_location, se->expr);
+
/* Use the actual tree type and not the wrapped coarray. */
se->expr = fold_convert (TREE_TYPE (TREE_TYPE (se->expr)), se->expr);
return;
diff --git a/gcc/fortran/trans-decl.c b/gcc/fortran/trans-decl.c
index d771484..5121a39 100644
--- a/gcc/fortran/trans-decl.c
+++ b/gcc/fortran/trans-decl.c
@@ -78,6 +78,12 @@ static gfc_namespace *module_namespace;
static gfc_symbol* current_procedure_symbol = NULL;
+/* With -fcoarray=lib: For generating the registering call
+ of static coarrays. */
+static bool has_coarray_vars;
+static stmtblock_t caf_init_block;
+
+
/* List of static constructor functions. */
tree gfc_static_ctors;
@@ -114,6 +120,7 @@ tree gfor_fndecl_associated;
/* Coarray run-time library function decls. */
tree gfor_fndecl_caf_init;
tree gfor_fndecl_caf_finalize;
+tree gfor_fndecl_caf_register;
tree gfor_fndecl_caf_critical;
tree gfor_fndecl_caf_end_critical;
tree gfor_fndecl_caf_sync_all;
@@ -566,7 +573,9 @@ gfc_finish_var_decl (tree decl, gfc_symbol * sym)
SAVE_EXPLICIT. */
if (!sym->attr.use_assoc
&& (sym->attr.save != SAVE_NONE || sym->attr.data
- || (sym->value && sym->ns->proc_name->attr.is_main_program)))
+ || (sym->value && sym->ns->proc_name->attr.is_main_program)
+ || (gfc_option.coarray == GFC_FCOARRAY_LIB
+ && sym->attr.codimension && !sym->attr.allocatable)))
TREE_STATIC (decl) = 1;
if (sym->attr.volatile_)
@@ -745,6 +754,18 @@ gfc_build_qualified_array (tree decl, gfc_symbol * sym)
nest = (procns->proc_name->backend_decl != current_function_decl)
&& !sym->attr.contained;
+ if (sym->attr.codimension && gfc_option.coarray == GFC_FCOARRAY_LIB
+ && GFC_TYPE_ARRAY_CAF_TOKEN (type) == NULL_TREE)
+ {
+ tree token;
+
+ token = gfc_create_var_np (pvoid_type_node, "caf_token");
+ GFC_TYPE_ARRAY_CAF_TOKEN (type) = token;
+ DECL_ARTIFICIAL (token) = 1;
+ TREE_STATIC (token) = 1;
+ gfc_add_decl_to_function (token);
+ }
+
for (dim = 0; dim < GFC_TYPE_ARRAY_RANK (type); dim++)
{
if (GFC_TYPE_ARRAY_LBOUND (type, dim) == NULL_TREE)
@@ -1403,7 +1424,8 @@ gfc_get_symbol_decl (gfc_symbol * sym)
&& !(sym->attr.use_assoc && !intrinsic_array_parameter)
&& (sym->attr.save || sym->ns->proc_name->attr.is_main_program
|| gfc_option.flag_max_stack_var_size == 0
- || sym->attr.data || sym->ns->proc_name->attr.flavor == FL_MODULE))
+ || sym->attr.data || sym->ns->proc_name->attr.flavor == FL_MODULE)
+ && (gfc_option.coarray != GFC_FCOARRAY_LIB || !sym->attr.codimension))
{
/* Add static initializer. For procedures, it is only needed if
SAVE is specified otherwise they need to be reinitialized
@@ -3025,6 +3047,11 @@ gfc_build_builtin_function_decls (void)
gfor_fndecl_caf_finalize = gfc_build_library_function_decl (
get_identifier (PREFIX("caf_finalize")), void_type_node, 0);
+ gfor_fndecl_caf_register = gfc_build_library_function_decl_with_spec (
+ get_identifier (PREFIX("caf_register")), "...WWW", pvoid_type_node, 6,
+ size_type_node, integer_type_node, ppvoid_type_node, pint_type,
+ build_pointer_type (pchar_type_node), integer_type_node);
+
gfor_fndecl_caf_critical = gfc_build_library_function_decl (
get_identifier (PREFIX("caf_critical")), void_type_node, 0);
@@ -3458,7 +3485,7 @@ gfc_trans_deferred_vars (gfc_symbol * proc_sym, gfc_wrapped_block * block)
gfc_trans_deferred_array (sym, block);
}
}
- else
+ else if (gfc_option.coarray != GFC_FCOARRAY_LIB)
{
gfc_save_backend_locus (&loc);
gfc_set_backend_locus (&sym->declared_at);
@@ -4066,6 +4093,9 @@ gfc_emit_parameter_debug_info (gfc_symbol *sym)
sym->attr.dimension, false))
return;
+ if (gfc_option.coarray == GFC_FCOARRAY_LIB && sym->attr.codimension)
+ return;
+
/* Create the decl for the variable or constant. */
decl = build_decl (input_location,
sym->attr.flavor == FL_PARAMETER ? CONST_DECL : VAR_DECL,
@@ -4200,6 +4230,10 @@ generate_local_decl (gfc_symbol * sym)
{
if (sym->attr.flavor == FL_VARIABLE)
{
+ if (sym->attr.codimension && !sym->attr.dummy && !sym->attr.allocatable
+ && sym->attr.referenced)
+ has_coarray_vars = true;
+
if (!sym->attr.dummy && !sym->ns->proc_name->attr.entry_master)
generate_dependency_declarations (sym);
@@ -4826,6 +4860,116 @@ gfc_generate_return (void)
}
+static void
+generate_coarray_sym_init (gfc_symbol *sym)
+{
+ tree tmp, size, decl, token;
+
+ if (sym->attr.dummy || sym->attr.allocatable || !sym->attr.codimension)
+ return;
+
+ if (!sym->attr.referenced)
+ return;
+
+ decl = sym->backend_decl;
+ TREE_USED(decl) = 1;
+ gcc_assert (GFC_ARRAY_TYPE_P (TREE_TYPE (decl)));
+
+ /* FIXME: Workaround for PR middle-end/49106, cf. also PR middle-end/49108
+ to make sure the variable is not optimized away. */
+ DECL_PRESERVE_P (DECL_CONTEXT (decl)) = 1;
+
+ size = TYPE_SIZE_UNIT (gfc_get_element_type (TREE_TYPE (decl)));
+
+ if (GFC_TYPE_ARRAY_RANK (TREE_TYPE (decl)))
+ {
+ tmp = GFC_TYPE_ARRAY_SIZE (TREE_TYPE (decl));
+ size = fold_build2_loc (input_location, MULT_EXPR, size_type_node,
+ fold_convert (size_type_node, tmp),
+ fold_convert (size_type_node, size));
+ }
+
+ gcc_assert (GFC_TYPE_ARRAY_CAF_TOKEN (TREE_TYPE (decl)) != NULL_TREE);
+ token = gfc_build_addr_expr (ppvoid_type_node,
+ GFC_TYPE_ARRAY_CAF_TOKEN (TREE_TYPE(decl)));
+
+ tmp = build_call_expr_loc (input_location, gfor_fndecl_caf_register, 6, size,
+ build_int_cst (integer_type_node, 0), /* type. */
+ token, null_pointer_node, /* token, stat. */
+ null_pointer_node, /* errgmsg, errmsg_len. */
+ build_int_cst (integer_type_node, 0));
+
+ gfc_add_modify (&caf_init_block, decl, fold_convert (TREE_TYPE (decl), tmp));
+
+
+ /* Handle "static" initializer. */
+ if (sym->value)
+ {
+ sym->attr.pointer = 1;
+ tmp = gfc_trans_assignment (gfc_lval_expr_from_sym (sym), sym->value,
+ true, false);
+ sym->attr.pointer = 0;
+ gfc_add_expr_to_block (&caf_init_block, tmp);
+ }
+}
+
+
+/* Generate constructor function to initialize static, nonallocatable
+ coarrays. */
+
+static void
+generate_coarray_init (gfc_namespace * ns __attribute((unused)))
+{
+ tree fndecl, tmp, decl, save_fn_decl;
+
+ save_fn_decl = current_function_decl;
+ push_function_context ();
+
+ tmp = build_function_type_list (void_type_node, NULL_TREE);
+ fndecl = build_decl (input_location, FUNCTION_DECL,
+ create_tmp_var_name ("_caf_init"), tmp);
+
+ DECL_STATIC_CONSTRUCTOR (fndecl) = 1;
+ SET_DECL_INIT_PRIORITY (fndecl, DEFAULT_INIT_PRIORITY);
+
+ decl = build_decl (input_location, RESULT_DECL, NULL_TREE, void_type_node);
+ DECL_ARTIFICIAL (decl) = 1;
+ DECL_IGNORED_P (decl) = 1;
+ DECL_CONTEXT (decl) = fndecl;
+ DECL_RESULT (fndecl) = decl;
+
+ pushdecl (fndecl);
+ current_function_decl = fndecl;
+ announce_function (fndecl);
+
+ rest_of_decl_compilation (fndecl, 0, 0);
+ make_decl_rtl (fndecl);
+ init_function_start (fndecl);
+
+ pushlevel (0);
+ gfc_init_block (&caf_init_block);
+
+ gfc_traverse_ns (ns, generate_coarray_sym_init);
+
+ DECL_SAVED_TREE (fndecl) = gfc_finish_block (&caf_init_block);
+ decl = getdecls ();
+
+ poplevel (1, 0, 1);
+ BLOCK_SUPERCONTEXT (DECL_INITIAL (fndecl)) = fndecl;
+
+ DECL_SAVED_TREE (fndecl)
+ = build3_v (BIND_EXPR, decl, DECL_SAVED_TREE (fndecl),
+ DECL_INITIAL (fndecl));
+ dump_function (TDI_original, fndecl);
+
+ cfun->function_end_locus = input_location;
+ set_cfun (NULL);
+ (void) cgraph_create_node (fndecl);
+ pop_function_context ();
+ current_function_decl = save_fn_decl;
+}
+
+
/* Generate code for a function. */
void
@@ -4897,8 +5041,12 @@ gfc_generate_function_code (gfc_namespace * ns)
nonlocal_dummy_decls = NULL;
nonlocal_dummy_decl_pset = NULL;
+ has_coarray_vars = false;
generate_local_vars (ns);
+ if (gfc_option.coarray == GFC_FCOARRAY_LIB && has_coarray_vars)
+ generate_coarray_init (ns);
+
/* Keep the parent fake result declaration in module functions
or external procedures. */
if ((ns->parent && ns->parent->proc_name->attr.flavor == FL_MODULE)
@@ -5062,9 +5210,13 @@ gfc_generate_function_code (gfc_namespace * ns)
}
current_function_decl = old_context;
- if (decl_function_context (fndecl))
+ if (decl_function_context (fndecl) && !gfc_option.coarray == GFC_FCOARRAY_LIB
+ && has_coarray_vars)
/* Register this function with cgraph just far enough to get it
- added to our parent's nested function list. */
+ added to our parent's nested function list.
+ If there are static coarrays in this function, the nested _caf_init
+ function has already called cgraph_create_node, which also created
+ the cgraph node for this function. */
(void) cgraph_create_node (fndecl);
else
cgraph_finalize_function (fndecl, true);
diff --git a/gcc/fortran/trans-types.c b/gcc/fortran/trans-types.c
index 1165926..9c4f5f6 100644
--- a/gcc/fortran/trans-types.c
+++ b/gcc/fortran/trans-types.c
@@ -1542,13 +1542,13 @@ gfc_get_nodesc_array_type (tree etype, gfc_array_spec * as, gfc_packed packed,
if (as->rank == 0)
{
- if (packed != PACKED_STATIC)
+ if (packed != PACKED_STATIC || gfc_option.coarray == GFC_FCOARRAY_LIB)
type = build_pointer_type (type);
if (restricted)
type = build_qualified_type (type, TYPE_QUAL_RESTRICT);
- if (packed != PACKED_STATIC)
+ if (packed != PACKED_STATIC || gfc_option.coarray == GFC_FCOARRAY_LIB)
{
GFC_ARRAY_TYPE_P (type) = 1;
TYPE_LANG_SPECIFIC (type) = TYPE_LANG_SPECIFIC (TREE_TYPE (type));
@@ -1596,7 +1596,8 @@ gfc_get_nodesc_array_type (tree etype, gfc_array_spec * as, gfc_packed packed,
DECL_ORIGINAL_TYPE (type_decl) = gtype;
}
- if (packed != PACKED_STATIC || !known_stride)
+ if (packed != PACKED_STATIC || !known_stride
+ || (as->corank && gfc_option.coarray == GFC_FCOARRAY_LIB))
{
/* For dummy arrays and automatic (heap allocated) arrays we
want a pointer to the array. */
diff --git a/gcc/fortran/trans.h b/gcc/fortran/trans.h
index 2b06d80..95cd9fb 100644
--- a/gcc/fortran/trans.h
+++ b/gcc/fortran/trans.h
@@ -617,6 +617,7 @@ extern GTY(()) tree gfor_fndecl_associated;
/* Coarray run-time library function decls. */
extern GTY(()) tree gfor_fndecl_caf_init;
extern GTY(()) tree gfor_fndecl_caf_finalize;
+extern GTY(()) tree gfor_fndecl_caf_register;
extern GTY(()) tree gfor_fndecl_caf_critical;
extern GTY(()) tree gfor_fndecl_caf_end_critical;
extern GTY(()) tree gfor_fndecl_caf_sync_all;
@@ -722,6 +723,7 @@ struct GTY((variable_size)) lang_type {
tree span;
tree base_decl[2];
tree nonrestricted_type;
+ tree caf_token;
};
struct GTY((variable_size)) lang_decl {
@@ -766,6 +768,7 @@ struct GTY((variable_size)) lang_decl {
(TYPE_LANG_SPECIFIC(node)->stride[dim])
#define GFC_TYPE_ARRAY_RANK(node) (TYPE_LANG_SPECIFIC(node)->rank)
#define GFC_TYPE_ARRAY_CORANK(node) (TYPE_LANG_SPECIFIC(node)->corank)
+#define GFC_TYPE_ARRAY_CAF_TOKEN(node) (TYPE_LANG_SPECIFIC(node)->caf_token)
#define GFC_TYPE_ARRAY_SIZE(node) (TYPE_LANG_SPECIFIC(node)->size)
#define GFC_TYPE_ARRAY_OFFSET(node) (TYPE_LANG_SPECIFIC(node)->offset)
#define GFC_TYPE_ARRAY_AKIND(node) (TYPE_LANG_SPECIFIC(node)->akind)
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [Patch, Fortran] -fcoarray=lib - add registering calls for nonallocatable coarrays
2011-05-22 19:08 [Patch, Fortran] -fcoarray=lib - add registering calls for nonallocatable coarrays Tobias Burnus
@ 2011-05-25 0:24 ` Tobias Burnus
2011-05-26 9:05 ` Tobias Burnus
0 siblings, 1 reply; 6+ messages in thread
From: Tobias Burnus @ 2011-05-25 0:24 UTC (permalink / raw)
To: gcc patches, gfortran
[-- Attachment #1: Type: text/plain, Size: 3350 bytes --]
Instead of a ping, an updated patch. This one additionally supports
registering of nonallocatable coarrays also in MODULE and in BLOCK plus
a test case.
(Changes to gfc_generate_module_vars and gfc_process_block_locals and
cgraph call in generate_coarray_init; some functions were moved up in
the trans-decl.c file.)
OK for the trunk?
Tobias
On 22 May 2011, Tobias Burnus wrote:
> The following applies to -fcoarray=lib; for -fcoarray=single there
> should be no change.
>
> The coarray communication library needs to know about the coarrays
> even before the function containing them has been invoked. Thus, the
> coarrays (of all translation units) need to be registered at start up.
>
> This patch handles this by creating a _caf_init function with
> constructor attribute, which is nested in the the parent's procedure
> if the latter contains local nonallocatable (and thus: static/SAVE)
> coarrays variables.
>
> At the same time, all (nonallocatable) coarrays have been turned into
> pointers - to allow the communication library to allocate the memory.
> This allows optimizations, e.g., by allocating in memory which is
> available for all images on the same node (cf. MPI_Alloc_mem).
>
> Additionally, a "token" is saved with the coarray, which allows the
> coarray library to identify the coarray. In a simple implementation,
> it could simply use the base_addr of the coarray or enumerate them
> through.
>
>
> Example: The small example program
>
> ------------- < test.f90 >-----------------
> program caf_program
> integer :: a[*] = 7
> a = 8
> end program caf_program
> ------------- </ test.f90 >-----------------
>
> is turned into the following tree (-fdump-tree-original)
>
> ------------- < test.f90.003t.original >-----------------
> _caf_init.1 ()
> {
> a = (integer(kind=4) * restrict) _gfortran_caf_register (4, 0,
> &caf_token.0, 0B, 0B, 0);
> *a = 7;
> }
>
> caf_program ()
> {
> static void * caf_token.0;
> static integer(kind=4) * restrict a;
> void _caf_init.1 (void);
>
> (integer(kind=4)) *a = 8;
> }
>
> main (integer(kind=4) argc, character(kind=1) * * argv)
> {
> static integer(kind=4) options.2[8] = {68, 1023, 0, 0, 1, 1, 0, 1};
>
> _gfortran_caf_init (&argc, &argv, &_gfortran_caf_this_image,
> &_gfortran_caf_num_images);
> _gfortran_set_args (argc, argv);
> _gfortran_set_options (8, &options.2[0]);
> _gfortran_caf_sync_all (0B, 0);
> caf_program ();
> __sync_synchronize ();
> _gfortran_caf_finalize ();
> return 0;
> }
> ------------- </ test.f90.003t.original >-----------------
>
> Note: By construction, _gfortran_caf_register is called before
> _gfortran_caf_init; thus, the MPI library will be initialized by the
> first _gfortran_caf_register call, unless the program does not have
> any nonallocatable coarrays.
>
> No test cases, but the ones in gfortran.dg/coarray/ should already
> test this functionality.
>
> To be done in later patches:
> - Coarrays declared in modules (module variables)
> - Allocatable coarrays
>
> Note: As constructors are never optimized away [unless they are
> pure/const], static coarrays and also uncalled functions containing
> static coarrays will not be optimized away. (Cf. PRs middle-end/49106
> and middle-end/49108.)
>
> Bootstrapped and regtested on x86-64-linux.
> OK for the trunk?
>
> Tobias
[-- Attachment #2: caf_register-v2.diff --]
[-- Type: text/x-patch, Size: 15548 bytes --]
2011-05-24 Tobias Burnus <burnus@net-b.de>
PR fortran/18918
* trans-array.c (gfc_conv_array_ref): Handle pointer coarrays.
* trans-decl.c (has_coarray_vars, caf_init_block,
gfor_fndecl_caf_register): New file-global variables.
(gfc_finish_var_decl): Make sure that coarrays in main are static.
(gfc_build_qualified_array): Generate coarray token variable.
(gfc_get_symbol_decl): Don't use a static initializer for coarrays.
(gfc_build_builtin_function_decls): Set gfor_fndecl_caf_register.
(gfc_trans_deferred_vars, gfc_emit_parameter_debug_info): Skip for
static coarrays.
(generate_local_decl): Check for local coarrays.
(create_main_function): SYNC ALL before calling MAIN.
(generate_coarray_sym_init): Register static coarray.
(generate_coarray_init): Generate CAF registering constructor
function.
(gfc_generate_function_code): Call it, if needed, do not create
cgraph twice.
(gfc_generate_module_vars, gfc_process_block_locals): Call
generate_coarray_init.
* trans-types.c (gfc_get_nodesc_array_type): Generate pointers for
-fcoarray=lib.
* trans.h (gfor_fndecl_caf_register): New variable.
(lang_type): New element caf_token.
(GFC_TYPE_ARRAY_CAF_TOKEN): New macro.
2011-05-22 Tobias Burnus <burnus@net-b.de>
PR fortran/18918
* gfortran.dg/coarray/registering_1.f90: New.
diff --git a/gcc/fortran/trans-array.c b/gcc/fortran/trans-array.c
index 78d65a6..29c7f83 100644
--- a/gcc/fortran/trans-array.c
+++ b/gcc/fortran/trans-array.c
@@ -2623,6 +2623,10 @@ gfc_conv_array_ref (gfc_se * se, gfc_array_ref * ar, gfc_symbol * sym,
if (ar->dimen == 0)
{
gcc_assert (ar->codimen);
+ if (GFC_ARRAY_TYPE_P (TREE_TYPE (se->expr))
+ && TREE_CODE (TREE_TYPE (se->expr)) == POINTER_TYPE)
+ se->expr = build_fold_indirect_ref_loc (input_location, se->expr);
+
/* Use the actual tree type and not the wrapped coarray. */
se->expr = fold_convert (TREE_TYPE (TREE_TYPE (se->expr)), se->expr);
return;
diff --git a/gcc/fortran/trans-decl.c b/gcc/fortran/trans-decl.c
index d771484..299f224 100644
--- a/gcc/fortran/trans-decl.c
+++ b/gcc/fortran/trans-decl.c
@@ -78,6 +78,12 @@ static gfc_namespace *module_namespace;
static gfc_symbol* current_procedure_symbol = NULL;
+/* With -fcoarray=lib: For generating the registering call
+ of static coarrays. */
+static bool has_coarray_vars;
+static stmtblock_t caf_init_block;
+
+
/* List of static constructor functions. */
tree gfc_static_ctors;
@@ -114,6 +120,7 @@ tree gfor_fndecl_associated;
/* Coarray run-time library function decls. */
tree gfor_fndecl_caf_init;
tree gfor_fndecl_caf_finalize;
+tree gfor_fndecl_caf_register;
tree gfor_fndecl_caf_critical;
tree gfor_fndecl_caf_end_critical;
tree gfor_fndecl_caf_sync_all;
@@ -566,7 +573,9 @@ gfc_finish_var_decl (tree decl, gfc_symbol * sym)
SAVE_EXPLICIT. */
if (!sym->attr.use_assoc
&& (sym->attr.save != SAVE_NONE || sym->attr.data
- || (sym->value && sym->ns->proc_name->attr.is_main_program)))
+ || (sym->value && sym->ns->proc_name->attr.is_main_program)
+ || (gfc_option.coarray == GFC_FCOARRAY_LIB
+ && sym->attr.codimension && !sym->attr.allocatable)))
TREE_STATIC (decl) = 1;
if (sym->attr.volatile_)
@@ -745,6 +754,18 @@ gfc_build_qualified_array (tree decl, gfc_symbol * sym)
nest = (procns->proc_name->backend_decl != current_function_decl)
&& !sym->attr.contained;
+ if (sym->attr.codimension && gfc_option.coarray == GFC_FCOARRAY_LIB
+ && GFC_TYPE_ARRAY_CAF_TOKEN (type) == NULL_TREE)
+ {
+ tree token;
+
+ token = gfc_create_var_np (pvoid_type_node, "caf_token");
+ GFC_TYPE_ARRAY_CAF_TOKEN (type) = token;
+ DECL_ARTIFICIAL (token) = 1;
+ TREE_STATIC (token) = 1;
+ gfc_add_decl_to_function (token);
+ }
+
for (dim = 0; dim < GFC_TYPE_ARRAY_RANK (type); dim++)
{
if (GFC_TYPE_ARRAY_LBOUND (type, dim) == NULL_TREE)
@@ -1403,7 +1424,8 @@ gfc_get_symbol_decl (gfc_symbol * sym)
&& !(sym->attr.use_assoc && !intrinsic_array_parameter)
&& (sym->attr.save || sym->ns->proc_name->attr.is_main_program
|| gfc_option.flag_max_stack_var_size == 0
- || sym->attr.data || sym->ns->proc_name->attr.flavor == FL_MODULE))
+ || sym->attr.data || sym->ns->proc_name->attr.flavor == FL_MODULE)
+ && (gfc_option.coarray != GFC_FCOARRAY_LIB || !sym->attr.codimension))
{
/* Add static initializer. For procedures, it is only needed if
SAVE is specified otherwise they need to be reinitialized
@@ -3025,6 +3047,11 @@ gfc_build_builtin_function_decls (void)
gfor_fndecl_caf_finalize = gfc_build_library_function_decl (
get_identifier (PREFIX("caf_finalize")), void_type_node, 0);
+ gfor_fndecl_caf_register = gfc_build_library_function_decl_with_spec (
+ get_identifier (PREFIX("caf_register")), "...WWW", pvoid_type_node, 6,
+ size_type_node, integer_type_node, ppvoid_type_node, pint_type,
+ build_pointer_type (pchar_type_node), integer_type_node);
+
gfor_fndecl_caf_critical = gfc_build_library_function_decl (
get_identifier (PREFIX("caf_critical")), void_type_node, 0);
@@ -3458,7 +3485,7 @@ gfc_trans_deferred_vars (gfc_symbol * proc_sym, gfc_wrapped_block * block)
gfc_trans_deferred_array (sym, block);
}
}
- else
+ else if (gfc_option.coarray != GFC_FCOARRAY_LIB)
{
gfc_save_backend_locus (&loc);
gfc_set_backend_locus (&sym->declared_at);
@@ -3864,6 +3891,10 @@ gfc_create_module_variable (gfc_symbol * sym)
rest_of_decl_compilation (length, 1, 0);
}
}
+
+ if (sym->attr.codimension && !sym->attr.dummy && !sym->attr.allocatable
+ && sym->attr.referenced && !sym->attr.use_assoc)
+ has_coarray_vars = true;
}
/* Emit debug information for USE statements. */
@@ -4066,6 +4097,9 @@ gfc_emit_parameter_debug_info (gfc_symbol *sym)
sym->attr.dimension, false))
return;
+ if (gfc_option.coarray == GFC_FCOARRAY_LIB && sym->attr.codimension)
+ return;
+
/* Create the decl for the variable or constant. */
decl = build_decl (input_location,
sym->attr.flavor == FL_PARAMETER ? CONST_DECL : VAR_DECL,
@@ -4087,6 +4121,120 @@ gfc_emit_parameter_debug_info (gfc_symbol *sym)
debug_hooks->global_decl (decl);
}
+
+static void
+generate_coarray_sym_init (gfc_symbol *sym)
+{
+ tree tmp, size, decl, token;
+
+ if (sym->attr.dummy || sym->attr.allocatable || !sym->attr.codimension
+ || sym->attr.use_assoc || !sym->attr.referenced)
+ return;
+
+ decl = sym->backend_decl;
+ TREE_USED(decl) = 1;
+ gcc_assert (GFC_ARRAY_TYPE_P (TREE_TYPE (decl)));
+
+ /* FIXME: Workaround for PR middle-end/49106, cf. also PR middle-end/49108
+ to make sure the variable is not optimized away. */
+ DECL_PRESERVE_P (DECL_CONTEXT (decl)) = 1;
+
+ size = TYPE_SIZE_UNIT (gfc_get_element_type (TREE_TYPE (decl)));
+
+ if (GFC_TYPE_ARRAY_RANK (TREE_TYPE (decl)))
+ {
+ tmp = GFC_TYPE_ARRAY_SIZE (TREE_TYPE (decl));
+ size = fold_build2_loc (input_location, MULT_EXPR, size_type_node,
+ fold_convert (size_type_node, tmp),
+ fold_convert (size_type_node, size));
+ }
+
+ gcc_assert (GFC_TYPE_ARRAY_CAF_TOKEN (TREE_TYPE (decl)) != NULL_TREE);
+ token = gfc_build_addr_expr (ppvoid_type_node,
+ GFC_TYPE_ARRAY_CAF_TOKEN (TREE_TYPE(decl)));
+
+ tmp = build_call_expr_loc (input_location, gfor_fndecl_caf_register, 6, size,
+ build_int_cst (integer_type_node, 0), /* type. */
+ token, null_pointer_node, /* token, stat. */
+ null_pointer_node, /* errgmsg, errmsg_len. */
+ build_int_cst (integer_type_node, 0));
+
+ gfc_add_modify (&caf_init_block, decl, fold_convert (TREE_TYPE (decl), tmp));
+
+
+ /* Handle "static" initializer. */
+ if (sym->value)
+ {
+ sym->attr.pointer = 1;
+ tmp = gfc_trans_assignment (gfc_lval_expr_from_sym (sym), sym->value,
+ true, false);
+ sym->attr.pointer = 0;
+ gfc_add_expr_to_block (&caf_init_block, tmp);
+ }
+}
+
+
+/* Generate constructor function to initialize static, nonallocatable
+ coarrays. */
+
+static void
+generate_coarray_init (gfc_namespace * ns __attribute((unused)))
+{
+ tree fndecl, tmp, decl, save_fn_decl;
+
+ save_fn_decl = current_function_decl;
+ push_function_context ();
+
+ tmp = build_function_type_list (void_type_node, NULL_TREE);
+ fndecl = build_decl (input_location, FUNCTION_DECL,
+ create_tmp_var_name ("_caf_init"), tmp);
+
+ DECL_STATIC_CONSTRUCTOR (fndecl) = 1;
+ SET_DECL_INIT_PRIORITY (fndecl, DEFAULT_INIT_PRIORITY);
+
+ decl = build_decl (input_location, RESULT_DECL, NULL_TREE, void_type_node);
+ DECL_ARTIFICIAL (decl) = 1;
+ DECL_IGNORED_P (decl) = 1;
+ DECL_CONTEXT (decl) = fndecl;
+ DECL_RESULT (fndecl) = decl;
+
+ pushdecl (fndecl);
+ current_function_decl = fndecl;
+ announce_function (fndecl);
+
+ rest_of_decl_compilation (fndecl, 0, 0);
+ make_decl_rtl (fndecl);
+ init_function_start (fndecl);
+
+ pushlevel (0);
+ gfc_init_block (&caf_init_block);
+
+ gfc_traverse_ns (ns, generate_coarray_sym_init);
+
+ DECL_SAVED_TREE (fndecl) = gfc_finish_block (&caf_init_block);
+ decl = getdecls ();
+
+ poplevel (1, 0, 1);
+ BLOCK_SUPERCONTEXT (DECL_INITIAL (fndecl)) = fndecl;
+
+ DECL_SAVED_TREE (fndecl)
+ = build3_v (BIND_EXPR, decl, DECL_SAVED_TREE (fndecl),
+ DECL_INITIAL (fndecl));
+ dump_function (TDI_original, fndecl);
+
+ cfun->function_end_locus = input_location;
+ set_cfun (NULL);
+
+ if (decl_function_context (fndecl))
+ (void) cgraph_create_node (fndecl);
+ else
+ cgraph_finalize_function (fndecl, true);
+
+ pop_function_context ();
+ current_function_decl = save_fn_decl;
+}
+
+
/* Generate all the required code for module variables. */
void
@@ -4101,9 +4249,14 @@ gfc_generate_module_vars (gfc_namespace * ns)
/* Generate COMMON blocks. */
gfc_trans_common (ns);
+ has_coarray_vars = false;
+
/* Create decls for all the module variables. */
gfc_traverse_ns (ns, gfc_create_module_variable);
+ if (gfc_option.coarray == GFC_FCOARRAY_LIB && has_coarray_vars)
+ generate_coarray_init (ns);
+
cur_module = NULL;
gfc_trans_use_stmts (ns);
@@ -4200,6 +4353,10 @@ generate_local_decl (gfc_symbol * sym)
{
if (sym->attr.flavor == FL_VARIABLE)
{
+ if (sym->attr.codimension && !sym->attr.dummy && !sym->attr.allocatable
+ && sym->attr.referenced && !sym->attr.use_assoc)
+ has_coarray_vars = true;
+
if (!sym->attr.dummy && !sym->ns->proc_name->attr.entry_master)
generate_dependency_declarations (sym);
@@ -4897,8 +5054,12 @@ gfc_generate_function_code (gfc_namespace * ns)
nonlocal_dummy_decls = NULL;
nonlocal_dummy_decl_pset = NULL;
+ has_coarray_vars = false;
generate_local_vars (ns);
+ if (gfc_option.coarray == GFC_FCOARRAY_LIB && has_coarray_vars)
+ generate_coarray_init (ns);
+
/* Keep the parent fake result declaration in module functions
or external procedures. */
if ((ns->parent && ns->parent->proc_name->attr.flavor == FL_MODULE)
@@ -5062,9 +5223,13 @@ gfc_generate_function_code (gfc_namespace * ns)
}
current_function_decl = old_context;
- if (decl_function_context (fndecl))
+ if (decl_function_context (fndecl) && !gfc_option.coarray == GFC_FCOARRAY_LIB
+ && has_coarray_vars)
/* Register this function with cgraph just far enough to get it
- added to our parent's nested function list. */
+ added to our parent's nested function list.
+ If there are static coarrays in this function, the nested _caf_init
+ function has already called cgraph_create_node, which also created
+ the cgraph node for this function. */
(void) cgraph_create_node (fndecl);
else
cgraph_finalize_function (fndecl, true);
@@ -5190,8 +5355,13 @@ gfc_process_block_locals (gfc_namespace* ns)
tree decl;
gcc_assert (saved_local_decls == NULL_TREE);
+ has_coarray_vars = false;
+
generate_local_vars (ns);
+ if (gfc_option.coarray == GFC_FCOARRAY_LIB && has_coarray_vars)
+ generate_coarray_init (ns);
+
decl = saved_local_decls;
while (decl)
{
diff --git a/gcc/fortran/trans-types.c b/gcc/fortran/trans-types.c
index 1165926..9c4f5f6 100644
--- a/gcc/fortran/trans-types.c
+++ b/gcc/fortran/trans-types.c
@@ -1542,13 +1542,13 @@ gfc_get_nodesc_array_type (tree etype, gfc_array_spec * as, gfc_packed packed,
if (as->rank == 0)
{
- if (packed != PACKED_STATIC)
+ if (packed != PACKED_STATIC || gfc_option.coarray == GFC_FCOARRAY_LIB)
type = build_pointer_type (type);
if (restricted)
type = build_qualified_type (type, TYPE_QUAL_RESTRICT);
- if (packed != PACKED_STATIC)
+ if (packed != PACKED_STATIC || gfc_option.coarray == GFC_FCOARRAY_LIB)
{
GFC_ARRAY_TYPE_P (type) = 1;
TYPE_LANG_SPECIFIC (type) = TYPE_LANG_SPECIFIC (TREE_TYPE (type));
@@ -1596,7 +1596,8 @@ gfc_get_nodesc_array_type (tree etype, gfc_array_spec * as, gfc_packed packed,
DECL_ORIGINAL_TYPE (type_decl) = gtype;
}
- if (packed != PACKED_STATIC || !known_stride)
+ if (packed != PACKED_STATIC || !known_stride
+ || (as->corank && gfc_option.coarray == GFC_FCOARRAY_LIB))
{
/* For dummy arrays and automatic (heap allocated) arrays we
want a pointer to the array. */
diff --git a/gcc/fortran/trans.h b/gcc/fortran/trans.h
index 2b06d80..95cd9fb 100644
--- a/gcc/fortran/trans.h
+++ b/gcc/fortran/trans.h
@@ -617,6 +617,7 @@ extern GTY(()) tree gfor_fndecl_associated;
/* Coarray run-time library function decls. */
extern GTY(()) tree gfor_fndecl_caf_init;
extern GTY(()) tree gfor_fndecl_caf_finalize;
+extern GTY(()) tree gfor_fndecl_caf_register;
extern GTY(()) tree gfor_fndecl_caf_critical;
extern GTY(()) tree gfor_fndecl_caf_end_critical;
extern GTY(()) tree gfor_fndecl_caf_sync_all;
@@ -722,6 +723,7 @@ struct GTY((variable_size)) lang_type {
tree span;
tree base_decl[2];
tree nonrestricted_type;
+ tree caf_token;
};
struct GTY((variable_size)) lang_decl {
@@ -766,6 +768,7 @@ struct GTY((variable_size)) lang_decl {
(TYPE_LANG_SPECIFIC(node)->stride[dim])
#define GFC_TYPE_ARRAY_RANK(node) (TYPE_LANG_SPECIFIC(node)->rank)
#define GFC_TYPE_ARRAY_CORANK(node) (TYPE_LANG_SPECIFIC(node)->corank)
+#define GFC_TYPE_ARRAY_CAF_TOKEN(node) (TYPE_LANG_SPECIFIC(node)->caf_token)
#define GFC_TYPE_ARRAY_SIZE(node) (TYPE_LANG_SPECIFIC(node)->size)
#define GFC_TYPE_ARRAY_OFFSET(node) (TYPE_LANG_SPECIFIC(node)->offset)
#define GFC_TYPE_ARRAY_AKIND(node) (TYPE_LANG_SPECIFIC(node)->akind)
--- /dev/null 2011-05-24 21:36:28.023892895 +0200
+++ gcc/gcc/testsuite/gfortran.dg/coarray/registering_1.f90 2011-05-24 23:46:25.000000000 +0200
@@ -0,0 +1,41 @@
+! { dg-do run }
+!
+! PR fortran/18918
+!
+! Check whether registering coarrays works
+!
+module m
+ integer :: a(1)[*] = 7
+end module m
+
+use m
+if (any (a /= 7)) call abort()
+a = 88
+if (any (a /= 88)) call abort()
+
+ block
+ integer :: b[*] = 8494
+ if (b /= 8494) call abort()
+ end block
+
+if (any (a /= 88)) call abort()
+call test ()
+end
+
+subroutine test()
+ complex :: z = (1,1)
+ if (z /= (1,1)) call abort()
+ call sub1()
+contains
+ subroutine sub1
+ real :: r = -1
+ if (r /= -1) call abort
+ r = 10
+ if (r /= 10) call abort
+ end subroutine sub1
+
+ subroutine uncalled()
+ integer :: not_refed = 784
+ if (not_refed /= 784) call abort()
+ end subroutine uncalled
+end subroutine test
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [Patch, Fortran] -fcoarray=lib - add registering calls for nonallocatable coarrays
2011-05-25 0:24 ` Tobias Burnus
@ 2011-05-26 9:05 ` Tobias Burnus
2011-05-26 13:41 ` Paul Richard Thomas
0 siblings, 1 reply; 6+ messages in thread
From: Tobias Burnus @ 2011-05-26 9:05 UTC (permalink / raw)
To: gcc patches, gfortran
ping**0.3
http://gcc.gnu.org/ml/fortran/2011-05/msg00176.html
Tobias Burnus wrote:
> Instead of a ping, an updated patch. This one additionally supports
> registering of nonallocatable coarrays also in MODULE and in BLOCK
> plus a test case.
>
> (Changes to gfc_generate_module_vars and gfc_process_block_locals and
> cgraph call in generate_coarray_init; some functions were moved up in
> the trans-decl.c file.)
>
> OK for the trunk?
>
> Tobias
>
> On 22 May 2011, Tobias Burnus wrote:
>> The following applies to -fcoarray=lib; for -fcoarray=single there
>> should be no change.
>>
>> The coarray communication library needs to know about the coarrays
>> even before the function containing them has been invoked. Thus, the
>> coarrays (of all translation units) need to be registered at start up.
>>
>> This patch handles this by creating a _caf_init function with
>> constructor attribute, which is nested in the the parent's procedure
>> if the latter contains local nonallocatable (and thus: static/SAVE)
>> coarrays variables.
>>
>> At the same time, all (nonallocatable) coarrays have been turned into
>> pointers - to allow the communication library to allocate the memory.
>> This allows optimizations, e.g., by allocating in memory which is
>> available for all images on the same node (cf. MPI_Alloc_mem).
>>
>> Additionally, a "token" is saved with the coarray, which allows the
>> coarray library to identify the coarray. In a simple implementation,
>> it could simply use the base_addr of the coarray or enumerate them
>> through.
>>
>>
>> Example: The small example program
>>
>> ------------- < test.f90 >-----------------
>> program caf_program
>> integer :: a[*] = 7
>> a = 8
>> end program caf_program
>> ------------- </ test.f90 >-----------------
>>
>> is turned into the following tree (-fdump-tree-original)
>>
>> ------------- < test.f90.003t.original >-----------------
>> _caf_init.1 ()
>> {
>> a = (integer(kind=4) * restrict) _gfortran_caf_register (4, 0,
>> &caf_token.0, 0B, 0B, 0);
>> *a = 7;
>> }
>>
>> caf_program ()
>> {
>> static void * caf_token.0;
>> static integer(kind=4) * restrict a;
>> void _caf_init.1 (void);
>>
>> (integer(kind=4)) *a = 8;
>> }
>>
>> main (integer(kind=4) argc, character(kind=1) * * argv)
>> {
>> static integer(kind=4) options.2[8] = {68, 1023, 0, 0, 1, 1, 0, 1};
>>
>> _gfortran_caf_init (&argc, &argv, &_gfortran_caf_this_image,
>> &_gfortran_caf_num_images);
>> _gfortran_set_args (argc, argv);
>> _gfortran_set_options (8, &options.2[0]);
>> _gfortran_caf_sync_all (0B, 0);
>> caf_program ();
>> __sync_synchronize ();
>> _gfortran_caf_finalize ();
>> return 0;
>> }
>> ------------- </ test.f90.003t.original >-----------------
>>
>> Note: By construction, _gfortran_caf_register is called before
>> _gfortran_caf_init; thus, the MPI library will be initialized by the
>> first _gfortran_caf_register call, unless the program does not have
>> any nonallocatable coarrays.
>>
>> No test cases, but the ones in gfortran.dg/coarray/ should already
>> test this functionality.
>>
>> To be done in later patches:
>> - Coarrays declared in modules (module variables)
>> - Allocatable coarrays
>>
>> Note: As constructors are never optimized away [unless they are
>> pure/const], static coarrays and also uncalled functions containing
>> static coarrays will not be optimized away. (Cf. PRs middle-end/49106
>> and middle-end/49108.)
>>
>> Bootstrapped and regtested on x86-64-linux.
>> OK for the trunk?
>>
>> Tobias
>
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [Patch, Fortran] -fcoarray=lib - add registering calls for nonallocatable coarrays
2011-05-26 9:05 ` Tobias Burnus
@ 2011-05-26 13:41 ` Paul Richard Thomas
0 siblings, 0 replies; 6+ messages in thread
From: Paul Richard Thomas @ 2011-05-26 13:41 UTC (permalink / raw)
To: Tobias Burnus; +Cc: gcc patches, gfortran
Dear Tobias,
This looks fine to me. It does the things that you described and is
well hidden behind the co-array associated conditions. Thus it is OK
for trunk.
Maybe I am being stupid but what is the call, in the testcase, to
subroutine test for?
Cheers
Paul
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [Patch, Fortran] -fcoarray=lib - add registering calls for nonallocatable coarrays
2011-05-26 15:14 Tobias Burnus
@ 2011-05-26 19:19 ` Paul Richard Thomas
0 siblings, 0 replies; 6+ messages in thread
From: Paul Richard Thomas @ 2011-05-26 19:19 UTC (permalink / raw)
To: Tobias Burnus; +Cc: gcc-patches, fortran
> However, I forgot the [*] (or [3,*] or ...). Fortunately, you
> have spotted the sematically relevant typo!
>
;-)
Paul
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [Patch, Fortran] -fcoarray=lib - add registering calls for nonallocatable coarrays
@ 2011-05-26 15:14 Tobias Burnus
2011-05-26 19:19 ` Paul Richard Thomas
0 siblings, 1 reply; 6+ messages in thread
From: Tobias Burnus @ 2011-05-26 15:14 UTC (permalink / raw)
To: gcc-patches, fortran, Paul Richard Thomas
Dear Paul,
thanks for the review. Regarding:
Paul Thomas wrote:
> Maybe I am being stupid but what is the call, in the
> testcase, to subroutine test for?
Well, it is supposed to test coarray decls in functions,
contained functions, and in not-referenced functions.
However, I forgot the [*] (or [3,*] or ...). Fortunately, you
have spotted the sematically relevant typo!
Tobias
^ permalink raw reply [flat|nested] 6+ messages in thread
end of thread, other threads:[~2011-05-26 18:24 UTC | newest]
Thread overview: 6+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2011-05-22 19:08 [Patch, Fortran] -fcoarray=lib - add registering calls for nonallocatable coarrays Tobias Burnus
2011-05-25 0:24 ` Tobias Burnus
2011-05-26 9:05 ` Tobias Burnus
2011-05-26 13:41 ` Paul Richard Thomas
2011-05-26 15:14 Tobias Burnus
2011-05-26 19:19 ` Paul Richard Thomas
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).