2010-10-05 Antoniu Pop <antoniu.pop@gmail.com>

Merge diffs r32779:34430 from INRIA local svn to omp-stream branch
base r159266.

libgomp/
	This merge introduces a stream-communication layer to the GOMP
	runtime.

gcc/
	Code generation for an OpenMP streaming extension.




git-svn-id: svn://gcc.gnu.org/svn/gcc/branches/omp-stream@164990 138bc75d-0d04-0410-961f-82ee72b054a4
This commit is contained in:
apop 2010-10-05 12:58:55 +00:00
parent 5c1fb0cf09
commit 48de164d08
21 changed files with 3284 additions and 8 deletions

206
gcc/ChangeLog.omp-stream Normal file
View File

@ -0,0 +1,206 @@
2010-10-04 Cupertino Miranda <cupertinomiranda@gmail.com>
* omp-low.c: Debugging
(convert_view_var_array): Perform a type cast for the case where an
address of ARRAY_REF is performed. Cast is done for the expected type
of the current node.
(expand_view_traverser_callback): Corrected code for cases where an
assign statement that has two memory operands.
2010-10-04 Cupertino Miranda <cupertinomiranda@gmail.com>
* omp-low.c: Debugging and cleanup
(_lookup_stream): Removed stream type checking to start treat every
stream var in the same fashion.
(TRAVERSE_VIEWS_IN_REGION): Check htab before doing the traversal.
(traverse_views_in_region_and_subs): Check region->view_pointers before
traverse it.
(compute_data_position): Rename variables. Enabled to pass NULL index
to make it further reusable.
(convert_view_var_array_struct): Added assign_to_var_if_has_parent.
(convert_view_var_array): Updated way to perform convertion. Convertion
is only executed for ARRAY elements. Created checks to validate if
recursive callers should do the convertion or simply ignore. The
remaining expansions are performed by the caller function.
(expand_view_traverser_callback_data): Removed unused nr_elements.
(expand_view_traverser_callback): Moved sync_index increment to after
commit / release. Created condition to either call
convert_view_var_array (for an ARRAY element, substituting it by direct
buffer accesses) or perform the expansion in this function by adding
either and read / write to the buffer after / before an update / commit
respectively.
(register_views_traverser_callback): Change initial assign to
sync_index to view_horizon instead of 0.
(expand_task_streaming_extensions): Removed assign to nr_elements
remove from the structure. Added gsi_inserts for write_stmts and
read_stmts elements.
(stream_create_calls): Changed created variables from size_type_node to
long_long_unsigned_type_node.
(expand_push_and_pop_stubs): Removed un-used nr_elements local
variable.
(expand_omp_single): Removed a condition that was miss protecting some
code that was producing bad builtin calls when master had no shared
stream with child tasks.
(retrieve_streams_info): Changed var from size_type_node to
long_long_unsigned_type_node.
2010-09-28 Antoniu Pop <antoniu.pop@gmail.com>
* omp-low.c: Debugging and cleanup.
(retrieve_streams_info): Removed unguarded call to
OMP_CLAUSE_STREAM_ID. This macro can only be called on
OMP_CLAUSE_INPUT and OMP_CLAUSE_OUTPUT.
(list_bbs_in_sese): Renamed variable NEW to avoid compilation
warnings and potential surprises.
(lookup_stream, compute_data_position): Changed type of
BUFFER_MASK to be consistent. As we use unsigned_long_long for
indexes and horizons, this should be used everywhere we interact
with stream indexes.
(convert_view_var_array): Handle cases where the use of a
dereference is not acceptable in gimple. This includes among
others, binary RHS in assignment, non-register LHS, statements
with no memory operands.
2010-07-27 Cupertino Miranda <cupertinomiranda@gmail.com>
* omp-low.c: Updated code to new streaming syntax.
(regions_streamization_info): Added outer_check, outer_first,
sese_entry, sese_exit;
(stream, _lookup_stream): Added buffer_type, buffer_mask,
element_number. Removed element_size and data. Initializations within
_lookup_stream. Added logic to identify type of elements in stream
depending if stream var is simple type or an array. Should be changed
later.
(view): Added sync_index, buffer_pointer, view_var, burst, view_horizon,
expanded_push_pop and info.
(prepare_inner_context_for_streaming): Adapted to supported newly
expansion correctly updateing elements in regions_streamization_info.
(compute_data_position): Added function to simplify expansion to buffer
positions by index.
(create_data_pointer): Removed
(is_same_expression): Added function to identify similar tree node
expressions. Used to compare with operands used in code to substitute
the view_var by a direct buffer access.
(convert_view_var_array_struct, convert_view_var_array): Strucutre and
function traverser callback to convert the view_vars in direct buffer
accesses. Uses is_same_expression function to compare tree expressions.
(list_bbs_in_sese): Function to create a list of BBS inside of a SESE
region. We use it to identify which BBS we should traverse to
substitute all view_var references by buffer acceses.
(convert_view_var_array_traverser): Function to traverse SESE
and substitute all the references of view_var by the respective buffer
pointer. It is a callback function but is not used as such.
(expand_view_traverser_callback): Changed how the expansion is
performed. Mainly, created different index variables, view_vars are
converted here by calls to convert_view_var_array_traverser instead of
the previous copy or memcpy that was done before.
(register_views_traverser_callback): Initialize newly introduced index
vars.
(expand_task_streaming_extensions): Adapted to reflect new syntax /
expansion.
(expand_push_and_pop_stubs): Updated to reflect new expansion. More
respectively, create stall / release statements before single regions.
(expand_omp_single): Setup SESE BBS nodes in stramization_info, both
task and single regions.
(retrieve_streams_info): Initialize new view structure elements.
* gimplify.c: Updated set default cluase for view var.
(gimplify_scan_omp_clauses): Added view var as local when omp a new
syntax input / output clause is used.
* c-parser.c: Added support for new input / output clause clauses.
(c_parser_omp_stream_identifier, (c_parser_omp_stream_clause): New
parsing function.
(c_parser_omp_clause_input, c_parser_omp_clause_output): Updated.
2010-07-22 Cupertino Miranda <cupertinomiranda@gmail.com>
* omp-low.c: Clearly commented code.
Renamed stream_task to regions_streamization_info
Renamed create_synchronization to expand_view_traverser_callback
(stream, _lookup_stream): Added access_type, element_size, element_type
to stream structure. Initialized those in _lookup_stream.
(prepare_inner_context_for_streaming): Updated comments. Removed
repeated split_edge call for outer_latch. Removed call to remove edge.
(create_data_pointer): Changed way to obtain stream elements size.
(expand_view_traverser_callback): In case elements being accessed in
view are typed ARRAY_DECL then the data in it is fully copied to and
from the buffer with a MEMCPY built in.
(lower_copyprivate_clauses): Removed call to build_fold_addr_expr_loc.
Removed a couple of redundant calls to cleanup_tree_cfg.
2010-07-20 Antoniu Pop <antoniu.pop@gmail.com>
* omp-low.c (create_task_copyfn): Added cases for OMP_CLAUSE_INPUT
and OMP_CLAUSE_OUTPUT to create the proper copy-in code for the
marshalling function.
2010-07-09 Cupertino Miranda <cupertinomiranda@gmail.com>
* omp-low.c (clause_to_var_struct, hash_clause_to_var,
eq_clause_to_var, lookup_var_for_clause): New structure,
hash table and the accessor functions.
2010-07-06 Cupertino Miranda <cupertinomiranda@gmail.com>
* omp-low.c (stream_task, get_streamization_info_for_region):
Structure and creator/accessor functions streamization
information used through code expnsion.
(stream, htab_stream, hash_stream, eq_stream, lookup_stream,
_lookup_stream): New structure, hash table and the accessor
functions.
(view, hash_view, eq_view, alloc_view, _lookup_view,
lookup_view, maybe_lookup_view): New structure, hash table
and the accessor functions.
(stmt_location, stmt_loc, htab_stmt_loc, hash_stmt_loc,
eq_stmt_loc, get_stmt_loc, lookup_stmt_loc, set_stmt_loc,
set_stmt_loc_if_none): New structure, hash table and the
accessor functions.
(TRAVERSE_VIEWS_IN_REGION_AND_SUBS, TRAVERSE_VIEWS_IN_REGION,
GET_VIEW_FOR_STREAM_WITH_POINTER): New macros
(scan_sharing_clauses, lower_rec_input_clauses, expand_omp_taskreg,
lower_send_clauses, expand_omp_single, execute_expand_omp,
lower_omp_taskreg, execute_lower_omp):
Implement streamization of INPUT/OUTPUT clauses.
* c-parser.c (c_parser_omp_clause_name, c_parser_omp_all_clauses,
OMP_TASK_CLAUSE_MASK): Added OMP_CLAUSE_INPUT and
OMP_CLAUSE_OUTPUT cases.
(c_parser_omp_clause_input, c_parser_omp_clause_output): New.
* tree-flow.h (omp_region): Added streamization_init_bb and
streamization_exit_bb fields.
* c-pragma.h (pragma_omp_clause): Add OMP_CLAUSE_INPUT
OMP_CLAUSE_OUTPUT clauses.
* c-typeck.c (c_finish_omp_clauses): Added OMP_CLAUSE_INPUT and
OMP_CLAUSE_OUTPUT cases.
* gimplify.c (gimplify_scan_omp_clauses,
gimplify_adjust_omp_clauses): Added OMP_CLAUSE_INPUT and
OMP_CLAUSE_OUTPUT cases.
* tree.c (omp_clause_num_ops, omp_clause_code_name, walk_tree_1):
Add and handle OMP_CLAUSE_INPUT and OMP_CLAUSE_OUTPUT cases.
* tree.h (omp_clause_code): Add OMP_CLAUSE_INPUT
OMP_CLAUSE_OUTPUT clauses.
* tree-pretty-print.c (dump_omp_clause): Added OMP_CLAUSE_INPUT
and OMP_CLAUSE_OUTPUT cases.
2010-07-01 Antoniu Pop <antoniu.pop@gmail.com>
* builtin-types.def (BT_FN_ULL_PTR_ULL, BT_FN_VOID_PTR_ULL)
(BT_FN_PTR_SIZE_ULL_PTR, BT_FN_VOID_PTR_INT_INT_INT): New builtin
types for the GOMP stream runtime.
* omp-builtins.def (BUILT_IN_GOMP_STREAM_CREATE_STREAM)
(BUILT_IN_GOMP_STREAM_CREATE_READ_VIEW)
(BUILT_IN_GOMP_STREAM_CREATE_WRITE_VIEW)
(BUILT_IN_GOMP_STREAM_CREATE_TASK)
(BUILT_IN_GOMP_STREAM_ADD_EXPECTED_VIEWS)
(BUILT_IN_GOMP_STREAM_CONNECT_VIEW)
(BUILT_IN_GOMP_STREAM_WAIT_UNTIL_CONNECTED)
(BUILT_IN_GOMP_STREAM_UPDATE, BUILT_IN_GOMP_STREAM_STALL)
(BUILT_IN_GOMP_STREAM_RELEASE, BUILT_IN_GOMP_STREAM_COMMIT)
(BUILT_IN_GOMP_STREAM_TASK_EXIT): New builtin functions of the
GOMP stream runtime.
2010-06-30 Cupertino Miranda <cupertinomiranda@gmail.com>
* Branch from mainline (r158338).

View File

@ -218,6 +218,7 @@ DEF_FUNCTION_TYPE_1 (BT_FN_ULONG_ULONG, BT_ULONG, BT_ULONG)
DEF_FUNCTION_TYPE_1 (BT_FN_ULONGLONG_ULONGLONG, BT_ULONGLONG, BT_ULONGLONG)
DEF_FUNCTION_TYPE_1 (BT_FN_UINT32_UINT32, BT_UINT32, BT_UINT32)
DEF_FUNCTION_TYPE_1 (BT_FN_UINT64_UINT64, BT_UINT64, BT_UINT64)
DEF_FUNCTION_TYPE_1 (BT_FN_PTR_INT, BT_PTR, BT_INT)
DEF_POINTER_TYPE (BT_PTR_FN_VOID_PTR, BT_FN_VOID_PTR)
@ -313,6 +314,10 @@ DEF_FUNCTION_TYPE_2 (BT_FN_BOOL_LONGPTR_LONGPTR,
BT_BOOL, BT_PTR_LONG, BT_PTR_LONG)
DEF_FUNCTION_TYPE_2 (BT_FN_BOOL_ULONGLONGPTR_ULONGLONGPTR,
BT_BOOL, BT_PTR_ULONGLONG, BT_PTR_ULONGLONG)
DEF_FUNCTION_TYPE_2 (BT_FN_ULL_PTR_ULL,
BT_ULONGLONG, BT_PTR, BT_ULONGLONG)
DEF_FUNCTION_TYPE_2 (BT_FN_VOID_PTR_ULL,
BT_VOID, BT_PTR, BT_ULONGLONG)
DEF_POINTER_TYPE (BT_PTR_FN_VOID_PTR_PTR, BT_FN_VOID_PTR_PTR)
@ -381,6 +386,8 @@ DEF_FUNCTION_TYPE_3 (BT_FN_VOID_OMPFN_PTR_UINT, BT_VOID, BT_PTR_FN_VOID_PTR,
BT_PTR, BT_UINT)
DEF_FUNCTION_TYPE_3 (BT_FN_PTR_CONST_PTR_INT_SIZE, BT_PTR,
BT_CONST_PTR, BT_INT, BT_SIZE)
DEF_FUNCTION_TYPE_3 (BT_FN_PTR_SIZE_ULL_PTR,
BT_PTR, BT_SIZE, BT_ULONGLONG, BT_PTR)
DEF_FUNCTION_TYPE_4 (BT_FN_SIZE_CONST_PTR_SIZE_SIZE_FILEPTR,
BT_SIZE, BT_CONST_PTR, BT_SIZE, BT_SIZE, BT_FILEPTR)
@ -400,6 +407,8 @@ DEF_FUNCTION_TYPE_4 (BT_FN_VOID_OMPFN_PTR_UINT_UINT,
BT_VOID, BT_PTR_FN_VOID_PTR, BT_PTR, BT_UINT, BT_UINT)
DEF_FUNCTION_TYPE_4 (BT_FN_VOID_PTR_WORD_WORD_PTR,
BT_VOID, BT_PTR, BT_WORD, BT_WORD, BT_PTR)
DEF_FUNCTION_TYPE_4 (BT_FN_VOID_PTR_INT_INT_INT,
BT_VOID, BT_PTR, BT_INT, BT_INT, BT_INT)
DEF_FUNCTION_TYPE_5 (BT_FN_INT_STRING_INT_SIZE_CONST_STRING_VALIST_ARG,
BT_INT, BT_STRING, BT_INT, BT_SIZE, BT_CONST_STRING,

View File

@ -7156,6 +7156,10 @@ c_parser_omp_clause_name (c_parser *parser)
if (!strcmp ("firstprivate", p))
result = PRAGMA_OMP_CLAUSE_FIRSTPRIVATE;
break;
case 'i':
if (!strcmp ("input", p))
result = PRAGMA_OMP_CLAUSE_INPUT;
break;
case 'l':
if (!strcmp ("lastprivate", p))
result = PRAGMA_OMP_CLAUSE_LASTPRIVATE;
@ -7169,6 +7173,8 @@ c_parser_omp_clause_name (c_parser *parser)
case 'o':
if (!strcmp ("ordered", p))
result = PRAGMA_OMP_CLAUSE_ORDERED;
else if (!strcmp ("output", p))
result = PRAGMA_OMP_CLAUSE_OUTPUT;
break;
case 'p':
if (!strcmp ("private", p))
@ -7267,6 +7273,157 @@ c_parser_omp_variable_list (c_parser *parser,
return list;
}
/* OpenMP X.X:
stream-list:
identifier ************************
variable-list , identifier
KIND must be OMP_CLAUSE_INPUT or OMP_CLAUSE_OUTPUT. */
static bool
c_parser_omp_stream_identifier (c_parser *parser, location_t loc,
tree *id, tree *sub)
{
if (c_parser_next_token_is_not (parser, CPP_NAME)
|| c_parser_peek_token (parser)->id_kind != C_ID_ID)
c_parser_error (parser, "expected stream or view identifier");
*id = lookup_name (c_parser_peek_token (parser)->value);
if (*id == NULL_TREE)
{
inform (loc, "OpenMP stream and view identifiers must"
" be declared before use in streaming clauses.");
undeclared_variable (c_parser_peek_token (parser)->location,
c_parser_peek_token (parser)->value);
return false;
}
if (*id == error_mark_node)
return false;
c_parser_consume_token (parser);
/* If this is an array reference. */
if (c_parser_next_token_is (parser, CPP_OPEN_SQUARE))
{
c_parser_consume_token (parser);
*sub = c_parser_expression (parser).value;
c_parser_skip_until_found (parser, CPP_CLOSE_SQUARE,
"expected %<]%>");
}
else
*sub = NULL_TREE;
if (c_parser_next_token_is (parser, CPP_OPEN_SQUARE))
{
c_parser_error (parser, "single dimension arrays"
" supported only in streaming clauses");
return false;
}
/* Next, we must either connect a view or have another stream use
separated by a comma, or the closing parenthesis. This test
prevents all other syntaxes that will be supported later (like
dot or deref ...) */
if (c_parser_next_token_is_not (parser, CPP_LSHIFT)
&& c_parser_next_token_is_not (parser, CPP_RSHIFT)
&& c_parser_next_token_is_not (parser, CPP_CLOSE_PAREN)
&& c_parser_next_token_is_not (parser, CPP_COMMA))
{
c_parser_error (parser, "wrong syntax on streaming clause");
return false;
}
return true;
}
static tree
c_parser_omp_stream_clause (c_parser *parser,
enum omp_clause_code kind,
tree list)
{
/* The clause's location. */
location_t clause_loc = c_parser_peek_token (parser)->location;
gcc_assert (kind == OMP_CLAUSE_INPUT || kind == OMP_CLAUSE_OUTPUT);
if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>"))
return list;
/* Every stream clause must start with either a stream identifier or
a view identifier. */
while (true)
{
tree stream_id, stream_idx, view_id, view_idx;
tree omp_clause;
if (!c_parser_omp_stream_identifier (parser, clause_loc,
&stream_id, &stream_idx))
break;
omp_clause = build_omp_clause (clause_loc, kind);
OMP_CLAUSE_STREAM_ID (omp_clause) = stream_id;
OMP_CLAUSE_STREAM_SUB (omp_clause) = stream_idx;
if (c_parser_next_token_is (parser, CPP_LSHIFT)
|| c_parser_next_token_is (parser, CPP_RSHIFT))
{
bool lshift_stream_operator_p =
c_parser_next_token_is (parser, CPP_LSHIFT);
c_parser_consume_token (parser);
if (!c_parser_omp_stream_identifier (parser, clause_loc,
&view_id, &view_idx))
break;
/* If the clause is reversed ("view << >> stream" instead of
"stream << >> view"), swap the roles. */
if ((kind == OMP_CLAUSE_INPUT && lshift_stream_operator_p)
|| (kind == OMP_CLAUSE_OUTPUT && !lshift_stream_operator_p))
{
OMP_CLAUSE_STREAM_ID (omp_clause) = view_id;
view_id = stream_id;
OMP_CLAUSE_STREAM_SUB (omp_clause) = view_idx;
view_idx = stream_idx;
}
OMP_CLAUSE_VIEW_ID (omp_clause) = view_id;
OMP_CLAUSE_BURST_SIZE (omp_clause) = view_idx;
}
else
{
OMP_CLAUSE_VIEW_ID (omp_clause) = NULL_TREE;
OMP_CLAUSE_BURST_SIZE (omp_clause) = NULL_TREE;
}
OMP_CLAUSE_CHAIN (omp_clause) = list;
list = omp_clause;
// TODO: TINO Check this
//if(OMP_CLAUSE_VIEW_ID (omp_clause) != NULL_TREE)
//{
// tree new_omp_clause = build_omp_clause (clause_loc, OMP_CLAUSE_PRIVATE);
// OMP_CLAUSE_DECL (new_omp_clause) = OMP_CLAUSE_VIEW_ID (omp_clause);
// OMP_CLAUSE_CHAIN (new_omp_clause) = list;
// list = new_omp_clause;
//}
if (c_parser_next_token_is (parser, CPP_COMMA))
c_parser_consume_token (parser);
else if (c_parser_next_token_is (parser, CPP_CLOSE_PAREN))
break;
else
{
c_parser_error (parser, "expected %<,%> or %<)%>");
break;
}
}
c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>");
return list;
}
/* Similarly, but expect leading and trailing parenthesis. This is a very
common case for omp clauses. */
@ -7426,6 +7583,15 @@ c_parser_omp_clause_if (c_parser *parser, tree list)
return list;
}
/* OpenMP stream extension:
input ( variable-list ) */
static tree
c_parser_omp_clause_input (c_parser *parser, tree list)
{
return c_parser_omp_stream_clause (parser, OMP_CLAUSE_INPUT, list);
}
/* OpenMP 2.5:
lastprivate ( variable-list ) */
@ -7512,6 +7678,15 @@ c_parser_omp_clause_ordered (c_parser *parser, tree list)
return c;
}
/* OpenMP stream extension:
output ( variable-list ) */
static tree
c_parser_omp_clause_output (c_parser *parser, tree list)
{
return c_parser_omp_stream_clause (parser, OMP_CLAUSE_OUTPUT, list);
}
/* OpenMP 2.5:
private ( variable-list ) */
@ -7756,6 +7931,10 @@ c_parser_omp_all_clauses (c_parser *parser, unsigned int mask,
clauses = c_parser_omp_clause_if (parser, clauses);
c_name = "if";
break;
case PRAGMA_OMP_CLAUSE_INPUT:
clauses = c_parser_omp_clause_input (parser, clauses);
c_name = "input";
break;
case PRAGMA_OMP_CLAUSE_LASTPRIVATE:
clauses = c_parser_omp_clause_lastprivate (parser, clauses);
c_name = "lastprivate";
@ -7772,6 +7951,10 @@ c_parser_omp_all_clauses (c_parser *parser, unsigned int mask,
clauses = c_parser_omp_clause_ordered (parser, clauses);
c_name = "ordered";
break;
case PRAGMA_OMP_CLAUSE_OUTPUT:
clauses = c_parser_omp_clause_output (parser, clauses);
c_name = "output";
break;
case PRAGMA_OMP_CLAUSE_PRIVATE:
clauses = c_parser_omp_clause_private (parser, clauses);
c_name = "private";
@ -8583,7 +8766,9 @@ c_parser_omp_single (location_t loc, c_parser *parser)
| (1u << PRAGMA_OMP_CLAUSE_DEFAULT) \
| (1u << PRAGMA_OMP_CLAUSE_PRIVATE) \
| (1u << PRAGMA_OMP_CLAUSE_FIRSTPRIVATE) \
| (1u << PRAGMA_OMP_CLAUSE_SHARED))
| (1u << PRAGMA_OMP_CLAUSE_SHARED)) \
| (1u << PRAGMA_OMP_CLAUSE_INPUT) \
| (1u << PRAGMA_OMP_CLAUSE_OUTPUT)
static tree
c_parser_omp_task (location_t loc, c_parser *parser)

View File

@ -62,10 +62,12 @@ typedef enum pragma_omp_clause {
PRAGMA_OMP_CLAUSE_DEFAULT,
PRAGMA_OMP_CLAUSE_FIRSTPRIVATE,
PRAGMA_OMP_CLAUSE_IF,
PRAGMA_OMP_CLAUSE_INPUT,
PRAGMA_OMP_CLAUSE_LASTPRIVATE,
PRAGMA_OMP_CLAUSE_NOWAIT,
PRAGMA_OMP_CLAUSE_NUM_THREADS,
PRAGMA_OMP_CLAUSE_ORDERED,
PRAGMA_OMP_CLAUSE_OUTPUT,
PRAGMA_OMP_CLAUSE_PRIVATE,
PRAGMA_OMP_CLAUSE_REDUCTION,
PRAGMA_OMP_CLAUSE_SCHEDULE,

View File

@ -10272,6 +10272,20 @@ c_finish_omp_clauses (tree clauses)
bitmap_set_bit (&lastprivate_head, DECL_UID (t));
break;
case OMP_CLAUSE_INPUT:
name = "input";
t = OMP_CLAUSE_DECL (c);
need_complete = true;
need_implicitly_determined = true;
break;
case OMP_CLAUSE_OUTPUT:
name = "output";
t = OMP_CLAUSE_DECL (c);
need_complete = true;
need_implicitly_determined = true;
break;
case OMP_CLAUSE_IF:
case OMP_CLAUSE_NUM_THREADS:
case OMP_CLAUSE_SCHEDULE:

View File

@ -5734,6 +5734,15 @@ gimplify_scan_omp_clauses (tree *list_p, gimple_seq *pre_p,
flags = GOVD_REDUCTION | GOVD_SEEN | GOVD_EXPLICIT;
check_non_private = "reduction";
goto do_add;
case OMP_CLAUSE_INPUT:
case OMP_CLAUSE_OUTPUT:
{
tree view = OMP_CLAUSE_VIEW_ID (c);
if(view != NULL_TREE)
omp_add_variable (ctx, view, GOVD_LOCAL | GOVD_SEEN);
}
flags = GOVD_PRIVATE | GOVD_EXPLICIT;
goto do_add;
do_add:
decl = OMP_CLAUSE_DECL (c);
@ -5959,6 +5968,8 @@ gimplify_adjust_omp_clauses (tree *list_p)
= (n->value & GOVD_FIRSTPRIVATE) != 0;
break;
case OMP_CLAUSE_INPUT:
case OMP_CLAUSE_OUTPUT:
case OMP_CLAUSE_REDUCTION:
case OMP_CLAUSE_COPYIN:
case OMP_CLAUSE_COPYPRIVATE:

View File

@ -206,3 +206,40 @@ DEF_GOMP_BUILTIN (BUILT_IN_GOMP_SINGLE_COPY_START, "GOMP_single_copy_start",
BT_FN_PTR, ATTR_NOTHROW_LIST)
DEF_GOMP_BUILTIN (BUILT_IN_GOMP_SINGLE_COPY_END, "GOMP_single_copy_end",
BT_FN_VOID_PTR, ATTR_NOTHROW_LIST)
DEF_GOMP_BUILTIN (BUILT_IN_GOMP_STREAM_CREATE_STREAM,
"GOMP_stream_create_stream",
BT_FN_PTR_SIZE_ULL_PTR, ATTR_NOTHROW_LIST)
DEF_GOMP_BUILTIN (BUILT_IN_GOMP_STREAM_CREATE_READ_VIEW,
"GOMP_stream_create_read_view",
BT_FN_PTR, ATTR_NOTHROW_LIST)
DEF_GOMP_BUILTIN (BUILT_IN_GOMP_STREAM_CREATE_WRITE_VIEW,
"GOMP_stream_create_write_view",
BT_FN_PTR, ATTR_NOTHROW_LIST)
DEF_GOMP_BUILTIN (BUILT_IN_GOMP_STREAM_CREATE_TASK,
"GOMP_stream_create_task",
BT_FN_PTR, ATTR_NOTHROW_LIST)
DEF_GOMP_BUILTIN (BUILT_IN_GOMP_STREAM_ADD_EXPECTED_VIEWS,
"GOMP_stream_add_expected_views",
BT_FN_VOID_PTR_INT_INT_INT, ATTR_NOTHROW_LIST)
DEF_GOMP_BUILTIN (BUILT_IN_GOMP_STREAM_CONNECT_VIEW,
"GOMP_stream_connect_view",
BT_FN_VOID_PTR_PTR_PTR, ATTR_NOTHROW_LIST)
DEF_GOMP_BUILTIN (BUILT_IN_GOMP_STREAM_WAIT_UNTIL_CONNECTED,
"GOMP_stream_wait_until_connected",
BT_FN_VOID_PTR, ATTR_NOTHROW_LIST)
DEF_GOMP_BUILTIN (BUILT_IN_GOMP_STREAM_UPDATE, "GOMP_stream_update",
BT_FN_ULL_PTR_ULL, ATTR_NOTHROW_LIST)
DEF_GOMP_BUILTIN (BUILT_IN_GOMP_STREAM_STALL, "GOMP_stream_stall",
BT_FN_VOID_PTR_ULL, ATTR_NOTHROW_LIST)
DEF_GOMP_BUILTIN (BUILT_IN_GOMP_STREAM_RELEASE, "GOMP_stream_release",
BT_FN_VOID_PTR_ULL, ATTR_NOTHROW_LIST)
DEF_GOMP_BUILTIN (BUILT_IN_GOMP_STREAM_COMMIT, "GOMP_stream_commit",
BT_FN_VOID_PTR_ULL, ATTR_NOTHROW_LIST)
DEF_GOMP_BUILTIN (BUILT_IN_GOMP_STREAM_TASK_EXIT, "GOMP_stream_task_exit",
BT_FN_VOID_PTR, ATTR_NOTHROW_LIST)
DEF_GOMP_BUILTIN (BUILT_IN_GOMP_STREAM_PUSH_STUB, "GOMP_stream_push_stub",
BT_FN_VOID_PTR_PTR, ATTR_NOTHROW_LIST)
DEF_GOMP_BUILTIN (BUILT_IN_GOMP_STREAM_POP_STUB, "GOMP_stream_pop_stub",
BT_FN_VOID_PTR_PTR, ATTR_NOTHROW_LIST)

File diff suppressed because it is too large Load Diff

View File

@ -406,6 +406,12 @@ struct omp_region
/* True if this is a combined parallel+workshare region. */
bool is_combined_parallel;
/* Streams accessed by this region */
htab_t view_pointers;
/* Streamization data */
void *streamization_info;
};
extern struct omp_region *root_omp_region;

View File

@ -307,6 +307,12 @@ dump_omp_clause (pretty_printer *buffer, tree clause, int spc, int flags)
case OMP_CLAUSE_LASTPRIVATE:
name = "lastprivate";
goto print_remap;
case OMP_CLAUSE_INPUT:
name = "input";
goto print_remap;
case OMP_CLAUSE_OUTPUT:
name = "output";
goto print_remap;
case OMP_CLAUSE_COPYIN:
name = "copyin";
goto print_remap;

View File

@ -233,6 +233,8 @@ unsigned const char omp_clause_num_ops[] =
1, /* OMP_CLAUSE_SHARED */
1, /* OMP_CLAUSE_FIRSTPRIVATE */
2, /* OMP_CLAUSE_LASTPRIVATE */
4, /* OMP_CLAUSE_INPUT */
4, /* OMP_CLAUSE_OUTPUT */
4, /* OMP_CLAUSE_REDUCTION */
1, /* OMP_CLAUSE_COPYIN */
1, /* OMP_CLAUSE_COPYPRIVATE */
@ -243,7 +245,7 @@ unsigned const char omp_clause_num_ops[] =
0, /* OMP_CLAUSE_ORDERED */
0, /* OMP_CLAUSE_DEFAULT */
3, /* OMP_CLAUSE_COLLAPSE */
0 /* OMP_CLAUSE_UNTIED */
0, /* OMP_CLAUSE_UNTIED */
};
const char * const omp_clause_code_name[] =
@ -253,6 +255,8 @@ const char * const omp_clause_code_name[] =
"shared",
"firstprivate",
"lastprivate",
"input",
"output",
"reduction",
"copyin",
"copyprivate",
@ -10215,6 +10219,8 @@ walk_tree_1 (tree *tp, walk_tree_fn func, void *data,
case OMP_CLAUSE_PRIVATE:
case OMP_CLAUSE_SHARED:
case OMP_CLAUSE_FIRSTPRIVATE:
case OMP_CLAUSE_INPUT:
case OMP_CLAUSE_OUTPUT:
case OMP_CLAUSE_COPYIN:
case OMP_CLAUSE_COPYPRIVATE:
case OMP_CLAUSE_IF:

View File

@ -295,6 +295,12 @@ enum omp_clause_code
/* OpenMP clause: lastprivate (variable_list). */
OMP_CLAUSE_LASTPRIVATE,
/* OpenMP clause: firstprivate (variable_list). */
OMP_CLAUSE_INPUT,
/* OpenMP clause: lastprivate (variable_list). */
OMP_CLAUSE_OUTPUT,
/* OpenMP clause: reduction (operator:variable_list).
OMP_CLAUSE_REDUCTION_CODE: The tree_code of the operator.
Operand 1: OMP_CLAUSE_REDUCTION_INIT: Stmt-list to initialize the var.
@ -1760,6 +1766,24 @@ extern void protected_set_expr_location (tree, location_t);
OMP_CLAUSE_OPERAND (OMP_CLAUSE_RANGE_CHECK (OMP_CLAUSE_CHECK (NODE), \
OMP_CLAUSE_PRIVATE, \
OMP_CLAUSE_COPYPRIVATE), 0)
#define OMP_CLAUSE_STREAM_ID(NODE) \
OMP_CLAUSE_OPERAND (OMP_CLAUSE_RANGE_CHECK (OMP_CLAUSE_CHECK (NODE), \
OMP_CLAUSE_INPUT, \
OMP_CLAUSE_OUTPUT), 0)
#define OMP_CLAUSE_STREAM_SUB(NODE) \
OMP_CLAUSE_OPERAND (OMP_CLAUSE_RANGE_CHECK (OMP_CLAUSE_CHECK (NODE), \
OMP_CLAUSE_INPUT, \
OMP_CLAUSE_OUTPUT), 1)
#define OMP_CLAUSE_VIEW_ID(NODE) \
OMP_CLAUSE_OPERAND (OMP_CLAUSE_RANGE_CHECK (OMP_CLAUSE_CHECK (NODE), \
OMP_CLAUSE_INPUT, \
OMP_CLAUSE_OUTPUT), 2)
#define OMP_CLAUSE_BURST_SIZE(NODE) \
OMP_CLAUSE_OPERAND (OMP_CLAUSE_RANGE_CHECK (OMP_CLAUSE_CHECK (NODE), \
OMP_CLAUSE_INPUT, \
OMP_CLAUSE_OUTPUT), 3)
#define OMP_CLAUSE_HAS_LOCATION(NODE) \
((OMP_CLAUSE_CHECK (NODE))->omp_clause.locus != UNKNOWN_LOCATION)
#define OMP_CLAUSE_LOCATION(NODE) (OMP_CLAUSE_CHECK (NODE))->omp_clause.locus

View File

@ -0,0 +1,38 @@
2010-10-05 Antoniu Pop <antoniu.pop@gmail.com>
* stream.c (gomp_stream_add_view_to_list): Added missing sizeof
call inside gomp_realloc.
2010-07-10 Antoniu Pop <antoniu.pop@gmail.com>
* stream.c (GOMP_stream_connect_view): Update the
nr_registered_views field in the view_handle when connecting
views.
2010-07-05 Antoniu Pop <antoniu.pop@gmail.com>
* stream.c (gomp_stream_unregister_view): Set the EOS_P flag when
the last producer exits and commit up to the highest committed index.
(gomp_stream_compute_lower_max): New.
2010-07-05 Antoniu Pop <antoniu.pop@gmail.com>
* stream.c (GOMP_stream_create_stream): corrected initialization
values.
2010-07-01 Antoniu Pop <antoniu.pop@gmail.com>
* stream.h: New.
* stream.c: New.
* Makefile.am (libgomp_la_SOURCES): Added stream.c
* Makefile.in: Regenerated.
* libgomp.h: Include stream.h
* libgomp_g.h (GOMP_stream_create_stream)
(GOMP_stream_create_read_view, GOMP_stream_create_write_view)
(GOMP_stream_create_task, GOMP_stream_add_expected_views)
(GOMP_stream_connect_view, GOMP_stream_wait_until_connected)
(GOMP_stream_update, GOMP_stream_stall, GOMP_stream_release)
(GOMP_stream_commit, GOMP_stream_task_exit): Declared builtins
from stream.c
* libgomp.map: Export GOMP_stream_*.
* omp.h.in: Added GOMP_stream_* to the OpenMP public interface.

View File

@ -34,7 +34,7 @@ libgomp_la_LINK = $(LINK) $(libgomp_la_LDFLAGS)
libgomp_la_SOURCES = alloc.c barrier.c critical.c env.c error.c iter.c \
iter_ull.c loop.c loop_ull.c ordered.c parallel.c sections.c single.c \
task.c team.c work.c lock.c mutex.c proc.c sem.c bar.c ptrlock.c \
time.c fortran.c affinity.c
time.c fortran.c affinity.c stream.c
nodist_noinst_HEADERS = libgomp_f.h
nodist_libsubinclude_HEADERS = omp.h

View File

@ -95,7 +95,7 @@ am_libgomp_la_OBJECTS = alloc.lo barrier.lo critical.lo env.lo \
error.lo iter.lo iter_ull.lo loop.lo loop_ull.lo ordered.lo \
parallel.lo sections.lo single.lo task.lo team.lo work.lo \
lock.lo mutex.lo proc.lo sem.lo bar.lo ptrlock.lo time.lo \
fortran.lo affinity.lo
fortran.lo affinity.lo stream.lo
libgomp_la_OBJECTS = $(am_libgomp_la_OBJECTS)
DEFAULT_INCLUDES = -I.@am__isrc@
depcomp = $(SHELL) $(top_srcdir)/../depcomp
@ -306,7 +306,7 @@ libgomp_la_LINK = $(LINK) $(libgomp_la_LDFLAGS)
libgomp_la_SOURCES = alloc.c barrier.c critical.c env.c error.c iter.c \
iter_ull.c loop.c loop_ull.c ordered.c parallel.c sections.c single.c \
task.c team.c work.c lock.c mutex.c proc.c sem.c bar.c ptrlock.c \
time.c fortran.c affinity.c
time.c fortran.c affinity.c stream.c
nodist_noinst_HEADERS = libgomp_f.h
nodist_libsubinclude_HEADERS = omp.h
@ -463,6 +463,7 @@ distclean-compile:
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sections.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sem.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/single.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/stream.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/task.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/team.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/time.Plo@am__quote@

View File

@ -48,6 +48,7 @@
#include "mutex.h"
#include "bar.h"
#include "ptrlock.h"
#include "stream.h"
/* This structure contains the data to control one work-sharing construct,

View File

@ -167,4 +167,17 @@ GOMP_2.0 {
GOMP_loop_ull_runtime_start;
GOMP_loop_ull_static_next;
GOMP_loop_ull_static_start;
GOMP_stream_create_stream;
GOMP_stream_create_read_view;
GOMP_stream_create_write_view;
GOMP_stream_create_task;
GOMP_stream_add_expected_views;
GOMP_stream_connect_view;
GOMP_stream_wait_until_connected;
GOMP_stream_update;
GOMP_stream_stall;
GOMP_stream_release;
GOMP_stream_commit;
GOMP_stream_task_exit;
} GOMP_1.0;

View File

@ -179,4 +179,21 @@ extern bool GOMP_single_start (void);
extern void *GOMP_single_copy_start (void);
extern void GOMP_single_copy_end (void *);
/* stream.c */
extern void *GOMP_stream_create_stream (size_t, unsigned long long, char *);
extern void *GOMP_stream_create_read_view (void);
extern void *GOMP_stream_create_write_view (void);
extern void *GOMP_stream_create_task (void);
extern void GOMP_stream_add_expected_views (void *, int, int, int);
extern void GOMP_stream_connect_view (void *, void *, void *);
extern void GOMP_stream_wait_until_connected (void *);
extern unsigned long long GOMP_stream_update (void *,
const unsigned long long);
extern void GOMP_stream_stall (void *, const unsigned long long);
extern void GOMP_stream_release (void *, const unsigned long long);
extern void GOMP_stream_commit (void *, const unsigned long long);
extern void GOMP_stream_task_exit (void *);
#endif /* LIBGOMP_G_H */

View File

@ -102,4 +102,29 @@ int omp_get_active_level (void) __GOMP_NOTHROW;
}
#endif
#define GOMP_STREAM_ACCESS(VIEW, INDEX, TYPE) \
(**((TYPE ***) (VIEW))) \
[(unsigned long long)(INDEX) & \
(*((unsigned long long *)((*((char ***) (VIEW))) + 1)))]
extern void *GOMP_stream_create_stream (size_t, unsigned long long, char *)
__GOMP_NOTHROW;
extern void *GOMP_stream_create_read_view (void) __GOMP_NOTHROW;
extern void *GOMP_stream_create_write_view (void) __GOMP_NOTHROW;
extern void *GOMP_stream_create_task (void) __GOMP_NOTHROW;
extern void GOMP_stream_add_expected_views (void *, int, int, int)
__GOMP_NOTHROW;
extern void GOMP_stream_connect_view (void *, void *, void *) __GOMP_NOTHROW;
extern void GOMP_stream_wait_until_connected (void *) __GOMP_NOTHROW;
extern unsigned long long GOMP_stream_update (void *,
const unsigned long long)
__GOMP_NOTHROW;
extern void GOMP_stream_stall (void *, const unsigned long long)
__GOMP_NOTHROW;
extern void GOMP_stream_release (void *, const unsigned long long)
__GOMP_NOTHROW;
extern void GOMP_stream_commit (void *, const unsigned long long)
__GOMP_NOTHROW;
extern void GOMP_stream_task_exit (void *) __GOMP_NOTHROW;
#endif /* OMP_H */

562
libgomp/stream.c Normal file
View File

@ -0,0 +1,562 @@
/* Copyright (C) 2010 Free Software Foundation, Inc.
Contributed by Antoniu Pop <antoniu.pop@gmail.com>.
This file is part of the GNU OpenMP Library (libgomp).
Libgomp is free software; you can redistribute it and/or modify it
under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 2.1 of the License, or
(at your option) any later version.
Libgomp is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for
more details.
You should have received a copy of the GNU Lesser General Public License
along with libgomp; see the file COPYING.LIB. If not, write to the
Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
MA 02110-1301, USA. */
/* As a special exception, if you link this library with other files, some
of which are compiled with GCC, to produce an executable, this library
does not by itself cause the resulting executable to be covered by the
GNU General Public License. This exception does not however invalidate
any other reasons why the executable file might be covered by the GNU
General Public License. */
/* This implements the stream communication layer for libGOMP. */
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include "wait.h"
#include "sem.h"
#include "mutex.h"
#include "libgomp.h"
/* Data structures creation and pipeline initialization. */
/* Allocate and initialize a GOMP_STREAM for data elements of size
ELEMENT_SIZE using a circular buffer of STREAM_BUFFER_SIZE such
elements. Returns a pointer to the newly allocated stream. The
user may provide a pointer to pre-allocated memory to be used as
BUFFER for the stream. */
void *
GOMP_stream_create_stream (size_t element_size,
unsigned long long stream_buffer_size,
char *buffer)
{
gomp_stream_p stream = (gomp_stream_p) gomp_malloc (sizeof (gomp_stream_t));
/* Initialize and allocate the data buffer. We force the
buffer_size to be a power of 2 for efficient modulo computation
of the indices in the circular buffer. */
stream->element_size = element_size;
stream->buffer_size = 1;
while(stream->buffer_size < stream_buffer_size)
stream->buffer_size <<= 1;
stream->buffer_mask = stream->buffer_size - 1;
/* In case the user provided a pre-allocated buffer, we need to
ensure it is properly sized. */
if (buffer != NULL)
{
if (stream->buffer_size != stream_buffer_size)
gomp_fatal ("GOMP_stream: provided buffer size is not power of 2.");
stream->buffer = buffer;
}
else
{
stream->buffer =
(void *) gomp_malloc (stream->element_size * stream->buffer_size);
}
stream->expected_ready_p = false;
stream->connected_p = false;
stream->eos_p = false;
/* Initialize the view_handles. */
stream->read_views.current_min = stream->buffer_size;
stream->read_views.current_max = 0;
stream->read_views.view_list.views = NULL;
stream->read_views.view_list.nr_views = 0;
stream->read_views.view_list.size = 0;
stream->read_views.nr_expected_views = 0;
stream->read_views.nr_registered_views = 0;
stream->read_views.nr_unregistered_views = 0;
gomp_mutex_init (&stream->read_views.connect_view_mutex);
stream->write_views.current_min = 0;
stream->write_views.current_max = stream->buffer_size;
stream->write_views.view_list.views = NULL;
stream->write_views.view_list.nr_views = 0;
stream->write_views.view_list.size = 0;
stream->write_views.nr_expected_views = 0;
stream->write_views.nr_registered_views = 0;
stream->write_views.nr_unregistered_views = 0;
gomp_mutex_init (&stream->write_views.connect_view_mutex);
#ifndef HAVE_SYNC_BUILTINS
gomp_mutex_init (&stream->stream_mutex);
#endif
return stream;
}
/* Allocate and initialize a generic GOMP_STREAM_VIEW that can be
connected to any stream to give either read or write access
depending on its TYPE. Returns a pointer to the newly allocated
view. */
static inline void *
gomp_stream_create_view (int type)
{
gomp_stream_view_p view =
(gomp_stream_view_p) gomp_malloc (sizeof(gomp_stream_view_t));
view->lower_index = 0;
view->upper_index = 0;
view->stream = NULL;
view->end_p = false;
view->type = type;
view->local_min_value = 0;
return view;
}
/* Wrapper for creating a READ view. */
void *
GOMP_stream_create_read_view (void)
{
return gomp_stream_create_view (READ_VIEW);
}
/* Wrapper for creating a WRITE view. */
void *
GOMP_stream_create_write_view (void)
{
return gomp_stream_create_view (WRITE_VIEW);
}
/* Allocate and initialize a GOMP_STREAM_TASK data structure. */
void *
GOMP_stream_create_task (void)
{
gomp_stream_task_p task =
(gomp_stream_task_p) gomp_malloc (sizeof(gomp_stream_task_t));
task->read_view_list.views = NULL;
task->read_view_list.nr_views = 0;
task->read_view_list.size = 0;
task->write_view_list.views = NULL;
task->write_view_list.nr_views = 0;
task->write_view_list.size = 0;
return task;
}
/* Declare additional READ_VIEWS and WRITE_VIEWS expected views on
stream S. When possible, the thread that creates the streaming
tasks should declare, for each stream, the number of read/write
views that will connect to a stream before the streaming tasks are
started. If this function is called on a stream, there will be no
further checks for the number of tasks partaking in the
initialization synchronization. */
void
GOMP_stream_add_expected_views (void *s, int read_views, int write_views,
int final)
{
gomp_stream_p stream = (gomp_stream_p) s;
if (stream->expected_ready_p)
gomp_fatal
("GOMP_stream: attempting to modify a final number of expected views.");
stream->expected_ready_p = final;
#ifdef HAVE_SYNC_BUILTINS
__sync_fetch_and_add (&stream->read_views.nr_expected_views, read_views);
__sync_fetch_and_add (&stream->write_views.nr_expected_views, write_views);
#else
gomp_mutex_lock (&stream->stream_mutex);
stream->read_views.nr_expected_views += read_views;
stream->write_views.nr_expected_views += write_views;
gomp_mutex_unlock (&stream->stream_mutex);
#endif
}
/* Add VIEW to the VIEW_LIST. We actually use an array as this list
is only modified in the initialization phase and we never remove
any items from it. */
static inline void
gomp_stream_add_view_to_list (gomp_stream_view_p view,
gomp_stream_view_list_p view_list)
{
/* Allocate memory when needed. */
if (view_list->views == NULL || view_list->nr_views == view_list->size)
{
if (view_list->size == 0)
view_list->size = 4;
if (view_list->nr_views == view_list->size)
view_list->size <<= 1;
view_list->views =
(gomp_stream_view_p *) gomp_realloc (view_list->views,
view_list->size * sizeof (gomp_stream_view_p));
}
view_list->views[view_list->nr_views] = view;
view_list->nr_views += 1;
}
/* Connect a VIEW to a STREAM and also to the TASK which will use it.
This effectively builds the runtime task graph. */
void
GOMP_stream_connect_view (void *t, void *s, void *v)
{
gomp_stream_task_p task = (gomp_stream_task_p) t;
gomp_stream_p stream = (gomp_stream_p) s;
gomp_stream_view_p view = (gomp_stream_view_p) v;
gomp_stream_view_handle_p vh = (view->type == READ_VIEW) ?
&stream->read_views : &stream->write_views;
gomp_stream_view_list_p stream_list = &vh->view_list;
gomp_stream_view_list_p task_list = (view->type == READ_VIEW) ?
&task->read_view_list : &task->write_view_list;
view->stream = stream;
/* A read view's lower index is shifted by the buffer_size as the
stream is initially empty. This is equivalent to releasing the
original buffer_size elements. A write view will start with
buffer_size free space. */
if (view->type == READ_VIEW)
view->lower_index = stream->buffer_size;
else
view->local_min_value = stream->buffer_size;
/* Register the view with the TASK to which it belongs. This
operation is local to the task, so there is no need to
synchronize. */
gomp_stream_add_view_to_list (view, task_list);
/* Connect the view to the stream. This must be done atomically as
this data structure is shared with the other producer/consumer
tasks. */
gomp_mutex_lock (&vh->connect_view_mutex);
gomp_stream_add_view_to_list (view, stream_list);
gomp_mutex_unlock (&vh->connect_view_mutex);
__sync_fetch_and_add (&vh->nr_registered_views, 1);
}
/* Check whether all the expected views on STREAM have already
connected. */
static inline bool
gomp_stream_check_connected (gomp_stream_p stream)
{
if (!stream->expected_ready_p)
return false;
if (stream->connected_p)
return true;
if ((stream->read_views.view_list.nr_views
== stream->read_views.nr_expected_views)
&& (stream->write_views.view_list.nr_views
== stream->write_views.nr_expected_views))
{
stream->connected_p = true;
return true;
}
return false;
}
/* Wait until all the streams to which TASK connects are ready and
connected to all producer/consumer tasks. */
void
GOMP_stream_wait_until_connected (void *t)
{
gomp_stream_task_p task = (gomp_stream_task_p) t;
int num_read_views = task->read_view_list.nr_views;
int num_write_views = task->write_view_list.nr_views;
int i;
bool done;
do
{
done = true;
for (i = 0; i < num_read_views; ++i)
if (!gomp_stream_check_connected (task->read_view_list.views[i]->stream))
done = false;
for (i = 0; i < num_write_views; ++i)
if (!gomp_stream_check_connected (task->write_view_list.views[i]->stream))
done = false;
}
while (!done);
}
/* Stream communication/synchronization. */
/* Compute the minimum of the LOWER_INDEX fields of all views in the
LIST of views. This is used during the termination phase to give
access to the readers up to the highest committed index. This is
only useful when producers, not too far apart in indices they
committed, forget to commit up to the last index that should appear
in the stream. */
static inline unsigned long long
gomp_stream_compute_lower_max (gomp_stream_view_list_p list)
{
unsigned long long local_max = 0;
gomp_stream_view_p *views = list->views;
int i;
for (i = 0; i < list->nr_views; ++i)
if (views[i]->lower_index > local_max)
local_max = views[i]->lower_index;
return local_max;
}
/* Compute the minimum of the LOWER_INDEX fields of all views in the
LIST of views. For a LIST of read views, this minimum represents
the highest index released by all read views on a stream (i.e. the
index of elements that all consumers have already discarded) and
therefore the highest index a write view will be allowed to acquire
for writing. For a LIST of write views, this minimum represents
the highest index all producers have committed and thus the highest
index available for reading. */
static inline unsigned long long
gomp_stream_compute_lower_min (gomp_stream_view_list_p list)
{
unsigned long long local_min = GOMP_STREAM_MAX_INDEX;
gomp_stream_view_p *views = list->views;
int i;
for (i = 0; i < list->nr_views; ++i)
if (views[i]->lower_index < local_min)
local_min = views[i]->lower_index;
return local_min;
}
/* Compute the minimum of the UPPER_INDEX fields of all views in the
LIST of views. Similar to the above, but this is only a hint on
the resources that another producer (resp. consumer) has already
acquired. If a producer (resp. consumer) has successfully acquired
an index with GOMP_stream_stall (resp. GOMP_stream_update) for
writing (resp. reading), then all other producers (resp. consumers)
on the same stream can access up to the same index without further
verification. */
static inline unsigned long long
gomp_stream_compute_upper_min (gomp_stream_view_list_p list)
{
unsigned long long local_min = GOMP_STREAM_MAX_INDEX;
gomp_stream_view_p *views = list->views;
int i;
for (i = 0; i < list->nr_views; ++i)
if (views[i]->upper_index < local_min)
local_min = views[i]->upper_index;
return local_min;
}
/* Wait until the producers (resp. consumers) on this stream have
committed (resp. released) up to the INDEX position in the stream.
When that hapens, the consumer (resp. producer) connected to the
stream through VIEW is allowed to access the elements up to
INDEX. */
static inline void
gomp_stream_wait_release (gomp_stream_view_p view,
gomp_stream_view_handle_p vh,
const unsigned long long index)
{
/* Test whether someone already got a hold of a bigger index
yet. */
if (view->local_min_value < index)
{
while (vh->current_min < index && !view->stream->eos_p)
{
unsigned long long local_min =
gomp_stream_compute_lower_min (&vh->view_list);
if (vh->current_min == local_min)
__asm volatile ("pause" : : : "memory");
else
vh->current_min = local_min;
}
view->local_min_value = vh->current_min;
}
}
/* Request read access for the view V to the stream up to INDEX. In
case the producers have finished and there is not enough data, the
returned value is the highest index to which the view is allowed to
access the stream. */
unsigned long long
GOMP_stream_update (void *v, const unsigned long long index)
{
gomp_stream_view_p view = (gomp_stream_view_p) v;
view->upper_index = index;
/* In case another consumer has received permission to read up to a
yet higher index, then there is no need to check for this one. */
if (index > view->stream->read_views.current_max)
{
gomp_stream_wait_release (view, &view->stream->write_views, index);
/* If the producers have finished producing for this stream, we
need to ensure we do not give read permission to the view
past the highest fully committed index (committed by all
producers). */
if (view->stream->eos_p)
{
view->stream->write_views.current_min =
gomp_stream_compute_lower_min (&view->stream->write_views.view_list);
if (index > view->stream->write_views.current_min)
{
return view->stream->write_views.current_min;
}
}
view->stream->read_views.current_max = index;
}
return index;
}
/* Request write access for the view V to the stream up to INDEX. */
void
GOMP_stream_stall (void *v, const unsigned long long index)
{
gomp_stream_view_p view = (gomp_stream_view_p) v;
view->upper_index = index;
if (index > view->stream->write_views.current_max)
{
gomp_stream_wait_release (view, &view->stream->read_views, index);
view->stream->write_views.current_max = index;
}
}
/* Relinquish read access for the view V to the stream up to
INDEX. */
void
GOMP_stream_release (void *v, const unsigned long long index)
{
gomp_stream_view_p view = (gomp_stream_view_p) v;
view->lower_index = index + view->stream->buffer_size;
}
/* Relinquish write access for the view V to the stream up to
INDEX. */
void
GOMP_stream_commit (void *v, const unsigned long long index)
{
gomp_stream_view_p view = (gomp_stream_view_p) v;
view->lower_index = index;
}
/* Finalization and destruction of the streaming data structures. */
/* Disconnects VIEW from the stream to which it is connected and free
the stream if it was the last task to disconnect. */
static inline void
gomp_stream_unregister_view (gomp_stream_view_p view)
{
gomp_stream_p stream = view->stream;
gomp_stream_view_handle_p vh =
(view->type == READ_VIEW) ? &stream->read_views : &stream->write_views;
int unregistered_views;
__sync_fetch_and_add (&(vh->nr_unregistered_views), 1);
unregistered_views = __sync_add_and_fetch (&(stream->unregistered_views), 1);
/* Make sure that when multiple views access a stream, the finished
views do not hinder the others in the min computation. */
if (view->type == READ_VIEW)
GOMP_stream_release (view, GOMP_STREAM_MAX_INDEX);
/* The last producer exiting will set the eos_p flag and allow the
consumers to read up to the highest committed index. */
else if (vh->nr_unregistered_views == vh->nr_registered_views)
{
stream->eos_p = true;
vh->current_min = gomp_stream_compute_lower_max (&vh->view_list);
}
/* If all known views arre accounted for, this is the last one
unregistering. It frees the memory allocated for the stream as
well as all the views on this stream. */
if (unregistered_views == (stream->read_views.nr_registered_views
+ stream->write_views.nr_registered_views))
{
gomp_stream_view_list_p read_view_list = &stream->read_views.view_list;
gomp_stream_view_list_p write_view_list = &stream->write_views.view_list;
int i;
for (i = 0; i < read_view_list->nr_views; ++i)
free (read_view_list->views[i]);
for (i = 0; i < write_view_list->nr_views; ++i)
free (write_view_list->views[i]);
free (stream->buffer);
free (read_view_list->views);
free (write_view_list->views);
free (stream);
}
}
/* Invoked before terminating a stream TASK, this disconnects all the
views and for all streams for which it is the last one to
disconnect from, it frees up all data structures. */
void
GOMP_stream_task_exit (void *t)
{
gomp_stream_task_p task = (gomp_stream_task_p) t;
int num_read_views = task->read_view_list.nr_views;
int num_write_views = task->write_view_list.nr_views;
int i;
for (i = 0; i < num_read_views; ++i)
gomp_stream_unregister_view (task->read_view_list.views[i]);
for (i = 0; i < num_write_views; ++i)
gomp_stream_unregister_view (task->write_view_list.views[i]);
free (task->read_view_list.views);
free (task->write_view_list.views);
free (task);
}

210
libgomp/stream.h Normal file
View File

@ -0,0 +1,210 @@
/* Copyright (C) 2010 Free Software Foundation, Inc.
Contributed by Antoniu Pop <antoniu.pop@gmail.com>.
This file is part of the GNU OpenMP Library (libgomp).
Libgomp is free software; you can redistribute it and/or modify it
under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 2.1 of the License, or
(at your option) any later version.
Libgomp is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for
more details.
You should have received a copy of the GNU Lesser General Public License
along with libgomp; see the file COPYING.LIB. If not, write to the
Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
MA 02110-1301, USA. */
/* As a special exception, if you link this library with other files, some
of which are compiled with GCC, to produce an executable, this library
does not by itself cause the resulting executable to be covered by the
GNU General Public License. This exception does not however invalidate
any other reasons why the executable file might be covered by the GNU
General Public License. */
/* This implements the stream communication layer for libGOMP. */
#ifndef GOMP_STREAM_H
#define GOMP_STREAM_H 1
#include <limits.h>
/* Define the type and maximum value for the indices used within the
stream. The indices are strictly monotonically increasing
integers, so we need a type that does not wrap around too fast. An
implementation of the wrap-around is necessary for systems where
this poses a problem. */
/* typedef unsigned long long int gomp_stream_index_t; */
#define GOMP_STREAM_MAX_INDEX ULLONG_MAX
/*#define LAZY_SYNCH
#define GUARDED_WAKE*/
/*
typedef enum {
GOMP_STREAM_INITIALIZED = 1,
GOMP_STREAM_ALLOCATED = 2,
GOMP_STREAM_PRODUCED = 4,
GOMP_STREAM_CONSUMED = 8,
GOMP_STREAM_ZOMBIE = 16,
GOMP_STREAM_STALL = 32
} gomp_stream_state;
*/
typedef enum
{
READ_VIEW,
WRITE_VIEW
} gomp_stream_view_type_t;
struct gomp_stream;
struct gomp_stream_task;
/* GOMP_STREAM_VIEW data structure. Producer and consumer tasks
connect to a GOMP_STREAM using views. */
typedef struct gomp_stream_view
{
/* The stream accessed through this view. WARNING: this field needs
to be first. */
struct gomp_stream *stream;
/* The alignment directives are needed to ensure these
high-potential false-sharing fields are on their own cache
lines. */
/* Lower and upper bounds accessible in the stream through this
view. */
unsigned long long lower_index __attribute__((aligned (64)));
unsigned long long upper_index __attribute__((aligned (64)));
/* The task using this view. */
struct gomp_stream_task *task __attribute__((aligned (64)));
/* Setting this flag means the process accessing the stream through
this view relinquishes his access to the stream (generally when
terminating). */
bool end_p;
/* Type of this view (read or write). */
gomp_stream_view_type_t type;
/* In order to avoid excessive accesses to the global minimum index
(released or consumed), which strongly impacts cache traffic, use
this duplcated field for an additional level of caching and only
update when needed. */
unsigned long long local_min_value;
} gomp_stream_view_t, *gomp_stream_view_p;
/* List of GOMP_STREAM_VIEWs. As this list is only modified in the
initialization phase and we never remove items, we'll use an
array. */
typedef struct gomp_stream_view_list
{
gomp_stream_view_p *views;
int nr_views;
int size;
} gomp_stream_view_list_t, *gomp_stream_view_list_p;
/* GOMP_STREAM_VIEW_HANDLE data structure. This allows the tasks
interacting through the GOMP_STREAM to which this handle is
attached to keep updated information global to all similar views on
this stream. */
typedef struct gomp_stream_view_handle
{
/* The alignment directives are needed to ensure these
high-potential false-sharing fields are on their own cache
lines. */
/* Latest computed value of the min released index and max acquired
index values across views. */
volatile unsigned long long current_min __attribute__((aligned (64)));
volatile unsigned long long current_max __attribute__((aligned (64)));
/* Bookkeeping for view connections. */
gomp_stream_view_list_t view_list __attribute__((aligned (64)));
int nr_expected_views;
int nr_registered_views;
int nr_unregistered_views;
/* Enforce atomic connection of the views to the stream. */
gomp_mutex_t connect_view_mutex;
} gomp_stream_view_handle_t, *gomp_stream_view_handle_p;
/* GOMP_STREAM data structure. */
typedef struct gomp_stream
{
/* WARNING: the first two fields (BUFFER and BUFFER_MASK) need to
remain in their respective positions. */
/* The pointer to the buffer, as well as the subsequent buffer
description, should be on a single mostly read cache line. The
EOS_P flag is only set at the very end of the use of this
stream. */
/* Circular buffer containing the data communicated through this
stream. */
char *buffer __attribute__((aligned (64)));
/* Size of the buffer and the bitmask used for modulo computation
for the wrap-around. The size is expressed in basic elements for
this stream. The size in bytes of the buffer is
BUFFER_SIZE * ELEMENT_SIZE. */
unsigned long long buffer_mask;
unsigned long long buffer_size;
unsigned long long element_size;
/* True once all the tasks that should be expected to connect to
this stream been declared. */
bool expected_ready_p;
/* True once all the tasks expected to connect to this stream have
done so. */
bool connected_p;
/* End of stream: true when all producers have finished committing
all the data and are terminating. */
bool eos_p;
/* Handles for read and write views on this stream. */
gomp_stream_view_handle_t read_views;
gomp_stream_view_handle_t write_views;
/* Barrier used both for waiting for all views to connect to the
stream and to find the last view disconnecting (and who therefore
frees this stream). */
/*gomp_barrier_t view_handling_barrier;*/
/* Counter of the number of total unregistered views, both read and
write, used to determine the last task deconnecting its view.
The last task will also free the data structures. */
int unregistered_views;
#ifndef HAVE_SYNC_BUILTINS
/* We may need a lock for atomicity if no atomic operations are
available. */
gomp_mutex_t stream_mutex;
#endif
} gomp_stream_t, *gomp_stream_p;
/* GOMP_STREAM_TASK data structure. Runtime node in the task
graph. */
typedef struct gomp_stream_task
{
/* Lists of views on streams used by this task. */
gomp_stream_view_list_t read_view_list;
gomp_stream_view_list_t write_view_list;
} gomp_stream_task_t, *gomp_stream_task_p;
#endif /* GOMP_STREAM_H */