[1/6] OpenMP 4.0 support (gcc/ part)

Jakub Jelinek jakub@redhat.com
Tue Oct 8 19:52:00 GMT 2013


Hi!

2013-10-08  Jakub Jelinek  <jakub@redhat.com>

gcc/
	* tree-pretty-print.c (dump_omp_clause): Handle OMP_CLAUSE__LOOPTEMP_
	and new OpenMP 4.0 clauses, handle UDR OMP_CLAUSE_REDUCTION,
	formatting fixes, use pp_colon instead of pp_character (..., ':'),
	similarly pp_right_paren.
	(dump_generic_node): Handle OMP_DISTRIBUTE, OMP_TEAMS,
	OMP_TARGET_DATA, OMP_TARGET, OMP_TARGET_UPDATE, OMP_TASKGROUP,
	allow OMP_FOR_INIT to be NULL, handle OMP_ATOMIC_SEQ_CST.
	* tree.c (omp_clause_num_ops, omp_clause_code_name): Add OpenMP 4.0
	clauses.
	(omp_declare_simd_clauses_equal,
	omp_remove_redundant_declare_simd_attrs): New functions.
	(attribute_value_equal): Use omp_declare_simd_clauses_equal.
	(walk_tree_1): Handle new OpenMP 4.0 clauses.
	* tree.h (OMP_LOOP_CHECK): Define.
	(OMP_FOR_BODY, OMP_FOR_CLAUSES, OMP_FOR_INIT, OMP_FOR_COND,
	OMP_FOR_INCR, OMP_FOR_PRE_BODY): Use it.
	(OMP_TASKGROUP_BODY, OMP_TEAMS_BODY, OMP_TEAMS_CLAUSES,
	OMP_TARGET_DATA_BODY, OMP_TARGET_DATA_CLAUSES, OMP_TARGET_BODY,
	OMP_TARGET_CLAUSES, OMP_TARGET_UPDATE_CLAUSES, OMP_CLAUSE_SIZE,
	OMP_ATOMIC_SEQ_CST, OMP_CLAUSE_DEPEND_KIND, OMP_CLAUSE_MAP_KIND,
	OMP_CLAUSE_MAP_ZERO_BIAS_ARRAY_SECTION, OMP_CLAUSE_PROC_BIND_KIND,
	OMP_CLAUSE_REDUCTION_OMP_ORIG_REF, OMP_CLAUSE_ALIGNED_ALIGNMENT,
	OMP_CLAUSE_NUM_TEAMS_EXPR, OMP_CLAUSE_THREAD_LIMIT_EXPR,
	OMP_CLAUSE_DEVICE_ID, OMP_CLAUSE_DIST_SCHEDULE_CHUNK_EXPR,
	OMP_CLAUSE_SIMDLEN_EXPR): Define.
	(OMP_CLAUSE_DECL): Change range up to OMP_CLAUSE__LOOPTEMP_.
	(omp_remove_redundant_declare_simd_attrs): New prototype.
	* gimple.def (GIMPLE_OMP_TASKGROUP, GIMPLE_OMP_TARGET,
	GIMPLE_OMP_TEAMS): New codes.
	(GIMPLE_OMP_RETURN): Use GSS_OMP_ATOMIC_STORE instead of GSS_BASE.
	* omp-low.c (struct omp_context): Add cancel_label and cancellable
	fields.
	(target_nesting_level): New variable.
	(extract_omp_for_data): Handle GF_OMP_FOR_KIND_DISTRIBUTE and
	OMP_CLAUSE_DIST_SCHEDULE.  Don't fallback to library implementation
	for collapse > 1 static schedule unless ordered.
	(get_ws_args_for): Add par_stmt argument.  Handle combined loops.
	(determine_parallel_type): Adjust get_ws_args_for caller.
	(install_var_field): Handle mask & 4 for double indirection.
	(scan_sharing_clauses): Ignore shared clause on teams construct.
	Handle OMP_CLAUSE__LOOPTEMP_ and new OpenMP 4.0 clauses.
	(create_omp_child_function): If inside target or declare target
	constructs, set "omp declare target" attribute on the child
	function.
	(find_combined_for): New function.
	(scan_omp_parallel): Handle combined loops.
	(scan_omp_target, scan_omp_teams): New functions.
	(check_omp_nesting_restrictions): Check new OpenMP 4.0 nesting
	restrictions and set ctx->cancellable for cancellable constructs.
	(scan_omp_1_stmt): Call check_omp_nesting_restrictions also on
	selected builtin calls.  Handle GIMPLE_OMP_TASKGROUP,
	GIMPLE_OMP_TARGET, GIMPLE_OMP_TEAMS.
	(build_omp_barrier): Add lhs argument, return gimple rather than
	tree.
	(omp_clause_aligned_alignment): New function.
	(lower_rec_simd_input_clauses): Only call SET_DECL_VALUE_EXPR
	on decls.
	(lower_rec_input_clauses): Add FD argument.  Ignore shared clauses
	on teams constructs.  Handle user defined reductions and new
	OpenMP 4.0 clauses.
	(lower_reduction_clauses): Don't set placeholder to address of ref
	if it has already the right type.
	(lower_send_clauses): Handle OMP_CLAUSE__LOOPTEMP_.
	(expand_parallel_call): Use the new non-_start suffixed builtins,
	handle OMP_CLAUSE_PROC_BIND, don't call the outlined function
	and GOMP_parallel_end after the call.
	(expand_task_call): Handle OMP_CLAUSE_DEPEND.
	(expand_omp_for_init_counts): Handle combined loops.
	(expand_omp_for_init_vars): Add inner_stmt argument, handle combined
	loops.
	(expand_omp_for_generic): Likewise.  Use GOMP_loop_end_cancel at the
	end of cancellable loops.
	(expand_omp_for_static_nochunk, expand_omp_for_static_chunk):
	Likewise.  Handle collapse > 1 loops.
	(expand_omp_simd): Handle combined loops.
	(expand_omp_for): Add inner_stmt argument, adjust callers of
	expand_omp_for* functions, use expand_omp_for_static*chunk even
	for collapse > 1 unless ordered.
	(expand_omp_sections): Use GOMP_sections_end_cancel at the end
	of cancellable sections.
	(expand_omp_single): Remove need_barrier variable, just rely on
	gimple_omp_return_nowait_p.  Adjust build_omp_barrier caller.
	(expand_omp_synch): Allow GIMPLE_OMP_TASKGROUP and GIMPLE_OMP_TEAMS.
	(expand_omp_atomic_load, expand_omp_atomic_store,
	expand_omp_atomic_fetch_op): Handle gimple_omp_atomic_seq_cst_p.
	(expand_omp_target): New function.
	(expand_omp): Handle combined loops.  Handle GIMPLE_OMP_TASKGROUP,
	GIMPLE_OMP_TEAMS, GIMPLE_OMP_TARGET.
	(build_omp_regions_1): Immediately close region for
	GF_OMP_TARGET_KIND_UPDATE.
	(maybe_add_implicit_barrier_cancel): New function.
	(lower_omp_sections): Adjust lower_rec_input_clauses caller.  Handle
	cancellation.
	(lower_omp_single): Likewise.  Add clobber after the barrier.
	(lower_omp_taskgroup): New function.
	(lower_omp_for): Handle combined loops.  Adjust
	lower_rec_input_clauses caller.  Handle cancellation.
	(lower_depend_clauses): New function.
	(lower_omp_taskreg): Lower depend clauses.  Adjust
	lower_rec_input_clauses caller.  Add clobber after the call.  Handle
	cancellation.
	(lower_omp_target, lower_omp_teams): New functions.
	(lower_omp_1): Handle cancellation.  Handle GIMPLE_OMP_TASKGROUP,
	GIMPLE_OMP_TARGET, GIMPLE_OMP_TEAMS and GOMP_barrier, GOMP_cancel
	and GOMP_cancellation_point calls.
	(lower_omp): Fold stmts inside of target region.
	(diagnose_sb_1, diagnose_sb_2): Handle GIMPLE_OMP_TASKGROUP,
	GIMPLE_OMP_TARGET and GIMPLE_OMP_TEAMS.
	* builtin-types.def (DEF_FUNCTION_TYPE_8): Document.
	(BT_FN_VOID_OMPFN_PTR_UINT,
	BT_FN_VOID_OMPFN_PTR_UINT_LONG_LONG_LONG,
	BT_FN_VOID_OMPFN_PTR_UINT_LONG_LONG_LONG_LONG,
	BT_FN_VOID_OMPFN_PTR_OMPCPYFN_LONG_LONG_BOOL_UINT): Remove.
	(BT_FN_VOID_OMPFN_PTR_UINT_UINT_UINT,
	BT_FN_VOID_OMPFN_PTR_UINT_LONG_LONG_LONG_UINT,
	BT_FN_VOID_OMPFN_PTR_UINT_LONG_LONG_LONG_LONG_UINT,
	BT_FN_BOOL_INT, BT_FN_BOOL_INT_BOOL, BT_FN_VOID_UINT_UINT,
	BT_FN_VOID_INT_PTR_SIZE_PTR_PTR_PTR,
	BT_FN_VOID_INT_OMPFN_PTR_SIZE_PTR_PTR_PTR,
	BT_FN_VOID_OMPFN_PTR_OMPCPYFN_LONG_LONG_BOOL_UINT_PTR): New.
	* tree-ssa-alias.c (ref_maybe_used_by_call_p_1,
	call_may_clobber_ref_p_1): Handle BUILT_IN_GOMP_BARRIER_CANCEL,
	BUILT_IN_GOMP_TASKGROUP_END, BUILT_IN_GOMP_LOOP_END_CANCEL,
	BUILT_IN_GOMP_SECTIONS_END_CANCEL.  Don't handle
	BUILT_IN_GOMP_PARALLEL_END.
	* gimple-low.c (lower_stmt): Handle GIMPLE_OMP_TASKGROUP,
	GIMPLE_OMP_TARGET and GIMPLE_OMP_TEAMS.
	* gimple-pretty-print.c (dump_gimple_omp_for): Handle
	GF_OMP_FOR_KIND_DISTRIBUTE.
	(dump_gimple_omp_target, dump_gimple_omp_teams): New functions.
	(dump_gimple_omp_block): Handle GIMPLE_OMP_TASKGROUP.
	(dump_gimple_omp_return): Print lhs if it has any.
	(dump_gimple_omp_atomic_load, dump_gimple_omp_atomic_store): Handle
	gimple_omp_atomic_seq_cst_p.
	(pp_gimple_stmt_1): Handle GIMPLE_OMP_TASKGROUP, GIMPLE_OMP_TARGET
	and GIMPLE_OMP_TEAMS.
	* langhooks.c (lhd_omp_mappable_type): New function.
	* tree-vectorizer.c (struct simd_array_to_simduid): Fix up comment.
	* langhooks.h (struct lang_hooks_for_types): Add omp_mappable_type
	hook.
	* gimplify.c (enum gimplify_omp_var_data): Add GOVD_MAP,
	GOVD_ALIGNED and GOVD_MAP_TO_ONLY.
	(enum omp_region_type): Add ORT_TEAMS, ORT_TARGET_DATA and
	ORT_TARGET.
	(struct gimplify_omp_ctx): Add combined_loop field.
	(gimplify_call_expr, gimplify_modify_expr): Don't call fold_stmt
	on stmts inside of target region.
	(is_gimple_stmt): Return true for OMP_DISTRIBUTE and OMP_TASKGROUP.
	(omp_firstprivatize_variable): Handle GOVD_MAP, GOVD_ALIGNED,
	ORT_TARGET and ORT_TARGET_DATA.
	(omp_add_variable): Avoid checks on readding var for GOVD_ALIGNED.
	Handle GOVD_MAP.
	(omp_notice_threadprivate_variable): Complain about threadprivate
	variables in target region.
	(omp_notice_variable): Complain about vars with non-mappable type
	in target region.  Handle ORT_TEAMS, ORT_TARGET and ORT_TARGET_DATA.
	(omp_check_private): Ignore ORT_TARGET* regions.
	(gimplify_scan_omp_clauses, gimplify_adjust_omp_clauses_1,
	gimplify_adjust_omp_clauses): Handle new OpenMP 4.0 clauses.
	(find_combined_omp_for): New function.
	(gimplify_omp_for): Handle gimplification of combined loops.
	(gimplify_omp_workshare): Gimplify also OMP_TARGET, OMP_TARGET_DATA,
	OMP_TEAMS.
	(gimplify_omp_target_update): New function.
	(gimplify_omp_atomic): Handle OMP_ATOMIC_SEQ_CST.
	(gimplify_expr): Handle OMP_DISTRIBUTE, OMP_TARGET, OMP_TARGET_DATA,
	OMP_TARGET_UPDATE, OMP_TEAMS, OMP_TASKGROUP.
	(gimplify_body): If fndecl has "omp declare target" attribute, add
	implicit ORT_TARGET context around it.
	* tree.def (OMP_DISTRIBUTE, OMP_TEAMS, OMP_TARGET_DATA, OMP_TARGET,
	OMP_TASKGROUP, OMP_TARGET_UPDATE): New tree codes.
	* tree-nested.c (convert_nonlocal_reference_stmt,
	convert_local_reference_stmt, convert_gimple_call): Handle
	GIMPLE_OMP_TARGET, GIMPLE_OMP_TEAMS and GIMPLE_OMP_TASKGROUP.
	* omp-builtins.def (BUILT_IN_GOMP_TASK): Use
	BT_FN_VOID_OMPFN_PTR_OMPCPYFN_LONG_LONG_BOOL_UINT_PTR
	instead of BT_FN_VOID_OMPFN_PTR_OMPCPYFN_LONG_LONG_BOOL_UINT.
	(BUILT_IN_GOMP_TARGET, BUILT_IN_GOMP_TARGET_DATA,
	BUILT_IN_GOMP_TARGET_END_DATA, BUILT_IN_GOMP_TARGET_UPDATE,
	BUILT_IN_GOMP_TEAMS, BUILT_IN_BARRIER_CANCEL,
	BUILT_IN_GOMP_LOOP_END_CANCEL,
	BUILT_IN_GOMP_SECTIONS_END_CANCEL, BUILT_IN_OMP_GET_TEAM_NUM,
	BUILT_IN_OMP_GET_NUM_TEAMS, BUILT_IN_GOMP_TASKGROUP_START,
	BUILT_IN_GOMP_TASKGROUP_END, BUILT_IN_GOMP_PARALLEL_LOOP_STATIC,
	BUILT_IN_GOMP_PARALLEL_LOOP_DYNAMIC,
	BUILT_IN_GOMP_PARALLEL_LOOP_GUIDED,
	BUILT_IN_GOMP_PARALLEL_LOOP_RUNTIME, BUILT_IN_GOMP_PARALLEL,
	BUILT_IN_GOMP_PARALLEL_SECTIONS, BUILT_IN_GOMP_CANCEL,
	BUILT_IN_GOMP_CANCELLATION_POINT): New built-ins.
	(BUILT_IN_GOMP_PARALLEL_LOOP_STATIC_START,
	BUILT_IN_GOMP_PARALLEL_LOOP_DYNAMIC_START,
	BUILT_IN_GOMP_PARALLEL_LOOP_GUIDED_START,
	BUILT_IN_GOMP_PARALLEL_LOOP_RUNTIME_START,
	BUILT_IN_GOMP_PARALLEL_START, BUILT_IN_GOMP_PARALLEL_END,
	BUILT_IN_GOMP_PARALLEL_SECTIONS_START): Remove.
	* tree-inline.c (remap_gimple_stmt, estimate_num_insns):
	Handle GIMPLE_OMP_TARGET, GIMPLE_OMP_TEAMS and GIMPLE_OMP_TASKGROUP.
	* gimple.c (gimple_build_omp_taskgroup, gimple_build_omp_target,
	gimple_build_omp_teams): New functions.
	(walk_gimple_op): Handle GIMPLE_OMP_TARGET, GIMPLE_OMP_TEAMS and
	GIMPLE_OMP_TASKGROUP.  Walk optional lhs on GIMPLE_OMP_RETURN.
	(walk_gimple_stmt, gimple_copy): Handle GIMPLE_OMP_TARGET,
	GIMPLE_OMP_TEAMS and GIMPLE_OMP_TASKGROUP.
	* gimple.h (enum gf_mask): GF_OMP_FOR_KIND_DISTRIBUTE,
	GF_OMP_FOR_COMBINED, GF_OMP_FOR_COMBINED_INTO,
	GF_OMP_TARGET_KIND_MASK, GF_OMP_TARGET_KIND_REGION,
	GF_OMP_TARGET_KIND_DATA, GF_OMP_TARGET_KIND_UPDATE,
	GF_OMP_ATOMIC_SEQ_CST): New.
	(gimple_build_omp_taskgroup, gimple_build_omp_target,
	gimple_build_omp_teams): New prototypes.
	(gimple_has_substatements): Handle GIMPLE_OMP_TARGET,
	GIMPLE_OMP_TEAMS and GIMPLE_OMP_TASKGROUP.
	(gimple_omp_subcode): Use GIMPLE_OMP_TEAMS instead of
	GIMPLE_OMP_SINGLE as end of range.
	(gimple_omp_return_set_lhs, gimple_omp_return_lhs,
	gimple_omp_return_lhs_ptr, gimple_omp_atomic_seq_cst_p,
	gimple_omp_atomic_set_seq_cst, gimple_omp_for_combined_p,
	gimple_omp_for_set_combined_p, gimple_omp_for_combined_into_p,
	gimple_omp_for_set_combined_into_p, gimple_omp_target_clauses,
	gimple_omp_target_clauses_ptr, gimple_omp_target_set_clauses,
	gimple_omp_target_kind, gimple_omp_target_set_kind,
	gimple_omp_target_child_fn, gimple_omp_target_child_fn_ptr,
	gimple_omp_target_set_child_fn, gimple_omp_target_data_arg,
	gimple_omp_target_data_arg_ptr, gimple_omp_target_set_data_arg,
	gimple_omp_teams_clauses, gimple_omp_teams_clauses_ptr,
	gimple_omp_teams_set_clauses): New inlines.
	(CASE_GIMPLE_OMP): Add GIMPLE_OMP_TARGET, GIMPLE_OMP_TEAMS
	and GIMPLE_OMP_TASKGROUP.
	* tree-core.h (enum omp_clause_code): Add new OpenMP 4.0 clause
	codes.
	(enum omp_clause_depend_kind, enum omp_clause_map_kind,
	enum omp_clause_proc_bind_kind): New.
	(union omp_clause_subcode): Add depend_kind, map_kind and
	proc_bind_kind fields.
	* tree-cfg.c (make_edges): Handle GIMPLE_OMP_TARGET,
	GIMPLE_OMP_TEAMS and GIMPLE_OMP_TASKGROUP.
	* langhooks-def.h (lhd_omp_mappable_type): New prototype.
	(LANG_HOOKS_OMP_MAPPABLE_TYPE): Define.
	(LANG_HOOKS_FOR_TYPES_INITIALIZER): Add it.
gcc/c-family/
	* c-cppbuiltin.c (c_cpp_builtins): Predefine _OPENMP to
	201307 instead of 201107.
	* c-common.c (DEF_FUNCTION_TYPE_8): Define.
	(c_common_attribute_table): Add "omp declare target" and
	"omp declare simd" attributes.
	(handle_omp_declare_target_attribute,
	handle_omp_declare_simd_attribute): New functions.
	* c-omp.c: Include c-pragma.h.
	(c_finish_omp_taskgroup): New function.
	(c_finish_omp_atomic): Add swapped argument, if true,
	build the operation first with rhs, lhs arguments and use NOP_EXPR
	build_modify_expr.
	(c_finish_omp_for): Add code argument, pass it down to make_code.
	(c_omp_split_clauses): New function.
	(c_split_parallel_clauses): Removed.
	(c_omp_declare_simd_clause_cmp, c_omp_declare_simd_clauses_to_numbers,
	c_omp_declare_simd_clauses_to_decls): New functions.
	* c-common.h (omp_clause_mask): New type.
	(OMP_CLAUSE_MASK_1): Define.
	(omp_clause_mask::omp_clause_mask, omp_clause_mask::operator &=,
	omp_clause_mask::operator |=, omp_clause_mask::operator ~,
	omp_clause_mask::operator |, omp_clause_mask::operator &,
	omp_clause_mask::operator <<, omp_clause_mask::operator >>,
	omp_clause_mask::operator ==): New methods.
	(enum c_omp_clause_split): New.
	(c_finish_omp_taskgroup): New prototype.
	(c_finish_omp_atomic): Add swapped argument.
	(c_finish_omp_for): Add code argument.
	(c_omp_split_clauses): New prototype.
	(c_split_parallel_clauses): Removed.
	(c_omp_declare_simd_clauses_to_numbers,
	c_omp_declare_simd_clauses_to_decls): New prototypes.
	* c-pragma.c (omp_pragmas): Add new OpenMP 4.0 constructs.
	* c-pragma.h (enum pragma_kind): Add PRAGMA_OMP_CANCEL,
	PRAGMA_OMP_CANCELLATION_POINT, PRAGMA_OMP_DECLARE_REDUCTION,
	PRAGMA_OMP_DISTRIBUTE, PRAGMA_OMP_END_DECLARE_TARGET, PRAGMA_OMP_SIMD,
	PRAGMA_OMP_TARGET, PRAGMA_OMP_TASKGROUP and PRAGMA_OMP_TEAMS.
	Remove PRAGMA_OMP_PARALLEL_FOR and PRAGMA_OMP_PARALLEL_SECTIONS.
	(enum pragma_omp_clause): Add PRAGMA_OMP_CLAUSE_ALIGNED,
	PRAGMA_OMP_CLAUSE_DEPEND, PRAGMA_OMP_CLAUSE_DEVICE,
	PRAGMA_OMP_CLAUSE_DIST_SCHEDULE, PRAGMA_OMP_CLAUSE_FOR,
	PRAGMA_OMP_CLAUSE_FROM, PRAGMA_OMP_CLAUSE_INBRANCH,
	PRAGMA_OMP_CLAUSE_LINEAR, PRAGMA_OMP_CLAUSE_MAP,
	PRAGMA_OMP_CLAUSE_NOTINBRANCH, PRAGMA_OMP_CLAUSE_NUM_TEAMS,
	PRAGMA_OMP_CLAUSE_PARALLEL, PRAGMA_OMP_CLAUSE_PROC_BIND,
	PRAGMA_OMP_CLAUSE_SAFELEN, PRAGMA_OMP_CLAUSE_SECTIONS,
	PRAGMA_OMP_CLAUSE_SIMDLEN, PRAGMA_OMP_CLAUSE_TASKGROUP,
	PRAGMA_OMP_CLAUSE_THREAD_LIMIT, PRAGMA_OMP_CLAUSE_TO and
	PRAGMA_OMP_CLAUSE_UNIFORM.
gcc/ada/
	* gcc-interface/utils.c (DEF_FUNCTION_TYPE_8): Define.
gcc/fortran/
	* trans-openmp.c (gfc_omp_clause_default_ctor,
	gfc_omp_clause_dtor): Return NULL for OMP_CLAUSE_REDUCTION.
	* f95-lang.c (ATTR_NULL, DEF_FUNCTION_TYPE_8): Define.
	* types.def (DEF_FUNCTION_TYPE_8): Document.
	(BT_FN_VOID_OMPFN_PTR_UINT,
	BT_FN_VOID_OMPFN_PTR_UINT_LONG_LONG_LONG,
	BT_FN_VOID_OMPFN_PTR_UINT_LONG_LONG_LONG_LONG,
	BT_FN_VOID_OMPFN_PTR_OMPCPYFN_LONG_LONG_BOOL_UINT): Remove.
	(BT_FN_VOID_OMPFN_PTR_UINT_UINT_UINT,
	BT_FN_VOID_OMPFN_PTR_UINT_LONG_LONG_LONG_UINT,
	BT_FN_VOID_OMPFN_PTR_UINT_LONG_LONG_LONG_LONG_UINT,
	BT_FN_BOOL_INT, BT_FN_BOOL_INT_BOOL, BT_FN_VOID_UINT_UINT,
	BT_FN_VOID_INT_PTR_SIZE_PTR_PTR_PTR,
	BT_FN_VOID_INT_OMPFN_PTR_SIZE_PTR_PTR_PTR,
	BT_FN_VOID_OMPFN_PTR_OMPCPYFN_LONG_LONG_BOOL_UINT_PTR): New.
gcc/lto/
	* lto-lang.c (DEF_FUNCTION_TYPE_8): Define.

--- gcc/ada/gcc-interface/utils.c	(.../trunk)	(revision 203241)
+++ gcc/ada/gcc-interface/utils.c	(.../branches/gomp-4_0-branch)	(revision 203287)
@@ -5765,6 +5765,7 @@ enum c_builtin_type
 #define DEF_FUNCTION_TYPE_5(NAME, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5) NAME,
 #define DEF_FUNCTION_TYPE_6(NAME, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5, ARG6) NAME,
 #define DEF_FUNCTION_TYPE_7(NAME, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5, ARG6, ARG7) NAME,
+#define DEF_FUNCTION_TYPE_8(NAME, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5, ARG6, ARG7, ARG8) NAME,
 #define DEF_FUNCTION_TYPE_VAR_0(NAME, RETURN) NAME,
 #define DEF_FUNCTION_TYPE_VAR_1(NAME, RETURN, ARG1) NAME,
 #define DEF_FUNCTION_TYPE_VAR_2(NAME, RETURN, ARG1, ARG2) NAME,
@@ -5783,6 +5784,7 @@ enum c_builtin_type
 #undef DEF_FUNCTION_TYPE_5
 #undef DEF_FUNCTION_TYPE_6
 #undef DEF_FUNCTION_TYPE_7
+#undef DEF_FUNCTION_TYPE_8
 #undef DEF_FUNCTION_TYPE_VAR_0
 #undef DEF_FUNCTION_TYPE_VAR_1
 #undef DEF_FUNCTION_TYPE_VAR_2
@@ -5878,6 +5880,10 @@ install_builtin_function_types (void)
 #define DEF_FUNCTION_TYPE_7(ENUM, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5, \
 			    ARG6, ARG7)					\
   def_fn_type (ENUM, RETURN, 0, 7, ARG1, ARG2, ARG3, ARG4, ARG5, ARG6, ARG7);
+#define DEF_FUNCTION_TYPE_8(ENUM, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5, \
+			    ARG6, ARG7, ARG8)				\
+  def_fn_type (ENUM, RETURN, 0, 8, ARG1, ARG2, ARG3, ARG4, ARG5, ARG6,	\
+	       ARG7, ARG8);
 #define DEF_FUNCTION_TYPE_VAR_0(ENUM, RETURN) \
   def_fn_type (ENUM, RETURN, 1, 0);
 #define DEF_FUNCTION_TYPE_VAR_1(ENUM, RETURN, ARG1) \
--- gcc/builtin-types.def	(.../trunk)	(revision 203241)
+++ gcc/builtin-types.def	(.../branches/gomp-4_0-branch)	(revision 203287)
@@ -34,6 +34,8 @@ along with GCC; see the file COPYING3.
    DEF_FUNCTION_TYPE_5 (ENUM, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5)
    DEF_FUNCTION_TYPE_6 (ENUM, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5, ARG6)
    DEF_FUNCTION_TYPE_7 (ENUM, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5, ARG6, ARG7)
+   DEF_FUNCTION_TYPE_8 (ENUM, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5, ARG6, ARG7,
+			ARG8)
 
      These macros describe function types.  ENUM is as above.  The
      RETURN type is one of the enumerals already defined.  ARG1, ARG2,
@@ -230,6 +232,7 @@ DEF_FUNCTION_TYPE_1 (BT_FN_ULONGLONG_ULO
 DEF_FUNCTION_TYPE_1 (BT_FN_UINT16_UINT16, BT_UINT16, BT_UINT16)
 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_BOOL_INT, BT_BOOL, BT_INT)
 
 DEF_POINTER_TYPE (BT_PTR_FN_VOID_PTR, BT_FN_VOID_PTR)
 
@@ -341,6 +344,8 @@ DEF_FUNCTION_TYPE_2 (BT_FN_VOID_VPTR_INT
 DEF_FUNCTION_TYPE_2 (BT_FN_BOOL_VPTR_INT, BT_BOOL, BT_VOLATILE_PTR, BT_INT)
 DEF_FUNCTION_TYPE_2 (BT_FN_BOOL_SIZE_CONST_VPTR, BT_BOOL, BT_SIZE,
 		     BT_CONST_VOLATILE_PTR)
+DEF_FUNCTION_TYPE_2 (BT_FN_BOOL_INT_BOOL, BT_BOOL, BT_INT, BT_BOOL)
+DEF_FUNCTION_TYPE_2 (BT_FN_VOID_UINT_UINT, BT_VOID, BT_UINT, BT_UINT)
 
 DEF_POINTER_TYPE (BT_PTR_FN_VOID_PTR_PTR, BT_FN_VOID_PTR_PTR)
 
@@ -411,8 +416,6 @@ DEF_FUNCTION_TYPE_3 (BT_FN_I4_VPTR_I4_I4
 DEF_FUNCTION_TYPE_3 (BT_FN_I8_VPTR_I8_I8, BT_I8, BT_VOLATILE_PTR, BT_I8, BT_I8)
 DEF_FUNCTION_TYPE_3 (BT_FN_I16_VPTR_I16_I16, BT_I16, BT_VOLATILE_PTR,
 		     BT_I16, BT_I16)
-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_I1_VPTR_I1_INT, BT_I1, BT_VOLATILE_PTR, BT_I1, BT_INT)
@@ -467,6 +470,9 @@ DEF_FUNCTION_TYPE_5 (BT_FN_BOOL_VPTR_PTR
 		     BT_BOOL, BT_VOLATILE_PTR, BT_PTR, BT_I8, BT_INT, BT_INT)
 DEF_FUNCTION_TYPE_5 (BT_FN_BOOL_VPTR_PTR_I16_INT_INT,
 		     BT_BOOL, BT_VOLATILE_PTR, BT_PTR, BT_I16, BT_INT, BT_INT)
+DEF_FUNCTION_TYPE_5 (BT_FN_VOID_OMPFN_PTR_UINT_UINT_UINT,
+		     BT_VOID, BT_PTR_FN_VOID_PTR, BT_PTR, BT_UINT, BT_UINT,
+		     BT_UINT)
 
 DEF_FUNCTION_TYPE_6 (BT_FN_INT_STRING_SIZE_INT_SIZE_CONST_STRING_VALIST_ARG,
 		     BT_INT, BT_STRING, BT_SIZE, BT_INT, BT_SIZE,
@@ -474,9 +480,6 @@ DEF_FUNCTION_TYPE_6 (BT_FN_INT_STRING_SI
 DEF_FUNCTION_TYPE_6 (BT_FN_BOOL_LONG_LONG_LONG_LONG_LONGPTR_LONGPTR,
 		     BT_BOOL, BT_LONG, BT_LONG, BT_LONG, BT_LONG,
 		     BT_PTR_LONG, BT_PTR_LONG)
-DEF_FUNCTION_TYPE_6 (BT_FN_VOID_OMPFN_PTR_UINT_LONG_LONG_LONG,
-		     BT_VOID, BT_PTR_FN_VOID_PTR, BT_PTR, BT_UINT,
-		     BT_LONG, BT_LONG, BT_LONG)
 DEF_FUNCTION_TYPE_6 (BT_FN_BOOL_BOOL_ULL_ULL_ULL_ULLPTR_ULLPTR,
 		     BT_BOOL, BT_BOOL, BT_ULONGLONG, BT_ULONGLONG,
 		     BT_ULONGLONG, BT_PTR_ULONGLONG, BT_PTR_ULONGLONG)
@@ -497,19 +500,27 @@ DEF_FUNCTION_TYPE_6 (BT_FN_BOOL_VPTR_PTR
 		     BT_INT)
 DEF_FUNCTION_TYPE_6 (BT_FN_BOOL_SIZE_VPTR_PTR_PTR_INT_INT, BT_BOOL, BT_SIZE,
 		     BT_VOLATILE_PTR, BT_PTR, BT_PTR, BT_INT, BT_INT)
+DEF_FUNCTION_TYPE_6 (BT_FN_VOID_INT_PTR_SIZE_PTR_PTR_PTR,
+		     BT_VOID, BT_INT, BT_PTR, BT_SIZE, BT_PTR, BT_PTR, BT_PTR)
 
-
-DEF_FUNCTION_TYPE_7 (BT_FN_VOID_OMPFN_PTR_UINT_LONG_LONG_LONG_LONG,
+DEF_FUNCTION_TYPE_7 (BT_FN_VOID_OMPFN_PTR_UINT_LONG_LONG_LONG_UINT,
 		     BT_VOID, BT_PTR_FN_VOID_PTR, BT_PTR, BT_UINT,
-		     BT_LONG, BT_LONG, BT_LONG, BT_LONG)
-DEF_FUNCTION_TYPE_7 (BT_FN_VOID_OMPFN_PTR_OMPCPYFN_LONG_LONG_BOOL_UINT,
-		     BT_VOID, BT_PTR_FN_VOID_PTR, BT_PTR,
-		     BT_PTR_FN_VOID_PTR_PTR, BT_LONG, BT_LONG,
-		     BT_BOOL, BT_UINT)
+		     BT_LONG, BT_LONG, BT_LONG, BT_UINT)
 DEF_FUNCTION_TYPE_7 (BT_FN_BOOL_BOOL_ULL_ULL_ULL_ULL_ULLPTR_ULLPTR,
 		     BT_BOOL, BT_BOOL, BT_ULONGLONG, BT_ULONGLONG,
 		     BT_ULONGLONG, BT_ULONGLONG,
 		     BT_PTR_ULONGLONG, BT_PTR_ULONGLONG)
+DEF_FUNCTION_TYPE_7 (BT_FN_VOID_INT_OMPFN_PTR_SIZE_PTR_PTR_PTR,
+		     BT_VOID, BT_INT, BT_PTR_FN_VOID_PTR, BT_PTR, BT_SIZE,
+		     BT_PTR, BT_PTR, BT_PTR)
+
+DEF_FUNCTION_TYPE_8 (BT_FN_VOID_OMPFN_PTR_UINT_LONG_LONG_LONG_LONG_UINT,
+		     BT_VOID, BT_PTR_FN_VOID_PTR, BT_PTR, BT_UINT,
+		     BT_LONG, BT_LONG, BT_LONG, BT_LONG, BT_UINT)
+DEF_FUNCTION_TYPE_8 (BT_FN_VOID_OMPFN_PTR_OMPCPYFN_LONG_LONG_BOOL_UINT_PTR,
+		     BT_VOID, BT_PTR_FN_VOID_PTR, BT_PTR,
+		     BT_PTR_FN_VOID_PTR_PTR, BT_LONG, BT_LONG,
+		     BT_BOOL, BT_UINT, BT_PTR)
 
 DEF_FUNCTION_TYPE_VAR_0 (BT_FN_VOID_VAR, BT_VOID)
 DEF_FUNCTION_TYPE_VAR_0 (BT_FN_INT_VAR, BT_INT)
--- gcc/c-family/c-common.c	(.../trunk)	(revision 203241)
+++ gcc/c-family/c-common.c	(.../branches/gomp-4_0-branch)	(revision 203287)
@@ -371,6 +371,10 @@ static tree ignore_attribute (tree *, tr
 static tree handle_no_split_stack_attribute (tree *, tree, tree, int, bool *);
 static tree handle_fnspec_attribute (tree *, tree, tree, int, bool *);
 static tree handle_warn_unused_attribute (tree *, tree, tree, int, bool *);
+static tree handle_omp_declare_simd_attribute (tree *, tree, tree, int,
+					       bool *);
+static tree handle_omp_declare_target_attribute (tree *, tree, tree, int,
+						 bool *);
 
 static void check_function_nonnull (tree, int, tree *);
 static void check_nonnull_arg (void *, tree, unsigned HOST_WIDE_INT);
@@ -747,6 +751,10 @@ const struct attribute_spec c_common_att
 			      handle_fnspec_attribute, false },
   { "warn_unused",            0, 0, false, false, false,
 			      handle_warn_unused_attribute, false },
+  { "omp declare simd",       0, -1, true,  false, false,
+			      handle_omp_declare_simd_attribute, false },
+  { "omp declare target",     0, 0, true, false, false,
+			      handle_omp_declare_target_attribute, false },
   { NULL,                     0, 0, false, false, false, NULL, false }
 };
 
@@ -5054,6 +5062,7 @@ enum c_builtin_type
 #define DEF_FUNCTION_TYPE_5(NAME, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5) NAME,
 #define DEF_FUNCTION_TYPE_6(NAME, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5, ARG6) NAME,
 #define DEF_FUNCTION_TYPE_7(NAME, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5, ARG6, ARG7) NAME,
+#define DEF_FUNCTION_TYPE_8(NAME, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5, ARG6, ARG7, ARG8) NAME,
 #define DEF_FUNCTION_TYPE_VAR_0(NAME, RETURN) NAME,
 #define DEF_FUNCTION_TYPE_VAR_1(NAME, RETURN, ARG1) NAME,
 #define DEF_FUNCTION_TYPE_VAR_2(NAME, RETURN, ARG1, ARG2) NAME,
@@ -5072,6 +5081,7 @@ enum c_builtin_type
 #undef DEF_FUNCTION_TYPE_5
 #undef DEF_FUNCTION_TYPE_6
 #undef DEF_FUNCTION_TYPE_7
+#undef DEF_FUNCTION_TYPE_8
 #undef DEF_FUNCTION_TYPE_VAR_0
 #undef DEF_FUNCTION_TYPE_VAR_1
 #undef DEF_FUNCTION_TYPE_VAR_2
@@ -5154,6 +5164,10 @@ c_define_builtins (tree va_list_ref_type
 #define DEF_FUNCTION_TYPE_7(ENUM, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5, \
 			    ARG6, ARG7)					\
   def_fn_type (ENUM, RETURN, 0, 7, ARG1, ARG2, ARG3, ARG4, ARG5, ARG6, ARG7);
+#define DEF_FUNCTION_TYPE_8(ENUM, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5, \
+			    ARG6, ARG7, ARG8)				\
+  def_fn_type (ENUM, RETURN, 0, 8, ARG1, ARG2, ARG3, ARG4, ARG5, ARG6,	\
+	       ARG7, ARG8);
 #define DEF_FUNCTION_TYPE_VAR_0(ENUM, RETURN) \
   def_fn_type (ENUM, RETURN, 1, 0);
 #define DEF_FUNCTION_TYPE_VAR_1(ENUM, RETURN, ARG1) \
@@ -8021,6 +8035,24 @@ handle_warn_unused_attribute (tree *node
   return NULL_TREE;
 }
 
+/* Handle an "omp declare simd" attribute; arguments as in
+   struct attribute_spec.handler.  */
+
+static tree
+handle_omp_declare_simd_attribute (tree *, tree, tree, int, bool *)
+{
+  return NULL_TREE;
+}
+
+/* Handle an "omp declare target" attribute; arguments as in
+   struct attribute_spec.handler.  */
+
+static tree
+handle_omp_declare_target_attribute (tree *, tree, tree, int, bool *)
+{
+  return NULL_TREE;
+}
+
 /* Handle a "returns_twice" attribute; arguments as in
    struct attribute_spec.handler.  */
 
--- gcc/c-family/c-common.h	(.../trunk)	(revision 203241)
+++ gcc/c-family/c-common.h	(.../branches/gomp-4_0-branch)	(revision 203287)
@@ -1034,17 +1034,159 @@ extern void pp_dir_change (cpp_reader *,
 extern bool check_missing_format_attribute (tree, tree);
 
 /* In c-omp.c  */
+#if HOST_BITS_PER_WIDE_INT >= 64
+typedef unsigned HOST_WIDE_INT omp_clause_mask;
+# define OMP_CLAUSE_MASK_1 ((omp_clause_mask) 1)
+#else
+struct omp_clause_mask
+{
+  inline omp_clause_mask ();
+  inline omp_clause_mask (unsigned HOST_WIDE_INT l);
+  inline omp_clause_mask (unsigned HOST_WIDE_INT l,
+			  unsigned HOST_WIDE_INT h);
+  inline omp_clause_mask &operator &= (omp_clause_mask);
+  inline omp_clause_mask &operator |= (omp_clause_mask);
+  inline omp_clause_mask operator ~ () const;
+  inline omp_clause_mask operator & (omp_clause_mask) const;
+  inline omp_clause_mask operator | (omp_clause_mask) const;
+  inline omp_clause_mask operator >> (int);
+  inline omp_clause_mask operator << (int);
+  inline bool operator == (omp_clause_mask) const;
+  unsigned HOST_WIDE_INT low, high;
+};
+
+inline
+omp_clause_mask::omp_clause_mask ()
+{
+}
+
+inline
+omp_clause_mask::omp_clause_mask (unsigned HOST_WIDE_INT l)
+: low (l), high (0)
+{
+}
+
+inline
+omp_clause_mask::omp_clause_mask (unsigned HOST_WIDE_INT l,
+				  unsigned HOST_WIDE_INT h)
+: low (l), high (h)
+{
+}
+
+inline omp_clause_mask &
+omp_clause_mask::operator &= (omp_clause_mask b)
+{
+  low &= b.low;
+  high &= b.high;
+  return *this;
+}
+
+inline omp_clause_mask &
+omp_clause_mask::operator |= (omp_clause_mask b)
+{
+  low |= b.low;
+  high |= b.high;
+  return *this;
+}
+
+inline omp_clause_mask
+omp_clause_mask::operator ~ () const
+{
+  omp_clause_mask ret (~low, ~high);
+  return ret;
+}
+
+inline omp_clause_mask
+omp_clause_mask::operator | (omp_clause_mask b) const
+{
+  omp_clause_mask ret (low | b.low, high | b.high);
+  return ret;
+}
+
+inline omp_clause_mask
+omp_clause_mask::operator & (omp_clause_mask b) const
+{
+  omp_clause_mask ret (low & b.low, high & b.high);
+  return ret;
+}
+
+inline omp_clause_mask
+omp_clause_mask::operator << (int amount)
+{
+  omp_clause_mask ret;
+  if (amount >= HOST_BITS_PER_WIDE_INT)
+    {
+      ret.low = 0;
+      ret.high = low << (amount - HOST_BITS_PER_WIDE_INT);
+    }
+  else if (amount == 0)
+    ret = *this;
+  else
+    {
+      ret.low = low << amount;
+      ret.high = (low >> (HOST_BITS_PER_WIDE_INT - amount))
+		 | (high << amount);
+    }
+  return ret;
+}
+
+inline omp_clause_mask
+omp_clause_mask::operator >> (int amount)
+{
+  omp_clause_mask ret;
+  if (amount >= HOST_BITS_PER_WIDE_INT)
+    {
+      ret.low = high >> (amount - HOST_BITS_PER_WIDE_INT);
+      ret.high = 0;
+    }
+  else if (amount == 0)
+    ret = *this;
+  else
+    {
+      ret.low = (high << (HOST_BITS_PER_WIDE_INT - amount))
+		 | (low >> amount);
+      ret.high = high >> amount;
+    }
+  return ret;
+}
+
+inline bool
+omp_clause_mask::operator == (omp_clause_mask b) const
+{
+  return low == b.low && high == b.high;
+}
+
+# define OMP_CLAUSE_MASK_1 omp_clause_mask (1)
+#endif
+
+enum c_omp_clause_split
+{
+  C_OMP_CLAUSE_SPLIT_TARGET = 0,
+  C_OMP_CLAUSE_SPLIT_TEAMS,
+  C_OMP_CLAUSE_SPLIT_DISTRIBUTE,
+  C_OMP_CLAUSE_SPLIT_PARALLEL,
+  C_OMP_CLAUSE_SPLIT_FOR,
+  C_OMP_CLAUSE_SPLIT_SIMD,
+  C_OMP_CLAUSE_SPLIT_COUNT,
+  C_OMP_CLAUSE_SPLIT_SECTIONS = C_OMP_CLAUSE_SPLIT_FOR
+};
+
 extern tree c_finish_omp_master (location_t, tree);
+extern tree c_finish_omp_taskgroup (location_t, tree);
 extern tree c_finish_omp_critical (location_t, tree, tree);
 extern tree c_finish_omp_ordered (location_t, tree);
 extern void c_finish_omp_barrier (location_t);
 extern tree c_finish_omp_atomic (location_t, enum tree_code, enum tree_code,
-				 tree, tree, tree, tree, tree);
+				 tree, tree, tree, tree, tree, bool, bool);
 extern void c_finish_omp_flush (location_t);
 extern void c_finish_omp_taskwait (location_t);
 extern void c_finish_omp_taskyield (location_t);
-extern tree c_finish_omp_for (location_t, tree, tree, tree, tree, tree, tree);
-extern void c_split_parallel_clauses (location_t, tree, tree *, tree *);
+extern tree c_finish_omp_for (location_t, enum tree_code, tree, tree, tree,
+			      tree, tree, tree);
+extern void c_omp_split_clauses (location_t, enum tree_code, omp_clause_mask,
+				 tree, tree *);
+extern tree c_omp_declare_simd_clauses_to_numbers (tree, tree);
+extern void c_omp_declare_simd_clauses_to_decls (tree, tree);
 extern enum omp_clause_default_kind c_omp_predetermined_sharing (tree);
 
 /* Not in c-omp.c; provided by the front end.  */
--- gcc/c-family/c-cppbuiltin.c	(.../trunk)	(revision 203241)
+++ gcc/c-family/c-cppbuiltin.c	(.../branches/gomp-4_0-branch)	(revision 203287)
@@ -896,7 +896,7 @@ c_cpp_builtins (cpp_reader *pfile)
     cpp_define (pfile, "__SSP__=1");
 
   if (flag_openmp)
-    cpp_define (pfile, "_OPENMP=201107");
+    cpp_define (pfile, "_OPENMP=201307");
 
   if (int128_integer_type_node != NULL_TREE)
     builtin_define_type_sizeof ("__SIZEOF_INT128__",
--- gcc/c-family/c-omp.c	(.../trunk)	(revision 203241)
+++ gcc/c-family/c-omp.c	(.../branches/gomp-4_0-branch)	(revision 203287)
@@ -26,6 +26,7 @@ along with GCC; see the file COPYING3.
 #include "coretypes.h"
 #include "tree.h"
 #include "c-common.h"
+#include "c-pragma.h"
 #include "gimple.h"		/* For create_tmp_var_raw.  */
 #include "langhooks.h"
 
@@ -41,6 +42,17 @@ c_finish_omp_master (location_t loc, tre
   return t;
 }
 
+/* Complete a #pragma omp taskgroup construct.  STMT is the structured-block
+   that follows the pragma.  LOC is the l*/
+
+tree
+c_finish_omp_taskgroup (location_t loc, tree stmt)
+{
+  tree t = add_stmt (build1 (OMP_TASKGROUP, void_type_node, stmt));
+  SET_EXPR_LOCATION (t, loc);
+  return t;
+}
+
 /* Complete a #pragma omp critical construct.  STMT is the structured-block
    that follows the pragma, NAME is the identifier in the pragma, or null
    if it was omitted.  LOC is the location of the #pragma.  */
@@ -122,7 +134,7 @@ c_finish_omp_taskyield (location_t loc)
 tree
 c_finish_omp_atomic (location_t loc, enum tree_code code,
 		     enum tree_code opcode, tree lhs, tree rhs,
-		     tree v, tree lhs1, tree rhs1)
+		     tree v, tree lhs1, tree rhs1, bool swapped, bool seq_cst)
 {
   tree x, type, addr;
 
@@ -168,6 +180,7 @@ c_finish_omp_atomic (location_t loc, enu
     {
       x = build1 (OMP_ATOMIC_READ, type, addr);
       SET_EXPR_LOCATION (x, loc);
+      OMP_ATOMIC_SEQ_CST (x) = seq_cst;
       return build_modify_expr (loc, v, NULL_TREE, NOP_EXPR,
 				loc, x, NULL_TREE);
       return x;
@@ -176,8 +189,12 @@ c_finish_omp_atomic (location_t loc, enu
   /* There are lots of warnings, errors, and conversions that need to happen
      in the course of interpreting a statement.  Use the normal mechanisms
      to do this, and then take it apart again.  */
-  x = build_modify_expr (input_location, lhs, NULL_TREE, opcode,
-      			 input_location, rhs, NULL_TREE);
+  if (swapped)
+    {
+      rhs = build2_loc (loc, opcode, TREE_TYPE (lhs), rhs, lhs);
+      opcode = NOP_EXPR;
+    }
+  x = build_modify_expr (loc, lhs, NULL_TREE, opcode, loc, rhs, NULL_TREE);
   if (x == error_mark_node)
     return error_mark_node;
   gcc_assert (TREE_CODE (x) == MODIFY_EXPR);
@@ -188,6 +205,7 @@ c_finish_omp_atomic (location_t loc, enu
     type = void_type_node;
   x = build2 (code, type, addr, rhs);
   SET_EXPR_LOCATION (x, loc);
+  OMP_ATOMIC_SEQ_CST (x) = seq_cst;
 
   /* Generally it is hard to prove lhs1 and lhs are the same memory
      location, just diagnose different variables.  */
@@ -339,8 +357,8 @@ check_omp_for_incr_expr (location_t loc,
    the loop.  */
 
 tree
-c_finish_omp_for (location_t locus, tree declv, tree initv, tree condv,
-		  tree incrv, tree body, tree pre_body)
+c_finish_omp_for (location_t locus, enum tree_code code, tree declv,
+		  tree initv, tree condv, tree incrv, tree body, tree pre_body)
 {
   location_t elocus;
   bool fail = false;
@@ -565,7 +583,7 @@ c_finish_omp_for (location_t locus, tree
     return NULL;
   else
     {
-      tree t = make_node (OMP_FOR);
+      tree t = make_node (code);
 
       TREE_TYPE (t) = void_type_node;
       OMP_FOR_INIT (t) = initv;
@@ -579,21 +597,55 @@ c_finish_omp_for (location_t locus, tree
     }
 }
 
-
-/* Divide CLAUSES into two lists: those that apply to a parallel
-   construct, and those that apply to a work-sharing construct.  Place
-   the results in *PAR_CLAUSES and *WS_CLAUSES respectively.  In
-   addition, add a nowait clause to the work-sharing list.  LOC is the
-   location of the OMP_PARALLEL*.  */
+/* Right now we have 14 different combined constructs, this
+   function attempts to split or duplicate clauses for combined
+   constructs.  CODE is the innermost construct in the combined construct,
+   and MASK allows to determine which constructs are combined together,
+   as every construct has at least one clause that no other construct
+   has (except for OMP_SECTIONS, but that can be only combined with parallel).
+   Combined constructs are:
+   #pragma omp parallel for
+   #pragma omp parallel sections
+   #pragma omp parallel for simd
+   #pragma omp for simd
+   #pragma omp distribute simd
+   #pragma omp distribute parallel for
+   #pragma omp distribute parallel for simd
+   #pragma omp teams distribute
+   #pragma omp teams distribute parallel for
+   #pragma omp teams distribute parallel for simd
+   #pragma omp target teams
+   #pragma omp target teams distribute
+   #pragma omp target teams distribute parallel for
+   #pragma omp target teams distribute parallel for simd  */
 
 void
-c_split_parallel_clauses (location_t loc, tree clauses,
-			  tree *par_clauses, tree *ws_clauses)
+c_omp_split_clauses (location_t loc, enum tree_code code,
+		     omp_clause_mask mask, tree clauses, tree *cclauses)
 {
-  tree next;
+  tree next, c;
+  enum c_omp_clause_split s;
+  int i;
 
-  *par_clauses = NULL;
-  *ws_clauses = build_omp_clause (loc, OMP_CLAUSE_NOWAIT);
+  for (i = 0; i < C_OMP_CLAUSE_SPLIT_COUNT; i++)
+    cclauses[i] = NULL;
+  /* Add implicit nowait clause on
+     #pragma omp parallel {for,for simd,sections}.  */
+  if (mask & (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_NUM_THREADS))
+    switch (code)
+      {
+      case OMP_FOR:
+      case OMP_SIMD:
+        cclauses[C_OMP_CLAUSE_SPLIT_FOR]
+	  = build_omp_clause (loc, OMP_CLAUSE_NOWAIT);
+	break;
+      case OMP_SECTIONS:
+	cclauses[C_OMP_CLAUSE_SPLIT_SECTIONS]
+	  = build_omp_clause (loc, OMP_CLAUSE_NOWAIT);
+	break;
+      default:
+	break;
+      }
 
   for (; clauses ; clauses = next)
     {
@@ -601,32 +653,326 @@ c_split_parallel_clauses (location_t loc
 
       switch (OMP_CLAUSE_CODE (clauses))
 	{
-	case OMP_CLAUSE_PRIVATE:
-	case OMP_CLAUSE_SHARED:
-	case OMP_CLAUSE_FIRSTPRIVATE:
-	case OMP_CLAUSE_LASTPRIVATE:
-	case OMP_CLAUSE_REDUCTION:
+	/* First the clauses that are unique to some constructs.  */
+	case OMP_CLAUSE_DEVICE:
+	case OMP_CLAUSE_MAP:
+	  s = C_OMP_CLAUSE_SPLIT_TARGET;
+	  break;
+	case OMP_CLAUSE_NUM_TEAMS:
+	case OMP_CLAUSE_THREAD_LIMIT:
+	  s = C_OMP_CLAUSE_SPLIT_TEAMS;
+	  break;
+	case OMP_CLAUSE_DIST_SCHEDULE:
+	  s = C_OMP_CLAUSE_SPLIT_DISTRIBUTE;
+	  break;
 	case OMP_CLAUSE_COPYIN:
-	case OMP_CLAUSE_IF:
 	case OMP_CLAUSE_NUM_THREADS:
-	case OMP_CLAUSE_DEFAULT:
-	  OMP_CLAUSE_CHAIN (clauses) = *par_clauses;
-	  *par_clauses = clauses;
+	case OMP_CLAUSE_PROC_BIND:
+	  s = C_OMP_CLAUSE_SPLIT_PARALLEL;
 	  break;
-
-	case OMP_CLAUSE_SCHEDULE:
 	case OMP_CLAUSE_ORDERED:
+	case OMP_CLAUSE_SCHEDULE:
+	case OMP_CLAUSE_NOWAIT:
+	  s = C_OMP_CLAUSE_SPLIT_FOR;
+	  break;
+	case OMP_CLAUSE_SAFELEN:
+	case OMP_CLAUSE_LINEAR:
+	case OMP_CLAUSE_ALIGNED:
+	  s = C_OMP_CLAUSE_SPLIT_SIMD;
+	  break;
+	/* Duplicate this to all of distribute, for and simd.  */
 	case OMP_CLAUSE_COLLAPSE:
-	  OMP_CLAUSE_CHAIN (clauses) = *ws_clauses;
-	  *ws_clauses = clauses;
+	  if (code == OMP_SIMD)
+	    {
+	      c = build_omp_clause (OMP_CLAUSE_LOCATION (clauses),
+				    OMP_CLAUSE_COLLAPSE);
+	      OMP_CLAUSE_COLLAPSE_EXPR (c)
+		= OMP_CLAUSE_COLLAPSE_EXPR (clauses);
+	      OMP_CLAUSE_CHAIN (c) = cclauses[C_OMP_CLAUSE_SPLIT_SIMD];
+	      cclauses[C_OMP_CLAUSE_SPLIT_SIMD] = c;
+	    }
+	  if (mask & (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_SCHEDULE))
+	    {
+	      if (mask & (OMP_CLAUSE_MASK_1
+			  << PRAGMA_OMP_CLAUSE_DIST_SCHEDULE))
+		{
+		  c = build_omp_clause (OMP_CLAUSE_LOCATION (clauses),
+					OMP_CLAUSE_COLLAPSE);
+		  OMP_CLAUSE_COLLAPSE_EXPR (c)
+		    = OMP_CLAUSE_COLLAPSE_EXPR (clauses);
+		  OMP_CLAUSE_CHAIN (c) = cclauses[C_OMP_CLAUSE_SPLIT_FOR];
+		  cclauses[C_OMP_CLAUSE_SPLIT_FOR] = c;
+		  s = C_OMP_CLAUSE_SPLIT_DISTRIBUTE;
+		}
+	      else
+		s = C_OMP_CLAUSE_SPLIT_FOR;
+	    }
+	  else
+	    s = C_OMP_CLAUSE_SPLIT_DISTRIBUTE;
+	  break;
+	/* Private clause is supported on all constructs but target,
+	   it is enough to put it on the innermost one.  For
+	   #pragma omp {for,sections} put it on parallel though,
+	   as that's what we did for OpenMP 3.1.  */
+	case OMP_CLAUSE_PRIVATE:
+	  switch (code)
+	    {
+	    case OMP_SIMD: s = C_OMP_CLAUSE_SPLIT_SIMD; break;
+	    case OMP_FOR: case OMP_SECTIONS:
+	    case OMP_PARALLEL: s = C_OMP_CLAUSE_SPLIT_PARALLEL; break;
+	    case OMP_DISTRIBUTE: s = C_OMP_CLAUSE_SPLIT_DISTRIBUTE; break;
+	    case OMP_TEAMS: s = C_OMP_CLAUSE_SPLIT_TEAMS; break;
+	    default: gcc_unreachable ();
+	    }
+	  break;
+	/* Firstprivate clause is supported on all constructs but
+	   target and simd.  Put it on the outermost of those and
+	   duplicate on parallel.  */
+	case OMP_CLAUSE_FIRSTPRIVATE:
+	  if (mask & (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_NUM_THREADS))
+	    {
+	      if (mask & ((OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_NUM_TEAMS)
+			  | (OMP_CLAUSE_MASK_1
+			     << PRAGMA_OMP_CLAUSE_DIST_SCHEDULE)))
+		{
+		  c = build_omp_clause (OMP_CLAUSE_LOCATION (clauses),
+					OMP_CLAUSE_FIRSTPRIVATE);
+		  OMP_CLAUSE_DECL (c) = OMP_CLAUSE_DECL (clauses);
+		  OMP_CLAUSE_CHAIN (c) = cclauses[C_OMP_CLAUSE_SPLIT_PARALLEL];
+		  cclauses[C_OMP_CLAUSE_SPLIT_PARALLEL] = c;
+		  if (mask & (OMP_CLAUSE_MASK_1
+			      << PRAGMA_OMP_CLAUSE_NUM_TEAMS))
+		    s = C_OMP_CLAUSE_SPLIT_TEAMS;
+		  else
+		    s = C_OMP_CLAUSE_SPLIT_DISTRIBUTE;
+		}
+	      else
+		/* This must be
+		   #pragma omp parallel{, for{, simd}, sections}.  */
+		s = C_OMP_CLAUSE_SPLIT_PARALLEL;
+	    }
+	  else if (mask & (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_NUM_TEAMS))
+	    {
+	      /* This must be #pragma omp {,target }teams distribute.  */
+	      gcc_assert (code == OMP_DISTRIBUTE);
+	      s = C_OMP_CLAUSE_SPLIT_TEAMS;
+	    }
+	  else if (mask & (OMP_CLAUSE_MASK_1
+			   << PRAGMA_OMP_CLAUSE_DIST_SCHEDULE))
+	    {
+	      /* This must be #pragma omp distribute simd.  */
+	      gcc_assert (code == OMP_SIMD);
+	      s = C_OMP_CLAUSE_SPLIT_TEAMS;
+	    }
+	  else
+	    {
+	      /* This must be #pragma omp for simd.  */
+	      gcc_assert (code == OMP_SIMD);
+	      s = C_OMP_CLAUSE_SPLIT_FOR;
+	    }
+	  break;
+	/* Lastprivate is allowed on for, sections and simd.  In
+	   parallel {for{, simd},sections} we actually want to put it on
+	   parallel rather than for or sections.  */
+	case OMP_CLAUSE_LASTPRIVATE:
+	  if (code == OMP_FOR || code == OMP_SECTIONS)
+	    {
+	      if (mask & (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_NUM_THREADS))
+		s = C_OMP_CLAUSE_SPLIT_PARALLEL;
+	      else
+		s = C_OMP_CLAUSE_SPLIT_FOR;
+	      break;
+	    }
+	  gcc_assert (code == OMP_SIMD);
+	  if (mask & (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_SCHEDULE))
+	    {
+	      c = build_omp_clause (OMP_CLAUSE_LOCATION (clauses),
+				    OMP_CLAUSE_LASTPRIVATE);
+	      OMP_CLAUSE_DECL (c) = OMP_CLAUSE_DECL (clauses);
+	      if (mask & (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_NUM_THREADS))
+		s = C_OMP_CLAUSE_SPLIT_PARALLEL;
+	      else
+		s = C_OMP_CLAUSE_SPLIT_FOR;
+	      OMP_CLAUSE_CHAIN (c) = cclauses[s];
+	      cclauses[s] = c;
+	    }
+	  s = C_OMP_CLAUSE_SPLIT_SIMD;
+	  break;
+	/* Shared and default clauses are allowed on private and teams.  */
+	case OMP_CLAUSE_SHARED:
+	case OMP_CLAUSE_DEFAULT:
+	  if (code == OMP_TEAMS)
+	    {
+	      s = C_OMP_CLAUSE_SPLIT_TEAMS;
+	      break;
+	    }
+	  if (mask & (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_NUM_TEAMS))
+	    {
+	      c = build_omp_clause (OMP_CLAUSE_LOCATION (clauses),
+				    OMP_CLAUSE_CODE (clauses));
+	      if (OMP_CLAUSE_CODE (clauses) == OMP_CLAUSE_SHARED)
+		OMP_CLAUSE_DECL (c) = OMP_CLAUSE_DECL (clauses);
+	      else
+		OMP_CLAUSE_DEFAULT_KIND (c)
+		  = OMP_CLAUSE_DEFAULT_KIND (clauses);
+	      OMP_CLAUSE_CHAIN (c) = cclauses[C_OMP_CLAUSE_SPLIT_TEAMS];
+	      cclauses[C_OMP_CLAUSE_SPLIT_TEAMS] = c;
+	      
+	    }
+	  s = C_OMP_CLAUSE_SPLIT_PARALLEL;
+	  break;
+	/* Reduction is allowed on simd, for, parallel, sections and teams.
+	   Duplicate it on all of them, but omit on for or sections if
+	   parallel is present.  */
+	case OMP_CLAUSE_REDUCTION:
+	  if (code == OMP_SIMD)
+	    {
+	      c = build_omp_clause (OMP_CLAUSE_LOCATION (clauses),
+				    OMP_CLAUSE_REDUCTION);
+	      OMP_CLAUSE_DECL (c) = OMP_CLAUSE_DECL (clauses);
+	      OMP_CLAUSE_REDUCTION_CODE (c)
+		= OMP_CLAUSE_REDUCTION_CODE (clauses);
+	      OMP_CLAUSE_REDUCTION_PLACEHOLDER (c)
+		= OMP_CLAUSE_REDUCTION_PLACEHOLDER (clauses);
+	      OMP_CLAUSE_CHAIN (c) = cclauses[C_OMP_CLAUSE_SPLIT_SIMD];
+	      cclauses[C_OMP_CLAUSE_SPLIT_SIMD] = c;
+	    }
+	  if (mask & (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_SCHEDULE))
+	    {
+	      if (mask & (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_NUM_TEAMS))
+		{
+		  c = build_omp_clause (OMP_CLAUSE_LOCATION (clauses),
+					OMP_CLAUSE_REDUCTION);
+		  OMP_CLAUSE_DECL (c) = OMP_CLAUSE_DECL (clauses);
+		  OMP_CLAUSE_REDUCTION_CODE (c)
+		    = OMP_CLAUSE_REDUCTION_CODE (clauses);
+		  OMP_CLAUSE_REDUCTION_PLACEHOLDER (c)
+		    = OMP_CLAUSE_REDUCTION_PLACEHOLDER (clauses);
+		  OMP_CLAUSE_CHAIN (c) = cclauses[C_OMP_CLAUSE_SPLIT_PARALLEL];
+		  cclauses[C_OMP_CLAUSE_SPLIT_PARALLEL] = c;
+		  s = C_OMP_CLAUSE_SPLIT_TEAMS;
+		}
+	      else if (mask & (OMP_CLAUSE_MASK_1
+			       << PRAGMA_OMP_CLAUSE_NUM_THREADS))
+		s = C_OMP_CLAUSE_SPLIT_PARALLEL;
+	      else
+		s = C_OMP_CLAUSE_SPLIT_FOR;
+	    }
+	  else if (code == OMP_SECTIONS)
+	    s = C_OMP_CLAUSE_SPLIT_PARALLEL;
+	  else
+	    s = C_OMP_CLAUSE_SPLIT_TEAMS;
+	  break;
+	case OMP_CLAUSE_IF:
+	  /* FIXME: This is currently being discussed.  */
+	  if (mask & (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_NUM_THREADS))
+	    s = C_OMP_CLAUSE_SPLIT_PARALLEL;
+	  else
+	    s = C_OMP_CLAUSE_SPLIT_TARGET;
 	  break;
-
 	default:
 	  gcc_unreachable ();
 	}
+      OMP_CLAUSE_CHAIN (clauses) = cclauses[s];
+      cclauses[s] = clauses;
     }
 }
 
+
+/* qsort callback to compare #pragma omp declare simd clauses.  */
+
+static int
+c_omp_declare_simd_clause_cmp (const void *p, const void *q)
+{
+  tree a = *(const tree *) p;
+  tree b = *(const tree *) q;
+  if (OMP_CLAUSE_CODE (a) != OMP_CLAUSE_CODE (b))
+    {
+      if (OMP_CLAUSE_CODE (a) > OMP_CLAUSE_CODE (b))
+	return -1;
+      return 1;
+    }
+  if (OMP_CLAUSE_CODE (a) != OMP_CLAUSE_SIMDLEN
+      && OMP_CLAUSE_CODE (a) != OMP_CLAUSE_INBRANCH
+      && OMP_CLAUSE_CODE (a) != OMP_CLAUSE_NOTINBRANCH)
+    {
+      int c = tree_low_cst (OMP_CLAUSE_DECL (a), 0);
+      int d = tree_low_cst (OMP_CLAUSE_DECL (b), 0);
+      if (c < d)
+	return 1;
+      if (c > d)
+	return -1;
+    }
+  return 0;
+}
+
+/* Change PARM_DECLs in OMP_CLAUSE_DECL of #pragma omp declare simd
+   CLAUSES on FNDECL into argument indexes and sort them.  */
+
+tree
+c_omp_declare_simd_clauses_to_numbers (tree parms, tree clauses)
+{
+  tree c;
+  vec<tree> clvec = vNULL;
+
+  for (c = clauses; c; c = OMP_CLAUSE_CHAIN (c))
+    {
+      if (OMP_CLAUSE_CODE (c) != OMP_CLAUSE_SIMDLEN
+	  && OMP_CLAUSE_CODE (c) != OMP_CLAUSE_INBRANCH
+	  && OMP_CLAUSE_CODE (c) != OMP_CLAUSE_NOTINBRANCH)
+	{
+	  tree decl = OMP_CLAUSE_DECL (c);
+	  tree arg;
+	  int idx;
+	  for (arg = parms, idx = 0; arg;
+	       arg = TREE_CHAIN (arg), idx++)
+	    if (arg == decl)
+	      break;
+	  if (arg == NULL_TREE)
+	    {
+	      error_at (OMP_CLAUSE_LOCATION (c),
+			"%qD is not an function argument", decl);
+	      continue;
+	    }
+	  OMP_CLAUSE_DECL (c) = build_int_cst (integer_type_node, idx);
+	}
+      clvec.safe_push (c);
+    }
+  if (!clvec.is_empty ())
+    {
+      unsigned int len = clvec.length (), i;
+      clvec.qsort (c_omp_declare_simd_clause_cmp);
+      clauses = clvec[0];
+      for (i = 0; i < len; i++)
+	OMP_CLAUSE_CHAIN (clvec[i]) = (i < len - 1) ? clvec[i + 1] : NULL_TREE;
+    }
+  clvec.release ();
+  return clauses;
+}
+
+/* Change argument indexes in CLAUSES of FNDECL back to PARM_DECLs.  */
+
+void
+c_omp_declare_simd_clauses_to_decls (tree fndecl, tree clauses)
+{
+  tree c;
+
+  for (c = clauses; c; c = OMP_CLAUSE_CHAIN (c))
+    if (OMP_CLAUSE_CODE (c) != OMP_CLAUSE_SIMDLEN
+	&& OMP_CLAUSE_CODE (c) != OMP_CLAUSE_INBRANCH
+	&& OMP_CLAUSE_CODE (c) != OMP_CLAUSE_NOTINBRANCH)
+      {
+	int idx = tree_low_cst (OMP_CLAUSE_DECL (c), 0), i;
+	tree arg;
+	for (arg = DECL_ARGUMENTS (fndecl), i = 0; arg;
+	     arg = TREE_CHAIN (arg), i++)
+	  if (i == idx)
+	    break;
+	gcc_assert (arg);
+	OMP_CLAUSE_DECL (c) = arg;
+      }
+}
+
 /* True if OpenMP sharing attribute of DECL is predetermined.  */
 
 enum omp_clause_default_kind
--- gcc/c-family/c-pragma.c	(.../trunk)	(revision 203241)
+++ gcc/c-family/c-pragma.c	(.../branches/gomp-4_0-branch)	(revision 203287)
@@ -1167,7 +1167,12 @@ struct omp_pragma_def { const char *name
 static const struct omp_pragma_def omp_pragmas[] = {
   { "atomic", PRAGMA_OMP_ATOMIC },
   { "barrier", PRAGMA_OMP_BARRIER },
+  { "cancel", PRAGMA_OMP_CANCEL },
+  { "cancellation", PRAGMA_OMP_CANCELLATION_POINT },
   { "critical", PRAGMA_OMP_CRITICAL },
+  { "declare", PRAGMA_OMP_DECLARE_REDUCTION },
+  { "distribute", PRAGMA_OMP_DISTRIBUTE },
+  { "end", PRAGMA_OMP_END_DECLARE_TARGET },
   { "flush", PRAGMA_OMP_FLUSH },
   { "for", PRAGMA_OMP_FOR },
   { "master", PRAGMA_OMP_MASTER },
@@ -1175,10 +1180,14 @@ static const struct omp_pragma_def omp_p
   { "parallel", PRAGMA_OMP_PARALLEL },
   { "section", PRAGMA_OMP_SECTION },
   { "sections", PRAGMA_OMP_SECTIONS },
+  { "simd", PRAGMA_OMP_SIMD },
   { "single", PRAGMA_OMP_SINGLE },
+  { "target", PRAGMA_OMP_TARGET },
   { "task", PRAGMA_OMP_TASK },
+  { "taskgroup", PRAGMA_OMP_TASKGROUP },
   { "taskwait", PRAGMA_OMP_TASKWAIT },
   { "taskyield", PRAGMA_OMP_TASKYIELD },
+  { "teams", PRAGMA_OMP_TEAMS },
   { "threadprivate", PRAGMA_OMP_THREADPRIVATE }
 };
 
--- gcc/c-family/c-pragma.h	(.../trunk)	(revision 203241)
+++ gcc/c-family/c-pragma.h	(.../branches/gomp-4_0-branch)	(revision 203287)
@@ -29,21 +29,28 @@ typedef enum pragma_kind {
 
   PRAGMA_OMP_ATOMIC,
   PRAGMA_OMP_BARRIER,
+  PRAGMA_OMP_CANCEL,
+  PRAGMA_OMP_CANCELLATION_POINT,
   PRAGMA_OMP_CRITICAL,
+  PRAGMA_OMP_DECLARE_REDUCTION,
+  PRAGMA_OMP_DISTRIBUTE,
+  PRAGMA_OMP_END_DECLARE_TARGET,
   PRAGMA_OMP_FLUSH,
   PRAGMA_OMP_FOR,
   PRAGMA_OMP_MASTER,
   PRAGMA_OMP_ORDERED,
   PRAGMA_OMP_PARALLEL,
-  PRAGMA_OMP_PARALLEL_FOR,
-  PRAGMA_OMP_PARALLEL_SECTIONS,
   PRAGMA_OMP_SECTION,
   PRAGMA_OMP_SECTIONS,
+  PRAGMA_OMP_SIMD,
   PRAGMA_OMP_SINGLE,
+  PRAGMA_OMP_TARGET,
   PRAGMA_OMP_TASK,
+  PRAGMA_OMP_TASKGROUP,
   PRAGMA_OMP_TASKWAIT,
   PRAGMA_OMP_TASKYIELD,
   PRAGMA_OMP_THREADPRIVATE,
+  PRAGMA_OMP_TEAMS,
 
   PRAGMA_GCC_PCH_PREPROCESS,
 
@@ -51,28 +58,48 @@ typedef enum pragma_kind {
 } pragma_kind;
 
 
-/* All clauses defined by OpenMP 2.5 and 3.0.
+/* All clauses defined by OpenMP 2.5, 3.0, 3.1 and 4.0.
    Used internally by both C and C++ parsers.  */
 typedef enum pragma_omp_clause {
   PRAGMA_OMP_CLAUSE_NONE = 0,
 
+  PRAGMA_OMP_CLAUSE_ALIGNED,
   PRAGMA_OMP_CLAUSE_COLLAPSE,
   PRAGMA_OMP_CLAUSE_COPYIN,
   PRAGMA_OMP_CLAUSE_COPYPRIVATE,
   PRAGMA_OMP_CLAUSE_DEFAULT,
+  PRAGMA_OMP_CLAUSE_DEPEND,
+  PRAGMA_OMP_CLAUSE_DEVICE,
+  PRAGMA_OMP_CLAUSE_DIST_SCHEDULE,
+  PRAGMA_OMP_CLAUSE_FINAL,
   PRAGMA_OMP_CLAUSE_FIRSTPRIVATE,
+  PRAGMA_OMP_CLAUSE_FOR,
+  PRAGMA_OMP_CLAUSE_FROM,
   PRAGMA_OMP_CLAUSE_IF,
+  PRAGMA_OMP_CLAUSE_INBRANCH,
   PRAGMA_OMP_CLAUSE_LASTPRIVATE,
+  PRAGMA_OMP_CLAUSE_LINEAR,
+  PRAGMA_OMP_CLAUSE_MAP,
+  PRAGMA_OMP_CLAUSE_MERGEABLE,
+  PRAGMA_OMP_CLAUSE_NOTINBRANCH,
   PRAGMA_OMP_CLAUSE_NOWAIT,
+  PRAGMA_OMP_CLAUSE_NUM_TEAMS,
   PRAGMA_OMP_CLAUSE_NUM_THREADS,
   PRAGMA_OMP_CLAUSE_ORDERED,
+  PRAGMA_OMP_CLAUSE_PARALLEL,
   PRAGMA_OMP_CLAUSE_PRIVATE,
+  PRAGMA_OMP_CLAUSE_PROC_BIND,
   PRAGMA_OMP_CLAUSE_REDUCTION,
+  PRAGMA_OMP_CLAUSE_SAFELEN,
   PRAGMA_OMP_CLAUSE_SCHEDULE,
+  PRAGMA_OMP_CLAUSE_SECTIONS,
   PRAGMA_OMP_CLAUSE_SHARED,
-  PRAGMA_OMP_CLAUSE_UNTIED,
-  PRAGMA_OMP_CLAUSE_FINAL,
-  PRAGMA_OMP_CLAUSE_MERGEABLE
+  PRAGMA_OMP_CLAUSE_SIMDLEN,
+  PRAGMA_OMP_CLAUSE_TASKGROUP,
+  PRAGMA_OMP_CLAUSE_THREAD_LIMIT,
+  PRAGMA_OMP_CLAUSE_TO,
+  PRAGMA_OMP_CLAUSE_UNIFORM,
+  PRAGMA_OMP_CLAUSE_UNTIED
 } pragma_omp_clause;
 
 extern struct cpp_reader* parse_in;
--- gcc/fortran/f95-lang.c	(.../trunk)	(revision 203241)
+++ gcc/fortran/f95-lang.c	(.../branches/gomp-4_0-branch)	(revision 203287)
@@ -531,7 +531,8 @@ gfc_builtin_function (tree decl)
   return decl;
 }
 
-/* So far we need just these 4 attribute types.  */
+/* So far we need just these 6 attribute types.  */
+#define ATTR_NULL			0
 #define ATTR_NOTHROW_LEAF_LIST		(ECF_NOTHROW | ECF_LEAF)
 #define ATTR_NOTHROW_LEAF_MALLOC_LIST	(ECF_NOTHROW | ECF_LEAF | ECF_MALLOC)
 #define ATTR_CONST_NOTHROW_LEAF_LIST	(ECF_NOTHROW | ECF_LEAF | ECF_CONST)
@@ -618,6 +619,7 @@ gfc_init_builtin_functions (void)
 #define DEF_FUNCTION_TYPE_5(NAME, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5) NAME,
 #define DEF_FUNCTION_TYPE_6(NAME, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5, ARG6) NAME,
 #define DEF_FUNCTION_TYPE_7(NAME, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5, ARG6, ARG7) NAME,
+#define DEF_FUNCTION_TYPE_8(NAME, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5, ARG6, ARG7, ARG8) NAME,
 #define DEF_FUNCTION_TYPE_VAR_0(NAME, RETURN) NAME,
 #define DEF_POINTER_TYPE(NAME, TYPE) NAME,
 #include "types.def"
@@ -630,6 +632,7 @@ gfc_init_builtin_functions (void)
 #undef DEF_FUNCTION_TYPE_5
 #undef DEF_FUNCTION_TYPE_6
 #undef DEF_FUNCTION_TYPE_7
+#undef DEF_FUNCTION_TYPE_8
 #undef DEF_FUNCTION_TYPE_VAR_0
 #undef DEF_POINTER_TYPE
     BT_LAST
@@ -992,6 +995,19 @@ gfc_init_builtin_functions (void)
                                 builtin_types[(int) ARG6],              \
                                 builtin_types[(int) ARG7],              \
                                 NULL_TREE);
+#define DEF_FUNCTION_TYPE_8(ENUM, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5, \
+			    ARG6, ARG7, ARG8)				\
+  builtin_types[(int) ENUM]						\
+    = build_function_type_list (builtin_types[(int) RETURN],		\
+				builtin_types[(int) ARG1],		\
+				builtin_types[(int) ARG2],		\
+				builtin_types[(int) ARG3],		\
+				builtin_types[(int) ARG4],		\
+				builtin_types[(int) ARG5],		\
+				builtin_types[(int) ARG6],		\
+				builtin_types[(int) ARG7],		\
+				builtin_types[(int) ARG8],		\
+				NULL_TREE);
 #define DEF_FUNCTION_TYPE_VAR_0(ENUM, RETURN)				\
   builtin_types[(int) ENUM]						\
     = build_varargs_function_type_list (builtin_types[(int) RETURN],    \
--- gcc/fortran/trans-openmp.c	(.../trunk)	(revision 203241)
+++ gcc/fortran/trans-openmp.c	(.../branches/gomp-4_0-branch)	(revision 203287)
@@ -159,6 +159,9 @@ gfc_omp_clause_default_ctor (tree clause
       || GFC_TYPE_ARRAY_AKIND (type) != GFC_ARRAY_ALLOCATABLE)
     return NULL;
 
+  if (OMP_CLAUSE_CODE (clause) == OMP_CLAUSE_REDUCTION)
+    return NULL;
+
   gcc_assert (outer != NULL);
   gcc_assert (OMP_CLAUSE_CODE (clause) == OMP_CLAUSE_PRIVATE
 	      || OMP_CLAUSE_CODE (clause) == OMP_CLAUSE_LASTPRIVATE);
@@ -323,6 +326,9 @@ gfc_omp_clause_dtor (tree clause ATTRIBU
       || GFC_TYPE_ARRAY_AKIND (type) != GFC_ARRAY_ALLOCATABLE)
     return NULL;
 
+  if (OMP_CLAUSE_CODE (clause) == OMP_CLAUSE_REDUCTION)
+    return NULL;
+
   /* Allocatable arrays in FIRSTPRIVATE/LASTPRIVATE etc. clauses need
      to be deallocated if they were allocated.  */
   return gfc_trans_dealloc_allocated (decl, false, NULL);
--- gcc/fortran/types.def	(.../trunk)	(revision 203241)
+++ gcc/fortran/types.def	(.../branches/gomp-4_0-branch)	(revision 203287)
@@ -34,6 +34,8 @@ along with GCC; see the file COPYING3.
    DEF_FUNCTION_TYPE_5 (ENUM, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5)
    DEF_FUNCTION_TYPE_6 (ENUM, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5, ARG6)
    DEF_FUNCTION_TYPE_7 (ENUM, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5, ARG6, ARG7)
+   DEF_FUNCTION_TYPE_8 (ENUM, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5, ARG6, ARG7,
+			ARG8)
 
      These macros describe function types.  ENUM is as above.  The
      RETURN type is one of the enumerals already defined.  ARG1, ARG2,
@@ -89,7 +91,7 @@ DEF_FUNCTION_TYPE_1 (BT_FN_VOID_VPTR, BT
 DEF_FUNCTION_TYPE_1 (BT_FN_UINT_UINT, BT_UINT, BT_UINT)
 DEF_FUNCTION_TYPE_1 (BT_FN_PTR_PTR, BT_PTR, BT_PTR)
 DEF_FUNCTION_TYPE_1 (BT_FN_VOID_INT, BT_VOID, BT_INT)
-
+DEF_FUNCTION_TYPE_1 (BT_FN_BOOL_INT, BT_BOOL, BT_INT)
 
 DEF_POINTER_TYPE (BT_PTR_FN_VOID_PTR, BT_FN_VOID_PTR)
 
@@ -117,7 +119,8 @@ DEF_FUNCTION_TYPE_2 (BT_FN_VOID_VPTR_INT
 DEF_FUNCTION_TYPE_2 (BT_FN_BOOL_VPTR_INT, BT_BOOL, BT_VOLATILE_PTR, BT_INT)
 DEF_FUNCTION_TYPE_2 (BT_FN_BOOL_SIZE_CONST_VPTR, BT_BOOL, BT_SIZE,
 		     BT_CONST_VOLATILE_PTR)
-
+DEF_FUNCTION_TYPE_2 (BT_FN_BOOL_INT_BOOL, BT_BOOL, BT_INT, BT_BOOL)
+DEF_FUNCTION_TYPE_2 (BT_FN_VOID_UINT_UINT, BT_VOID, BT_UINT, BT_UINT)
 
 DEF_POINTER_TYPE (BT_PTR_FN_VOID_PTR_PTR, BT_FN_VOID_PTR_PTR)
 
@@ -137,8 +140,6 @@ DEF_FUNCTION_TYPE_3 (BT_FN_I4_VPTR_I4_I4
 DEF_FUNCTION_TYPE_3 (BT_FN_I8_VPTR_I8_I8, BT_I8, BT_VOLATILE_PTR, BT_I8, BT_I8)
 DEF_FUNCTION_TYPE_3 (BT_FN_I16_VPTR_I16_I16, BT_I16, BT_VOLATILE_PTR,
 		     BT_I16, BT_I16)
-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_I1_VPTR_I1_INT, BT_I1, BT_VOLATILE_PTR, BT_I1, BT_INT)
 DEF_FUNCTION_TYPE_3 (BT_FN_I2_VPTR_I2_INT, BT_I2, BT_VOLATILE_PTR, BT_I2, BT_INT)
 DEF_FUNCTION_TYPE_3 (BT_FN_I4_VPTR_I4_INT, BT_I4, BT_VOLATILE_PTR, BT_I4, BT_INT)
@@ -159,6 +160,9 @@ DEF_FUNCTION_TYPE_4 (BT_FN_VOID_SIZE_VPT
 DEF_FUNCTION_TYPE_4 (BT_FN_VOID_SIZE_CONST_VPTR_PTR_INT, BT_VOID, BT_SIZE,
 		     BT_CONST_VOLATILE_PTR, BT_PTR, BT_INT)
 
+DEF_FUNCTION_TYPE_5 (BT_FN_VOID_OMPFN_PTR_UINT_UINT_UINT,
+		     BT_VOID, BT_PTR_FN_VOID_PTR, BT_PTR, BT_UINT, BT_UINT,
+		     BT_UINT)
 DEF_FUNCTION_TYPE_5 (BT_FN_BOOL_LONG_LONG_LONG_LONGPTR_LONGPTR,
                      BT_BOOL, BT_LONG, BT_LONG, BT_LONG,
 		     BT_PTR_LONG, BT_PTR_LONG)
@@ -168,9 +172,6 @@ DEF_FUNCTION_TYPE_5 (BT_FN_VOID_SIZE_VPT
 DEF_FUNCTION_TYPE_6 (BT_FN_BOOL_LONG_LONG_LONG_LONG_LONGPTR_LONGPTR,
                      BT_BOOL, BT_LONG, BT_LONG, BT_LONG, BT_LONG,
 		     BT_PTR_LONG, BT_PTR_LONG)
-DEF_FUNCTION_TYPE_6 (BT_FN_VOID_OMPFN_PTR_UINT_LONG_LONG_LONG,
-                     BT_VOID, BT_PTR_FN_VOID_PTR, BT_PTR, BT_UINT,
-                     BT_LONG, BT_LONG, BT_LONG)
 DEF_FUNCTION_TYPE_6 (BT_FN_BOOL_BOOL_ULL_ULL_ULL_ULLPTR_ULLPTR,
 		     BT_BOOL, BT_BOOL, BT_ULONGLONG, BT_ULONGLONG,
 		     BT_ULONGLONG, BT_PTR_ULONGLONG, BT_PTR_ULONGLONG)
@@ -191,17 +192,26 @@ DEF_FUNCTION_TYPE_6 (BT_FN_BOOL_VPTR_PTR
 		     BT_INT)
 DEF_FUNCTION_TYPE_6 (BT_FN_BOOL_SIZE_VPTR_PTR_PTR_INT_INT, BT_BOOL, BT_SIZE,
 		     BT_VOLATILE_PTR, BT_PTR, BT_PTR, BT_INT, BT_INT)
+DEF_FUNCTION_TYPE_6 (BT_FN_VOID_INT_PTR_SIZE_PTR_PTR_PTR,
+		     BT_VOID, BT_INT, BT_PTR, BT_SIZE, BT_PTR, BT_PTR, BT_PTR)
 
-DEF_FUNCTION_TYPE_7 (BT_FN_VOID_OMPFN_PTR_UINT_LONG_LONG_LONG_LONG,
+DEF_FUNCTION_TYPE_7 (BT_FN_VOID_OMPFN_PTR_UINT_LONG_LONG_LONG_UINT,
                      BT_VOID, BT_PTR_FN_VOID_PTR, BT_PTR, BT_UINT,
-                     BT_LONG, BT_LONG, BT_LONG, BT_LONG)
-DEF_FUNCTION_TYPE_7 (BT_FN_VOID_OMPFN_PTR_OMPCPYFN_LONG_LONG_BOOL_UINT,
-		     BT_VOID, BT_PTR_FN_VOID_PTR, BT_PTR,
-		     BT_PTR_FN_VOID_PTR_PTR, BT_LONG, BT_LONG,
-		     BT_BOOL, BT_UINT)
+		     BT_LONG, BT_LONG, BT_LONG, BT_UINT)
 DEF_FUNCTION_TYPE_7 (BT_FN_BOOL_BOOL_ULL_ULL_ULL_ULL_ULLPTR_ULLPTR,
 		     BT_BOOL, BT_BOOL, BT_ULONGLONG, BT_ULONGLONG,
 		     BT_ULONGLONG, BT_ULONGLONG,
 		     BT_PTR_ULONGLONG, BT_PTR_ULONGLONG)
+DEF_FUNCTION_TYPE_7 (BT_FN_VOID_INT_OMPFN_PTR_SIZE_PTR_PTR_PTR,
+		     BT_VOID, BT_INT, BT_PTR_FN_VOID_PTR, BT_PTR, BT_SIZE,
+		     BT_PTR, BT_PTR, BT_PTR)
+
+DEF_FUNCTION_TYPE_8 (BT_FN_VOID_OMPFN_PTR_UINT_LONG_LONG_LONG_LONG_UINT,
+		     BT_VOID, BT_PTR_FN_VOID_PTR, BT_PTR, BT_UINT,
+		     BT_LONG, BT_LONG, BT_LONG, BT_LONG, BT_UINT)
+DEF_FUNCTION_TYPE_8 (BT_FN_VOID_OMPFN_PTR_OMPCPYFN_LONG_LONG_BOOL_UINT_PTR,
+		     BT_VOID, BT_PTR_FN_VOID_PTR, BT_PTR,
+		     BT_PTR_FN_VOID_PTR_PTR, BT_LONG, BT_LONG,
+		     BT_BOOL, BT_UINT, BT_PTR)
 
 DEF_FUNCTION_TYPE_VAR_0 (BT_FN_VOID_VAR, BT_VOID)
--- gcc/gimple-low.c	(.../trunk)	(revision 203241)
+++ gcc/gimple-low.c	(.../branches/gomp-4_0-branch)	(revision 203287)
@@ -425,6 +425,7 @@ lower_stmt (gimple_stmt_iterator *gsi, s
     case GIMPLE_OMP_SECTION:
     case GIMPLE_OMP_SINGLE:
     case GIMPLE_OMP_MASTER:
+    case GIMPLE_OMP_TASKGROUP:
     case GIMPLE_OMP_ORDERED:
     case GIMPLE_OMP_CRITICAL:
     case GIMPLE_OMP_RETURN:
@@ -466,6 +467,8 @@ lower_stmt (gimple_stmt_iterator *gsi, s
 
     case GIMPLE_OMP_PARALLEL:
     case GIMPLE_OMP_TASK:
+    case GIMPLE_OMP_TARGET:
+    case GIMPLE_OMP_TEAMS:
       data->cannot_fallthru = false;
       lower_omp_directive (gsi, data);
       data->cannot_fallthru = false;
--- gcc/gimple-pretty-print.c	(.../trunk)	(revision 203241)
+++ gcc/gimple-pretty-print.c	(.../branches/gomp-4_0-branch)	(revision 203287)
@@ -1097,6 +1097,9 @@ dump_gimple_omp_for (pretty_printer *buf
 	case GF_OMP_FOR_KIND_SIMD:
 	  kind = " simd";
 	  break;
+	case GF_OMP_FOR_KIND_DISTRIBUTE:
+	  kind = " distribute";
+	  break;
 	default:
 	  gcc_unreachable ();
 	}
@@ -1125,6 +1128,9 @@ dump_gimple_omp_for (pretty_printer *buf
 	case GF_OMP_FOR_KIND_SIMD:
 	  pp_string (buffer, "#pragma omp simd");
 	  break;
+	case GF_OMP_FOR_KIND_DISTRIBUTE:
+	  pp_string (buffer, "#pragma omp distribute");
+	  break;
 	default:
 	  gcc_unreachable ();
 	}
@@ -1239,6 +1245,85 @@ dump_gimple_omp_single (pretty_printer *
     }
 }
 
+/* Dump a GIMPLE_OMP_TARGET tuple on the pretty_printer BUFFER.  */
+
+static void
+dump_gimple_omp_target (pretty_printer *buffer, gimple gs, int spc, int flags)
+{
+  const char *kind;
+  switch (gimple_omp_target_kind (gs))
+    {
+    case GF_OMP_TARGET_KIND_REGION:
+      kind = "";
+      break;
+    case GF_OMP_TARGET_KIND_DATA:
+      kind = " data";
+      break;
+    case GF_OMP_TARGET_KIND_UPDATE:
+      kind = " update";
+      break;
+    default:
+      gcc_unreachable ();
+    }
+  if (flags & TDF_RAW)
+    {
+      dump_gimple_fmt (buffer, spc, flags, "%G%s <%+BODY <%S>%nCLAUSES <", gs,
+		       kind, gimple_omp_body (gs));
+      dump_omp_clauses (buffer, gimple_omp_target_clauses (gs), spc, flags);
+      dump_gimple_fmt (buffer, spc, flags, " >");
+    }
+  else
+    {
+      pp_string (buffer, "#pragma omp target");
+      pp_string (buffer, kind);
+      dump_omp_clauses (buffer, gimple_omp_target_clauses (gs), spc, flags);
+      if (gimple_omp_target_child_fn (gs))
+	{
+	  pp_string (buffer, " [child fn: ");
+	  dump_generic_node (buffer, gimple_omp_target_child_fn (gs),
+			     spc, flags, false);
+	  pp_right_bracket (buffer);
+	}
+      if (!gimple_seq_empty_p (gimple_omp_body (gs)))
+	{
+	  newline_and_indent (buffer, spc + 2);
+	  pp_character (buffer, '{');
+	  pp_newline (buffer);
+	  dump_gimple_seq (buffer, gimple_omp_body (gs), spc + 4, flags);
+	  newline_and_indent (buffer, spc + 2);
+	  pp_character (buffer, '}');
+	}
+    }
+}
+
+/* Dump a GIMPLE_OMP_TEAMS tuple on the pretty_printer BUFFER.  */
+
+static void
+dump_gimple_omp_teams (pretty_printer *buffer, gimple gs, int spc, int flags)
+{
+  if (flags & TDF_RAW)
+    {
+      dump_gimple_fmt (buffer, spc, flags, "%G <%+BODY <%S>%nCLAUSES <", gs,
+		       gimple_omp_body (gs));
+      dump_omp_clauses (buffer, gimple_omp_teams_clauses (gs), spc, flags);
+      dump_gimple_fmt (buffer, spc, flags, " >");
+    }
+  else
+    {
+      pp_string (buffer, "#pragma omp teams");
+      dump_omp_clauses (buffer, gimple_omp_teams_clauses (gs), spc, flags);
+      if (!gimple_seq_empty_p (gimple_omp_body (gs)))
+	{
+	  newline_and_indent (buffer, spc + 2);
+	  pp_character (buffer, '{');
+	  pp_newline (buffer);
+	  dump_gimple_seq (buffer, gimple_omp_body (gs), spc + 4, flags);
+	  newline_and_indent (buffer, spc + 2);
+	  pp_character (buffer, '}');
+	}
+    }
+}
+
 /* Dump a GIMPLE_OMP_SECTIONS tuple on the pretty_printer BUFFER.  */
 
 static void
@@ -1275,8 +1360,8 @@ dump_gimple_omp_sections (pretty_printer
     }
 }
 
-/* Dump a GIMPLE_OMP_{MASTER,ORDERED,SECTION} tuple on the pretty_printer
-   BUFFER.  */
+/* Dump a GIMPLE_OMP_{MASTER,TASKGROUP,ORDERED,SECTION} tuple on the
+   pretty_printer BUFFER.  */
 
 static void
 dump_gimple_omp_block (pretty_printer *buffer, gimple gs, int spc, int flags)
@@ -1291,6 +1376,9 @@ dump_gimple_omp_block (pretty_printer *b
 	case GIMPLE_OMP_MASTER:
 	  pp_string (buffer, "#pragma omp master");
 	  break;
+	case GIMPLE_OMP_TASKGROUP:
+	  pp_string (buffer, "#pragma omp taskgroup");
+	  break;
 	case GIMPLE_OMP_ORDERED:
 	  pp_string (buffer, "#pragma omp ordered");
 	  break;
@@ -1350,14 +1438,26 @@ dump_gimple_omp_return (pretty_printer *
 {
   if (flags & TDF_RAW)
     {
-      dump_gimple_fmt (buffer, spc, flags, "%G <nowait=%d>", gs,
+      dump_gimple_fmt (buffer, spc, flags, "%G <nowait=%d", gs,
                        (int) gimple_omp_return_nowait_p (gs));
+      if (gimple_omp_return_lhs (gs))
+	dump_gimple_fmt (buffer, spc, flags, ", lhs=%T>",
+			 gimple_omp_return_lhs (gs));
+      else
+	dump_gimple_fmt (buffer, spc, flags, ">");
     }
   else
     {
       pp_string (buffer, "#pragma omp return");
       if (gimple_omp_return_nowait_p (gs))
 	pp_string (buffer, "(nowait)");
+      if (gimple_omp_return_lhs (gs))
+	{
+	  pp_string (buffer, " (set ");
+	  dump_generic_node (buffer, gimple_omp_return_lhs (gs),
+			     spc, flags, false);
+	  pp_character (buffer, ')');
+	}
     }
 }
 
@@ -1826,6 +1926,8 @@ dump_gimple_omp_atomic_load (pretty_prin
   else
     {
       pp_string (buffer, "#pragma omp atomic_load");
+      if (gimple_omp_atomic_seq_cst_p (gs))
+	pp_string (buffer, " seq_cst");
       if (gimple_omp_atomic_need_value_p (gs))
 	pp_string (buffer, " [needed]");
       newline_and_indent (buffer, spc + 2);
@@ -1856,6 +1958,8 @@ dump_gimple_omp_atomic_store (pretty_pri
   else
     {
       pp_string (buffer, "#pragma omp atomic_store ");
+      if (gimple_omp_atomic_seq_cst_p (gs))
+	pp_string (buffer, "seq_cst ");
       if (gimple_omp_atomic_need_value_p (gs))
 	pp_string (buffer, "[needed] ");
       pp_left_paren (buffer);
@@ -2023,6 +2127,14 @@ pp_gimple_stmt_1 (pretty_printer *buffer
       dump_gimple_omp_single (buffer, gs, spc, flags);
       break;
 
+    case GIMPLE_OMP_TARGET:
+      dump_gimple_omp_target (buffer, gs, spc, flags);
+      break;
+
+    case GIMPLE_OMP_TEAMS:
+      dump_gimple_omp_teams (buffer, gs, spc, flags);
+      break;
+
     case GIMPLE_OMP_RETURN:
       dump_gimple_omp_return (buffer, gs, spc, flags);
       break;
@@ -2036,6 +2148,7 @@ pp_gimple_stmt_1 (pretty_printer *buffer
       break;
 
     case GIMPLE_OMP_MASTER:
+    case GIMPLE_OMP_TASKGROUP:
     case GIMPLE_OMP_ORDERED:
     case GIMPLE_OMP_SECTION:
       dump_gimple_omp_block (buffer, gs, spc, flags);
--- gcc/gimple.c	(.../trunk)	(revision 203241)
+++ gcc/gimple.c	(.../branches/gomp-4_0-branch)	(revision 203287)
@@ -1007,6 +1007,22 @@ gimple_build_omp_master (gimple_seq body
 }
 
 
+/* Build a GIMPLE_OMP_TASKGROUP statement.
+
+   BODY is the sequence of statements to be executed by the taskgroup
+   construct.  */
+
+gimple
+gimple_build_omp_taskgroup (gimple_seq body)
+{
+  gimple p = gimple_alloc (GIMPLE_OMP_TASKGROUP, 0);
+  if (body)
+    gimple_omp_set_body (p, body);
+
+  return p;
+}
+
+
 /* Build a GIMPLE_OMP_CONTINUE statement.
 
    CONTROL_DEF is the definition of the control variable.
@@ -1096,6 +1112,41 @@ gimple_build_omp_single (gimple_seq body
 }
 
 
+/* Build a GIMPLE_OMP_TARGET statement.
+
+   BODY is the sequence of statements that will be executed.
+   CLAUSES are any of the OMP target construct's clauses.  */
+
+gimple
+gimple_build_omp_target (gimple_seq body, int kind, tree clauses)
+{
+  gimple p = gimple_alloc (GIMPLE_OMP_TARGET, 0);
+  if (body)
+    gimple_omp_set_body (p, body);
+  gimple_omp_target_set_clauses (p, clauses);
+  gimple_omp_target_set_kind (p, kind);
+
+  return p;
+}
+
+
+/* Build a GIMPLE_OMP_TEAMS statement.
+
+   BODY is the sequence of statements that will be executed.
+   CLAUSES are any of the OMP teams construct's clauses.  */
+
+gimple
+gimple_build_omp_teams (gimple_seq body, tree clauses)
+{
+  gimple p = gimple_alloc (GIMPLE_OMP_TEAMS, 0);
+  if (body)
+    gimple_omp_set_body (p, body);
+  gimple_omp_teams_set_clauses (p, clauses);
+
+  return p;
+}
+
+
 /* Build a GIMPLE_OMP_ATOMIC_LOAD statement.  */
 
 gimple
@@ -1612,6 +1663,20 @@ walk_gimple_op (gimple stmt, walk_tree_f
 	return ret;
       break;
 
+    case GIMPLE_OMP_TARGET:
+      ret = walk_tree (gimple_omp_target_clauses_ptr (stmt), callback_op, wi,
+		       pset);
+      if (ret)
+	return ret;
+      break;
+
+    case GIMPLE_OMP_TEAMS:
+      ret = walk_tree (gimple_omp_teams_clauses_ptr (stmt), callback_op, wi,
+		       pset);
+      if (ret)
+	return ret;
+      break;
+
     case GIMPLE_OMP_ATOMIC_LOAD:
       ret = walk_tree (gimple_omp_atomic_load_lhs_ptr (stmt), callback_op, wi,
 		       pset);
@@ -1638,10 +1703,16 @@ walk_gimple_op (gimple stmt, walk_tree_f
 	return ret;
       break;
 
+    case GIMPLE_OMP_RETURN:
+      ret = walk_tree (gimple_omp_return_lhs_ptr (stmt), callback_op, wi,
+		       pset);
+      if (ret)
+	return ret;
+      break;
+
       /* Tuples that do not have operands.  */
     case GIMPLE_NOP:
     case GIMPLE_RESX:
-    case GIMPLE_OMP_RETURN:
     case GIMPLE_PREDICT:
       break;
 
@@ -1782,12 +1853,15 @@ walk_gimple_stmt (gimple_stmt_iterator *
       /* FALL THROUGH.  */
     case GIMPLE_OMP_CRITICAL:
     case GIMPLE_OMP_MASTER:
+    case GIMPLE_OMP_TASKGROUP:
     case GIMPLE_OMP_ORDERED:
     case GIMPLE_OMP_SECTION:
     case GIMPLE_OMP_PARALLEL:
     case GIMPLE_OMP_TASK:
     case GIMPLE_OMP_SECTIONS:
     case GIMPLE_OMP_SINGLE:
+    case GIMPLE_OMP_TARGET:
+    case GIMPLE_OMP_TEAMS:
       ret = walk_gimple_seq_mod (gimple_omp_body_ptr (stmt), callback_stmt,
 			     callback_op, wi);
       if (ret)
@@ -2277,8 +2351,11 @@ gimple_copy (gimple stmt)
 	  /* FALLTHRU  */
 
 	case GIMPLE_OMP_SINGLE:
+	case GIMPLE_OMP_TARGET:
+	case GIMPLE_OMP_TEAMS:
 	case GIMPLE_OMP_SECTION:
 	case GIMPLE_OMP_MASTER:
+	case GIMPLE_OMP_TASKGROUP:
 	case GIMPLE_OMP_ORDERED:
 	copy_omp_body:
 	  new_seq = gimple_seq_copy (gimple_omp_body (stmt));
--- gcc/gimple.def	(.../trunk)	(revision 203241)
+++ gcc/gimple.def	(.../branches/gomp-4_0-branch)	(revision 203287)
@@ -276,6 +276,10 @@ DEFGSCODE(GIMPLE_OMP_FOR, "gimple_omp_fo
    BODY is the sequence of statements to execute in the master section.  */
 DEFGSCODE(GIMPLE_OMP_MASTER, "gimple_omp_master", GSS_OMP)
 
+/* GIMPLE_OMP_TASKGROUP <BODY> represents #pragma omp taskgroup.
+   BODY is the sequence of statements to execute in the taskgroup section.  */
+DEFGSCODE(GIMPLE_OMP_TASKGROUP, "gimple_omp_taskgroup", GSS_OMP)
+
 /* GIMPLE_OMP_ORDERED <BODY> represents #pragma omp ordered.
    BODY is the sequence of statements to execute in the ordered section.  */
 DEFGSCODE(GIMPLE_OMP_ORDERED, "gimple_omp_ordered", GSS_OMP)
@@ -325,7 +329,7 @@ DEFGSCODE(GIMPLE_OMP_PARALLEL, "gimple_o
 DEFGSCODE(GIMPLE_OMP_TASK, "gimple_omp_task", GSS_OMP_TASK)
 
 /* OMP_RETURN marks the end of an OpenMP directive.  */
-DEFGSCODE(GIMPLE_OMP_RETURN, "gimple_omp_return", GSS_BASE)
+DEFGSCODE(GIMPLE_OMP_RETURN, "gimple_omp_return", GSS_OMP_ATOMIC_STORE)
 
 /* OMP_SECTION <BODY> represents #pragma omp section.
    BODY is the sequence of statements in the section body.  */
@@ -349,6 +353,24 @@ DEFGSCODE(GIMPLE_OMP_SECTIONS_SWITCH, "g
    CLAUSES is an OMP_CLAUSE chain holding the associated clauses.  */
 DEFGSCODE(GIMPLE_OMP_SINGLE, "gimple_omp_single", GSS_OMP_SINGLE)
 
+/* GIMPLE_OMP_TARGET <BODY, CLAUSES, CHILD_FN> represents
+   #pragma omp target {,data,update}
+   BODY is the sequence of statements inside the target construct
+   (NULL for target update).
+   CLAUSES is an OMP_CLAUSE chain holding the associated clauses.
+   CHILD_FN is set when outlining the body of the target region.
+   All the statements in BODY are moved into this newly created
+   function when converting OMP constructs into low-GIMPLE.
+   DATA_ARG is a vec of 3 local variables in the parent function
+   containing data to be mapped to CHILD_FN.  This is used to
+   implement the MAP clauses.  */
+DEFGSCODE(GIMPLE_OMP_TARGET, "gimple_omp_target", GSS_OMP_PARALLEL)
+
+/* GIMPLE_OMP_TEAMS <BODY, CLAUSES> represents #pragma omp teams
+   BODY is the sequence of statements inside the single section.
+   CLAUSES is an OMP_CLAUSE chain holding the associated clauses.  */
+DEFGSCODE(GIMPLE_OMP_TEAMS, "gimple_omp_teams", GSS_OMP_SINGLE)
+
 /* GIMPLE_PREDICT <PREDICT, OUTCOME> specifies a hint for branch prediction.
 
    PREDICT is one of the predictors from predict.def.
--- gcc/gimple.h	(.../trunk)	(revision 203241)
+++ gcc/gimple.h	(.../branches/gomp-4_0-branch)	(revision 203287)
@@ -104,6 +104,13 @@ enum gf_mask {
     GF_OMP_FOR_KIND_MASK	= 3 << 0,
     GF_OMP_FOR_KIND_FOR		= 0 << 0,
     GF_OMP_FOR_KIND_SIMD	= 1 << 0,
+    GF_OMP_FOR_KIND_DISTRIBUTE	= 2 << 0,
+    GF_OMP_FOR_COMBINED		= 1 << 2,
+    GF_OMP_FOR_COMBINED_INTO	= 1 << 3,
+    GF_OMP_TARGET_KIND_MASK	= 3 << 0,
+    GF_OMP_TARGET_KIND_REGION	= 0 << 0,
+    GF_OMP_TARGET_KIND_DATA	= 1 << 0,
+    GF_OMP_TARGET_KIND_UPDATE	= 2 << 0,
 
     /* True on an GIMPLE_OMP_RETURN statement if the return does not require
        a thread synchronization via some sort of barrier.  The exact barrier
@@ -113,6 +120,7 @@ enum gf_mask {
 
     GF_OMP_SECTION_LAST		= 1 << 0,
     GF_OMP_ATOMIC_NEED_VALUE	= 1 << 0,
+    GF_OMP_ATOMIC_SEQ_CST	= 1 << 1,
     GF_PREDICT_TAKEN		= 1 << 15
 };
 
@@ -606,7 +614,7 @@ struct GTY(()) gimple_statement_omp_cont
   tree control_use;
 };
 
-/* GIMPLE_OMP_SINGLE */
+/* GIMPLE_OMP_SINGLE, GIMPLE_OMP_TARGET, GIMPLE_OMP_TEAMS */
 
 struct GTY(()) gimple_statement_omp_single {
   /* [ WORD 1-7 ]  */
@@ -785,11 +793,14 @@ gimple gimple_build_omp_critical (gimple
 gimple gimple_build_omp_section (gimple_seq);
 gimple gimple_build_omp_continue (tree, tree);
 gimple gimple_build_omp_master (gimple_seq);
+gimple gimple_build_omp_taskgroup (gimple_seq);
 gimple gimple_build_omp_return (bool);
 gimple gimple_build_omp_ordered (gimple_seq);
 gimple gimple_build_omp_sections (gimple_seq, tree);
 gimple gimple_build_omp_sections_switch (void);
 gimple gimple_build_omp_single (gimple_seq, tree);
+gimple gimple_build_omp_target (gimple_seq, int, tree);
+gimple gimple_build_omp_teams (gimple_seq, tree);
 gimple gimple_build_cdt (tree, tree);
 gimple gimple_build_omp_atomic_load (tree, tree);
 gimple gimple_build_omp_atomic_store (tree);
@@ -1230,12 +1241,15 @@ gimple_has_substatements (gimple g)
     case GIMPLE_TRY:
     case GIMPLE_OMP_FOR:
     case GIMPLE_OMP_MASTER:
+    case GIMPLE_OMP_TASKGROUP:
     case GIMPLE_OMP_ORDERED:
     case GIMPLE_OMP_SECTION:
     case GIMPLE_OMP_PARALLEL:
     case GIMPLE_OMP_TASK:
     case GIMPLE_OMP_SECTIONS:
     case GIMPLE_OMP_SINGLE:
+    case GIMPLE_OMP_TARGET:
+    case GIMPLE_OMP_TEAMS:
     case GIMPLE_OMP_CRITICAL:
     case GIMPLE_WITH_CLEANUP_EXPR:
     case GIMPLE_TRANSACTION:
@@ -1614,7 +1628,7 @@ static inline unsigned
 gimple_omp_subcode (const_gimple s)
 {
   gcc_gimple_checking_assert (gimple_code (s) >= GIMPLE_OMP_ATOMIC_LOAD
-	      && gimple_code (s) <= GIMPLE_OMP_SINGLE);
+	      && gimple_code (s) <= GIMPLE_OMP_TEAMS);
   return s->gsbase.subcode;
 }
 
@@ -1650,6 +1664,36 @@ gimple_omp_return_nowait_p (const_gimple
 }
 
 
+/* Set the LHS of OMP return.  */
+
+static inline void
+gimple_omp_return_set_lhs (gimple g, tree lhs)
+{
+  GIMPLE_CHECK (g, GIMPLE_OMP_RETURN);
+  g->gimple_omp_atomic_store.val = lhs;
+}
+
+
+/* Get the LHS of OMP return.  */
+
+static inline tree
+gimple_omp_return_lhs (const_gimple g)
+{
+  GIMPLE_CHECK (g, GIMPLE_OMP_RETURN);
+  return g->gimple_omp_atomic_store.val;
+}
+
+
+/* Return a pointer to the LHS of OMP return.  */
+
+static inline tree *
+gimple_omp_return_lhs_ptr (gimple g)
+{
+  GIMPLE_CHECK (g, GIMPLE_OMP_RETURN);
+  return &g->gimple_omp_atomic_store.val;
+}
+
+
 /* Return true if OMP section statement G has the GF_OMP_SECTION_LAST
    flag set.  */
 
@@ -1719,6 +1763,29 @@ gimple_omp_atomic_set_need_value (gimple
 }
 
 
+/* Return true if OMP atomic load/store statement G has the
+   GF_OMP_ATOMIC_SEQ_CST flag set.  */
+
+static inline bool
+gimple_omp_atomic_seq_cst_p (const_gimple g)
+{
+  if (gimple_code (g) != GIMPLE_OMP_ATOMIC_LOAD)
+    GIMPLE_CHECK (g, GIMPLE_OMP_ATOMIC_STORE);
+  return (gimple_omp_subcode (g) & GF_OMP_ATOMIC_SEQ_CST) != 0;
+}
+
+
+/* Set the GF_OMP_ATOMIC_SEQ_CST flag on G.  */
+
+static inline void
+gimple_omp_atomic_set_seq_cst (gimple g)
+{
+  if (gimple_code (g) != GIMPLE_OMP_ATOMIC_LOAD)
+    GIMPLE_CHECK (g, GIMPLE_OMP_ATOMIC_STORE);
+  g->gsbase.subcode |= GF_OMP_ATOMIC_SEQ_CST;
+}
+
+
 /* Return the number of operands for statement GS.  */
 
 static inline unsigned
@@ -3985,6 +4052,56 @@ gimple_omp_for_set_kind (gimple g, int k
 }
 
 
+/* Return true if OMP for statement G has the
+   GF_OMP_FOR_COMBINED flag set.  */
+
+static inline bool
+gimple_omp_for_combined_p (const_gimple g)
+{
+  GIMPLE_CHECK (g, GIMPLE_OMP_FOR);
+  return (gimple_omp_subcode (g) & GF_OMP_FOR_COMBINED) != 0;
+}
+
+
+/* Set the GF_OMP_FOR_COMBINED field in G depending on the boolean
+   value of COMBINED_P.  */
+
+static inline void
+gimple_omp_for_set_combined_p (gimple g, bool combined_p)
+{
+  GIMPLE_CHECK (g, GIMPLE_OMP_FOR);
+  if (combined_p)
+    g->gsbase.subcode |= GF_OMP_FOR_COMBINED;
+  else
+    g->gsbase.subcode &= ~GF_OMP_FOR_COMBINED;
+}
+
+
+/* Return true if OMP for statement G has the
+   GF_OMP_FOR_COMBINED_INTO flag set.  */
+
+static inline bool
+gimple_omp_for_combined_into_p (const_gimple g)
+{
+  GIMPLE_CHECK (g, GIMPLE_OMP_FOR);
+  return (gimple_omp_subcode (g) & GF_OMP_FOR_COMBINED_INTO) != 0;
+}
+
+
+/* Set the GF_OMP_FOR_COMBINED_INTO field in G depending on the boolean
+   value of COMBINED_P.  */
+
+static inline void
+gimple_omp_for_set_combined_into_p (gimple g, bool combined_p)
+{
+  GIMPLE_CHECK (g, GIMPLE_OMP_FOR);
+  if (combined_p)
+    g->gsbase.subcode |= GF_OMP_FOR_COMBINED_INTO;
+  else
+    g->gsbase.subcode &= ~GF_OMP_FOR_COMBINED_INTO;
+}
+
+
 /* Return the clauses associated with OMP_FOR GS.  */
 
 static inline tree
@@ -4594,6 +4711,148 @@ gimple_omp_single_set_clauses (gimple gs
 }
 
 
+/* Return the clauses associated with OMP_TARGET GS.  */
+
+static inline tree
+gimple_omp_target_clauses (const_gimple gs)
+{
+  GIMPLE_CHECK (gs, GIMPLE_OMP_TARGET);
+  return gs->gimple_omp_parallel.clauses;
+}
+
+
+/* Return a pointer to the clauses associated with OMP_TARGET GS.  */
+
+static inline tree *
+gimple_omp_target_clauses_ptr (gimple gs)
+{
+  GIMPLE_CHECK (gs, GIMPLE_OMP_TARGET);
+  return &gs->gimple_omp_parallel.clauses;
+}
+
+
+/* Set CLAUSES to be the clauses associated with OMP_TARGET GS.  */
+
+static inline void
+gimple_omp_target_set_clauses (gimple gs, tree clauses)
+{
+  GIMPLE_CHECK (gs, GIMPLE_OMP_TARGET);
+  gs->gimple_omp_parallel.clauses = clauses;
+}
+
+
+/* Return the kind of OMP target statemement.  */
+
+static inline int
+gimple_omp_target_kind (const_gimple g)
+{
+  GIMPLE_CHECK (g, GIMPLE_OMP_TARGET);
+  return (gimple_omp_subcode (g) & GF_OMP_TARGET_KIND_MASK);
+}
+
+
+/* Set the OMP target kind.  */
+
+static inline void
+gimple_omp_target_set_kind (gimple g, int kind)
+{
+  GIMPLE_CHECK (g, GIMPLE_OMP_TARGET);
+  g->gsbase.subcode = (g->gsbase.subcode & ~GF_OMP_TARGET_KIND_MASK)
+		      | (kind & GF_OMP_TARGET_KIND_MASK);
+}
+
+
+/* Return the child function used to hold the body of OMP_TARGET GS.  */
+
+static inline tree
+gimple_omp_target_child_fn (const_gimple gs)
+{
+  GIMPLE_CHECK (gs, GIMPLE_OMP_TARGET);
+  return gs->gimple_omp_parallel.child_fn;
+}
+
+/* Return a pointer to the child function used to hold the body of
+   OMP_TARGET GS.  */
+
+static inline tree *
+gimple_omp_target_child_fn_ptr (gimple gs)
+{
+  GIMPLE_CHECK (gs, GIMPLE_OMP_TARGET);
+  return &gs->gimple_omp_parallel.child_fn;
+}
+
+
+/* Set CHILD_FN to be the child function for OMP_TARGET GS.  */
+
+static inline void
+gimple_omp_target_set_child_fn (gimple gs, tree child_fn)
+{
+  GIMPLE_CHECK (gs, GIMPLE_OMP_TARGET);
+  gs->gimple_omp_parallel.child_fn = child_fn;
+}
+
+
+/* Return the artificial argument used to send variables and values
+   from the parent to the children threads in OMP_TARGET GS.  */
+
+static inline tree
+gimple_omp_target_data_arg (const_gimple gs)
+{
+  GIMPLE_CHECK (gs, GIMPLE_OMP_TARGET);
+  return gs->gimple_omp_parallel.data_arg;
+}
+
+
+/* Return a pointer to the data argument for OMP_TARGET GS.  */
+
+static inline tree *
+gimple_omp_target_data_arg_ptr (gimple gs)
+{
+  GIMPLE_CHECK (gs, GIMPLE_OMP_TARGET);
+  return &gs->gimple_omp_parallel.data_arg;
+}
+
+
+/* Set DATA_ARG to be the data argument for OMP_TARGET GS.  */
+
+static inline void
+gimple_omp_target_set_data_arg (gimple gs, tree data_arg)
+{
+  GIMPLE_CHECK (gs, GIMPLE_OMP_TARGET);
+  gs->gimple_omp_parallel.data_arg = data_arg;
+}
+
+
+/* Return the clauses associated with OMP_TEAMS GS.  */
+
+static inline tree
+gimple_omp_teams_clauses (const_gimple gs)
+{
+  GIMPLE_CHECK (gs, GIMPLE_OMP_TEAMS);
+  return gs->gimple_omp_single.clauses;
+}
+
+
+/* Return a pointer to the clauses associated with OMP_TEAMS GS.  */
+
+static inline tree *
+gimple_omp_teams_clauses_ptr (gimple gs)
+{
+  GIMPLE_CHECK (gs, GIMPLE_OMP_TEAMS);
+  return &gs->gimple_omp_single.clauses;
+}
+
+
+/* Set CLAUSES to be the clauses associated with OMP_TEAMS GS.  */
+
+static inline void
+gimple_omp_teams_set_clauses (gimple gs, tree clauses)
+{
+  GIMPLE_CHECK (gs, GIMPLE_OMP_TEAMS);
+  gs->gimple_omp_single.clauses = clauses;
+}
+
+
 /* Return the clauses associated with OMP_SECTIONS GS.  */
 
 static inline tree
@@ -4936,8 +5195,11 @@ gimple_return_set_retval (gimple gs, tre
     case GIMPLE_OMP_SECTIONS:			\
     case GIMPLE_OMP_SECTIONS_SWITCH:		\
     case GIMPLE_OMP_SINGLE:			\
+    case GIMPLE_OMP_TARGET:			\
+    case GIMPLE_OMP_TEAMS:			\
     case GIMPLE_OMP_SECTION:			\
     case GIMPLE_OMP_MASTER:			\
+    case GIMPLE_OMP_TASKGROUP:			\
     case GIMPLE_OMP_ORDERED:			\
     case GIMPLE_OMP_CRITICAL:			\
     case GIMPLE_OMP_RETURN:			\
--- gcc/gimplify.c	(.../trunk)	(revision 203241)
+++ gcc/gimplify.c	(.../branches/gomp-4_0-branch)	(revision 203287)
@@ -56,9 +56,12 @@ enum gimplify_omp_var_data
   GOVD_LASTPRIVATE = 32,
   GOVD_REDUCTION = 64,
   GOVD_LOCAL = 128,
-  GOVD_DEBUG_PRIVATE = 256,
-  GOVD_PRIVATE_OUTER_REF = 512,
+  GOVD_MAP = 256,
+  GOVD_DEBUG_PRIVATE = 512,
+  GOVD_PRIVATE_OUTER_REF = 1024,
   GOVD_LINEAR = 2048,
+  GOVD_ALIGNED = 4096,
+  GOVD_MAP_TO_ONLY = 8192,
   GOVD_DATA_SHARE_CLASS = (GOVD_SHARED | GOVD_PRIVATE | GOVD_FIRSTPRIVATE
 			   | GOVD_LASTPRIVATE | GOVD_REDUCTION | GOVD_LINEAR
 			   | GOVD_LOCAL)
@@ -72,7 +75,10 @@ enum omp_region_type
   ORT_PARALLEL = 2,
   ORT_COMBINED_PARALLEL = 3,
   ORT_TASK = 4,
-  ORT_UNTIED_TASK = 5
+  ORT_UNTIED_TASK = 5,
+  ORT_TEAMS = 8,
+  ORT_TARGET_DATA = 16,
+  ORT_TARGET = 32
 };
 
 struct gimplify_omp_ctx
@@ -83,6 +89,7 @@ struct gimplify_omp_ctx
   location_t location;
   enum omp_clause_default_kind default_kind;
   enum omp_region_type region_type;
+  bool combined_loop;
 };
 
 static struct gimplify_ctx *gimplify_ctxp;
@@ -2698,7 +2705,14 @@ gimplify_call_expr (tree *expr_p, gimple
       notice_special_calls (call);
       gimplify_seq_add_stmt (pre_p, call);
       gsi = gsi_last (*pre_p);
-      fold_stmt (&gsi);
+      /* Don't fold stmts inside of target construct.  We'll do it
+	 during omplower pass instead.  */
+      struct gimplify_omp_ctx *ctx;
+      for (ctx = gimplify_omp_ctxp; ctx; ctx = ctx->outer_context)
+	if (ctx->region_type == ORT_TARGET)
+	  break;
+      if (ctx == NULL)
+	fold_stmt (&gsi);
       *expr_p = NULL_TREE;
     }
   else
@@ -4710,10 +4724,12 @@ is_gimple_stmt (tree t)
     case OMP_PARALLEL:
     case OMP_FOR:
     case OMP_SIMD:
+    case OMP_DISTRIBUTE:
     case OMP_SECTIONS:
     case OMP_SECTION:
     case OMP_SINGLE:
     case OMP_MASTER:
+    case OMP_TASKGROUP:
     case OMP_ORDERED:
     case OMP_CRITICAL:
     case OMP_TASK:
@@ -4954,7 +4970,14 @@ gimplify_modify_expr (tree *expr_p, gimp
 
   gimplify_seq_add_stmt (pre_p, assign);
   gsi = gsi_last (*pre_p);
-  fold_stmt (&gsi);
+  /* Don't fold stmts inside of target construct.  We'll do it
+     during omplower pass instead.  */
+  struct gimplify_omp_ctx *ctx;
+  for (ctx = gimplify_omp_ctxp; ctx; ctx = ctx->outer_context)
+    if (ctx->region_type == ORT_TARGET)
+      break;
+  if (ctx == NULL)
+    fold_stmt (&gsi);
 
   if (want_value)
     {
@@ -5729,11 +5752,16 @@ omp_firstprivatize_variable (struct gimp
 	{
 	  if (n->value & GOVD_SHARED)
 	    n->value = GOVD_FIRSTPRIVATE | (n->value & GOVD_SEEN);
+	  else if (n->value & GOVD_MAP)
+	    n->value |= GOVD_MAP_TO_ONLY;
 	  else
 	    return;
 	}
+      else if (ctx->region_type == ORT_TARGET)
+	omp_add_variable (ctx, decl, GOVD_MAP | GOVD_MAP_TO_ONLY);
       else if (ctx->region_type != ORT_WORKSHARE
-	       && ctx->region_type != ORT_SIMD)
+	       && ctx->region_type != ORT_SIMD
+	       && ctx->region_type != ORT_TARGET_DATA)
 	omp_add_variable (ctx, decl, GOVD_FIRSTPRIVATE);
 
       ctx = ctx->outer_context;
@@ -5816,7 +5844,7 @@ omp_add_variable (struct gimplify_omp_ct
     flags |= GOVD_SEEN;
 
   n = splay_tree_lookup (ctx->variables, (splay_tree_key)decl);
-  if (n != NULL)
+  if (n != NULL && n->value != GOVD_ALIGNED)
     {
       /* We shouldn't be re-adding the decl with the same data
 	 sharing class.  */
@@ -5842,7 +5870,9 @@ omp_add_variable (struct gimplify_omp_ct
 	 copy into or out of the context.  */
       if (!(flags & GOVD_LOCAL))
 	{
-	  nflags = flags & GOVD_PRIVATE ? GOVD_PRIVATE : GOVD_FIRSTPRIVATE;
+	  nflags = flags & GOVD_MAP
+		   ? GOVD_MAP | GOVD_MAP_TO_ONLY | GOVD_EXPLICIT
+		   : flags & GOVD_PRIVATE ? GOVD_PRIVATE : GOVD_FIRSTPRIVATE;
 	  nflags |= flags & GOVD_SEEN;
 	  t = DECL_VALUE_EXPR (decl);
 	  gcc_assert (TREE_CODE (t) == INDIRECT_REF);
@@ -5871,13 +5901,13 @@ omp_add_variable (struct gimplify_omp_ct
 	 For local variables TYPE_SIZE_UNIT might not be gimplified yet,
 	 in this case omp_notice_variable will be called later
 	 on when it is gimplified.  */
-      else if (! (flags & GOVD_LOCAL)
+      else if (! (flags & (GOVD_LOCAL | GOVD_MAP))
 	       && DECL_P (TYPE_SIZE_UNIT (TREE_TYPE (decl))))
 	omp_notice_variable (ctx, TYPE_SIZE_UNIT (TREE_TYPE (decl)), true);
     }
-  else if (lang_hooks.decls.omp_privatize_by_reference (decl))
+  else if ((flags & (GOVD_MAP | GOVD_LOCAL)) == 0
+	   && lang_hooks.decls.omp_privatize_by_reference (decl))
     {
-      gcc_assert ((flags & GOVD_LOCAL) == 0);
       omp_firstprivatize_type_sizes (ctx, TREE_TYPE (decl));
 
       /* Similar to the direct variable sized case above, we'll need the
@@ -5906,6 +5936,22 @@ omp_notice_threadprivate_variable (struc
 				   tree decl2)
 {
   splay_tree_node n;
+  struct gimplify_omp_ctx *octx;
+
+  for (octx = ctx; octx; octx = octx->outer_context)
+    if (octx->region_type == ORT_TARGET)
+      {
+	n = splay_tree_lookup (octx->variables, (splay_tree_key)decl);
+	if (n == NULL)
+	  {
+	    error ("threadprivate variable %qE used in target region",
+		   DECL_NAME (decl));
+	    error_at (octx->location, "enclosing target region");
+	    splay_tree_insert (octx->variables, (splay_tree_key)decl, 0);
+	  }
+	if (decl2)
+	  splay_tree_insert (octx->variables, (splay_tree_key)decl2, 0);
+      }
 
   if (ctx->region_type != ORT_UNTIED_TASK)
     return false;
@@ -5954,13 +6000,33 @@ omp_notice_variable (struct gimplify_omp
     }
 
   n = splay_tree_lookup (ctx->variables, (splay_tree_key)decl);
+  if (ctx->region_type == ORT_TARGET)
+    {
+      if (n == NULL)
+	{
+	  if (!lang_hooks.types.omp_mappable_type (TREE_TYPE (decl)))
+	    {
+	      error ("%qD referenced in target region does not have "
+		     "a mappable type", decl);
+	      omp_add_variable (ctx, decl, GOVD_MAP | GOVD_EXPLICIT | flags);
+	    }
+	  else
+	    omp_add_variable (ctx, decl, GOVD_MAP | flags);
+	}
+      else
+	n->value |= flags;
+      ret = lang_hooks.decls.omp_disregard_value_expr (decl, true);
+      goto do_outer;
+    }
+
   if (n == NULL)
     {
       enum omp_clause_default_kind default_kind, kind;
       struct gimplify_omp_ctx *octx;
 
       if (ctx->region_type == ORT_WORKSHARE
-	  || ctx->region_type == ORT_SIMD)
+	  || ctx->region_type == ORT_SIMD
+	  || ctx->region_type == ORT_TARGET_DATA)
 	goto do_outer;
 
       /* ??? Some compiler-generated variables (like SAVE_EXPRs) could be
@@ -5974,12 +6040,24 @@ omp_notice_variable (struct gimplify_omp
       switch (default_kind)
 	{
 	case OMP_CLAUSE_DEFAULT_NONE:
-	  error ("%qE not specified in enclosing parallel",
-		 DECL_NAME (lang_hooks.decls.omp_report_decl (decl)));
 	  if ((ctx->region_type & ORT_TASK) != 0)
-	    error_at (ctx->location, "enclosing task");
+	    {
+	      error ("%qE not specified in enclosing task",
+		     DECL_NAME (lang_hooks.decls.omp_report_decl (decl)));
+	      error_at (ctx->location, "enclosing task");
+	    }
+	  else if (ctx->region_type == ORT_TEAMS)
+	    {
+	      error ("%qE not specified in enclosing teams construct",
+		     DECL_NAME (lang_hooks.decls.omp_report_decl (decl)));
+	      error_at (ctx->location, "enclosing teams construct");
+	    }
 	  else
-	    error_at (ctx->location, "enclosing parallel");
+	    {
+	      error ("%qE not specified in enclosing parallel",
+		     DECL_NAME (lang_hooks.decls.omp_report_decl (decl)));
+	      error_at (ctx->location, "enclosing parallel");
+	    }
 	  /* FALLTHRU */
 	case OMP_CLAUSE_DEFAULT_SHARED:
 	  flags |= GOVD_SHARED;
@@ -5999,13 +6077,15 @@ omp_notice_variable (struct gimplify_omp
 	    {
 	      splay_tree_node n2;
 
+	      if ((octx->region_type & (ORT_TARGET_DATA | ORT_TARGET)) != 0)
+		continue;
 	      n2 = splay_tree_lookup (octx->variables, (splay_tree_key) decl);
 	      if (n2 && (n2->value & GOVD_DATA_SHARE_CLASS) != GOVD_SHARED)
 		{
 		  flags |= GOVD_FIRSTPRIVATE;
 		  break;
 		}
-	      if ((octx->region_type & ORT_PARALLEL) != 0)
+	      if ((octx->region_type & (ORT_PARALLEL | ORT_TEAMS)) != 0)
 		break;
 	    }
 	  if (flags & GOVD_FIRSTPRIVATE)
@@ -6147,6 +6227,9 @@ omp_check_private (struct gimplify_omp_c
 		 /* References might be private, but might be shared too.  */
 		 || lang_hooks.decls.omp_privatize_by_reference (decl));
 
+      if ((ctx->region_type & (ORT_TARGET | ORT_TARGET_DATA)) != 0)
+	continue;
+
       n = splay_tree_lookup (ctx->variables, (splay_tree_key) decl);
       if (n != NULL)
 	return (n->value & GOVD_SHARED) == 0;
@@ -6205,15 +6288,87 @@ gimplify_scan_omp_clauses (tree *list_p,
 	  flags = GOVD_REDUCTION | GOVD_SEEN | GOVD_EXPLICIT;
 	  check_non_private = "reduction";
 	  goto do_add;
-       case OMP_CLAUSE_LINEAR:
-	 if (gimplify_expr (&OMP_CLAUSE_LINEAR_STEP (c), pre_p, NULL,
-			    is_gimple_val, fb_rvalue) == GS_ERROR)
-	   {
-	     remove = true;
-	     break;
-	   }
-	 flags = GOVD_LINEAR | GOVD_EXPLICIT;
-	 goto do_add;
+	case OMP_CLAUSE_LINEAR:
+	  if (gimplify_expr (&OMP_CLAUSE_LINEAR_STEP (c), pre_p, NULL,
+			     is_gimple_val, fb_rvalue) == GS_ERROR)
+	    {
+	      remove = true;
+	      break;
+	    }
+	  flags = GOVD_LINEAR | GOVD_EXPLICIT;
+	  goto do_add;
+
+	case OMP_CLAUSE_MAP:
+	  if (OMP_CLAUSE_SIZE (c)
+	      && gimplify_expr (&OMP_CLAUSE_SIZE (c), pre_p,
+				NULL, is_gimple_val, fb_rvalue) == GS_ERROR)
+	    {
+	      remove = true;
+	      break;
+	    }
+	  decl = OMP_CLAUSE_DECL (c);
+	  if (!DECL_P (decl))
+	    {
+	      if (gimplify_expr (&OMP_CLAUSE_DECL (c), pre_p,
+				 NULL, is_gimple_lvalue, fb_lvalue)
+		  == GS_ERROR)
+		{
+		  remove = true;
+		  break;
+		}
+	      break;
+	    }
+	  flags = GOVD_MAP | GOVD_EXPLICIT;
+	  goto do_add;
+
+	case OMP_CLAUSE_DEPEND:
+	  if (TREE_CODE (OMP_CLAUSE_DECL (c)) == COMPOUND_EXPR)
+	    {
+	      gimplify_expr (&TREE_OPERAND (OMP_CLAUSE_DECL (c), 0), pre_p,
+			     NULL, is_gimple_val, fb_rvalue);
+	      OMP_CLAUSE_DECL (c) = TREE_OPERAND (OMP_CLAUSE_DECL (c), 1);
+	    }
+	  if (error_operand_p (OMP_CLAUSE_DECL (c)))
+	    {
+	      remove = true;
+	      break;
+	    }
+	  OMP_CLAUSE_DECL (c) = build_fold_addr_expr (OMP_CLAUSE_DECL (c));
+	  if (gimplify_expr (&OMP_CLAUSE_DECL (c), pre_p, NULL,
+			     is_gimple_val, fb_rvalue) == GS_ERROR)
+	    {
+	      remove = true;
+	      break;
+	    }
+	  break;
+
+	case OMP_CLAUSE_TO:
+	case OMP_CLAUSE_FROM:
+	  if (OMP_CLAUSE_SIZE (c)
+	      && gimplify_expr (&OMP_CLAUSE_SIZE (c), pre_p,
+				NULL, is_gimple_val, fb_rvalue) == GS_ERROR)
+	    {
+	      remove = true;
+	      break;
+	    }
+	  decl = OMP_CLAUSE_DECL (c);
+	  if (error_operand_p (decl))
+	    {
+	      remove = true;
+	      break;
+	    }
+	  if (!DECL_P (decl))
+	    {
+	      if (gimplify_expr (&OMP_CLAUSE_DECL (c), pre_p,
+				 NULL, is_gimple_lvalue, fb_lvalue)
+		  == GS_ERROR)
+		{
+		  remove = true;
+		  break;
+		}
+	      break;
+	    }
+	  goto do_notice;
 
 	do_add:
 	  decl = OMP_CLAUSE_DECL (c);
@@ -6302,9 +6457,13 @@ gimplify_scan_omp_clauses (tree *list_p,
 
 	case OMP_CLAUSE_SCHEDULE:
 	case OMP_CLAUSE_NUM_THREADS:
+	case OMP_CLAUSE_NUM_TEAMS:
+	case OMP_CLAUSE_THREAD_LIMIT:
+	case OMP_CLAUSE_DIST_SCHEDULE:
+	case OMP_CLAUSE_DEVICE:
 	  if (gimplify_expr (&OMP_CLAUSE_OPERAND (c, 0), pre_p, NULL,
 			     is_gimple_val, fb_rvalue) == GS_ERROR)
-	      remove = true;
+	    remove = true;
 	  break;
 
 	case OMP_CLAUSE_NOWAIT:
@@ -6312,9 +6471,22 @@ gimplify_scan_omp_clauses (tree *list_p,
 	case OMP_CLAUSE_UNTIED:
 	case OMP_CLAUSE_COLLAPSE:
 	case OMP_CLAUSE_MERGEABLE:
+	case OMP_CLAUSE_PROC_BIND:
 	case OMP_CLAUSE_SAFELEN:
 	  break;
 
+	case OMP_CLAUSE_ALIGNED:
+	  decl = OMP_CLAUSE_DECL (c);
+	  if (error_operand_p (decl))
+	    {
+	      remove = true;
+	      break;
+	    }
+	  if (!is_global_var (decl)
+	      && TREE_CODE (TREE_TYPE (decl)) == POINTER_TYPE)
+	    omp_add_variable (ctx, decl, GOVD_ALIGNED);
+	  break;
+
 	case OMP_CLAUSE_DEFAULT:
 	  ctx->default_kind = OMP_CLAUSE_DEFAULT_KIND (c);
 	  break;
@@ -6354,12 +6526,16 @@ gimplify_adjust_omp_clauses_1 (splay_tre
       gcc_assert ((flags & GOVD_DATA_SHARE_CLASS) == GOVD_PRIVATE);
       private_debug = true;
     }
+  else if (flags & GOVD_MAP)
+    private_debug = false;
   else
     private_debug
       = lang_hooks.decls.omp_private_debug_clause (decl,
 						   !!(flags & GOVD_SHARED));
   if (private_debug)
     code = OMP_CLAUSE_PRIVATE;
+  else if (flags & GOVD_MAP)
+    code = OMP_CLAUSE_MAP;
   else if (flags & GOVD_SHARED)
     {
       if (is_global_var (decl))
@@ -6386,6 +6562,8 @@ gimplify_adjust_omp_clauses_1 (splay_tre
     code = OMP_CLAUSE_FIRSTPRIVATE;
   else if (flags & GOVD_LASTPRIVATE)
     code = OMP_CLAUSE_LASTPRIVATE;
+  else if (flags & GOVD_ALIGNED)
+    return 0;
   else
     gcc_unreachable ();
 
@@ -6396,6 +6574,36 @@ gimplify_adjust_omp_clauses_1 (splay_tre
     OMP_CLAUSE_PRIVATE_DEBUG (clause) = 1;
   else if (code == OMP_CLAUSE_PRIVATE && (flags & GOVD_PRIVATE_OUTER_REF))
     OMP_CLAUSE_PRIVATE_OUTER_REF (clause) = 1;
+  else if (code == OMP_CLAUSE_MAP)
+    {
+      OMP_CLAUSE_MAP_KIND (clause) = flags & GOVD_MAP_TO_ONLY
+				     ? OMP_CLAUSE_MAP_TO
+				     : OMP_CLAUSE_MAP_TOFROM;
+      if (DECL_SIZE (decl)
+	  && TREE_CODE (DECL_SIZE (decl)) != INTEGER_CST)
+	{
+	  tree decl2 = DECL_VALUE_EXPR (decl);
+	  gcc_assert (TREE_CODE (decl2) == INDIRECT_REF);
+	  decl2 = TREE_OPERAND (decl2, 0);
+	  gcc_assert (DECL_P (decl2));
+	  tree mem = build_simple_mem_ref (decl2);
+	  OMP_CLAUSE_DECL (clause) = mem;
+	  OMP_CLAUSE_SIZE (clause) = TYPE_SIZE_UNIT (TREE_TYPE (decl));
+	  if (gimplify_omp_ctxp->outer_context)
+	    {
+	      struct gimplify_omp_ctx *ctx = gimplify_omp_ctxp->outer_context;
+	      omp_notice_variable (ctx, decl2, true);
+	      omp_notice_variable (ctx, OMP_CLAUSE_SIZE (clause), true);
+	    }
+	  tree nc = build_omp_clause (OMP_CLAUSE_LOCATION (clause),
+				      OMP_CLAUSE_MAP);
+	  OMP_CLAUSE_DECL (nc) = decl;
+	  OMP_CLAUSE_SIZE (nc) = size_zero_node;
+	  OMP_CLAUSE_MAP_KIND (nc) = OMP_CLAUSE_MAP_POINTER;
+	  OMP_CLAUSE_CHAIN (nc) = OMP_CLAUSE_CHAIN (clause);
+	  OMP_CLAUSE_CHAIN (clause) = nc;
+	}
+    }
   *list_p = clause;
   lang_hooks.decls.omp_finish_clause (clause);
 
@@ -6471,11 +6679,116 @@ gimplify_adjust_omp_clauses (tree *list_
 	    = (n->value & GOVD_FIRSTPRIVATE) != 0;
 	  break;
 
+	case OMP_CLAUSE_ALIGNED:
+	  decl = OMP_CLAUSE_DECL (c);
+	  if (!is_global_var (decl))
+	    {
+	      n = splay_tree_lookup (ctx->variables, (splay_tree_key) decl);
+	      remove = n == NULL || !(n->value & GOVD_SEEN);
+	      if (!remove && TREE_CODE (TREE_TYPE (decl)) == POINTER_TYPE)
+		{
+		  struct gimplify_omp_ctx *octx;
+		  if (n != NULL
+		      && (n->value & (GOVD_DATA_SHARE_CLASS
+				      & ~GOVD_FIRSTPRIVATE)))
+		    remove = true;
+		  else
+		    for (octx = ctx->outer_context; octx;
+			 octx = octx->outer_context)
+		      {
+			n = splay_tree_lookup (octx->variables,
+					       (splay_tree_key) decl);
+			if (n == NULL)
+			  continue;
+			if (n->value & GOVD_LOCAL)
+			  break;
+			/* We have to avoid assigning a shared variable
+			   to itself when trying to add
+			   __builtin_assume_aligned.  */
+			if (n->value & GOVD_SHARED)
+			  {
+			    remove = true;
+			    break;
+			  }
+		      }
+		}
+	    }
+	  else if (TREE_CODE (TREE_TYPE (decl)) == ARRAY_TYPE)
+	    {
+	      n = splay_tree_lookup (ctx->variables, (splay_tree_key) decl);
+	      if (n != NULL && (n->value & GOVD_DATA_SHARE_CLASS) != 0)
+		remove = true;
+	    }
+	  break;
+
+	case OMP_CLAUSE_MAP:
+	  decl = OMP_CLAUSE_DECL (c);
+	  if (!DECL_P (decl))
+	    break;
+	  n = splay_tree_lookup (ctx->variables, (splay_tree_key) decl);
+	  if (ctx->region_type == ORT_TARGET && !(n->value & GOVD_SEEN))
+	    remove = true;
+	  else if (DECL_SIZE (decl)
+		   && TREE_CODE (DECL_SIZE (decl)) != INTEGER_CST
+		   && OMP_CLAUSE_MAP_KIND (c) != OMP_CLAUSE_MAP_POINTER)
+	    {
+	      tree decl2 = DECL_VALUE_EXPR (decl);
+	      gcc_assert (TREE_CODE (decl2) == INDIRECT_REF);
+	      decl2 = TREE_OPERAND (decl2, 0);
+	      gcc_assert (DECL_P (decl2));
+	      tree mem = build_simple_mem_ref (decl2);
+	      OMP_CLAUSE_DECL (c) = mem;
+	      OMP_CLAUSE_SIZE (c) = TYPE_SIZE_UNIT (TREE_TYPE (decl));
+	      if (ctx->outer_context)
+		{
+		  omp_notice_variable (ctx->outer_context, decl2, true);
+		  omp_notice_variable (ctx->outer_context,
+				       OMP_CLAUSE_SIZE (c), true);
+		}
+	      tree nc = build_omp_clause (OMP_CLAUSE_LOCATION (c),
+					  OMP_CLAUSE_MAP);
+	      OMP_CLAUSE_DECL (nc) = decl;
+	      OMP_CLAUSE_SIZE (nc) = size_zero_node;
+	      OMP_CLAUSE_MAP_KIND (nc) = OMP_CLAUSE_MAP_POINTER;
+	      OMP_CLAUSE_CHAIN (nc) = OMP_CLAUSE_CHAIN (c);
+	      OMP_CLAUSE_CHAIN (c) = nc;
+	      c = nc;
+	    }
+	  break;
+
+	case OMP_CLAUSE_TO:
+	case OMP_CLAUSE_FROM:
+	  decl = OMP_CLAUSE_DECL (c);
+	  if (!DECL_P (decl))
+	    break;
+	  if (DECL_SIZE (decl)
+	      && TREE_CODE (DECL_SIZE (decl)) != INTEGER_CST)
+	    {
+	      tree decl2 = DECL_VALUE_EXPR (decl);
+	      gcc_assert (TREE_CODE (decl2) == INDIRECT_REF);
+	      decl2 = TREE_OPERAND (decl2, 0);
+	      gcc_assert (DECL_P (decl2));
+	      tree mem = build_simple_mem_ref (decl2);
+	      OMP_CLAUSE_DECL (c) = mem;
+	      OMP_CLAUSE_SIZE (c) = TYPE_SIZE_UNIT (TREE_TYPE (decl));
+	      if (ctx->outer_context)
+		{
+		  omp_notice_variable (ctx->outer_context, decl2, true);
+		  omp_notice_variable (ctx->outer_context,
+				       OMP_CLAUSE_SIZE (c), true);
+		}
+	    }
+	  break;
+
 	case OMP_CLAUSE_REDUCTION:
 	case OMP_CLAUSE_COPYIN:
 	case OMP_CLAUSE_COPYPRIVATE:
 	case OMP_CLAUSE_IF:
 	case OMP_CLAUSE_NUM_THREADS:
+	case OMP_CLAUSE_NUM_TEAMS:
+	case OMP_CLAUSE_THREAD_LIMIT:
+	case OMP_CLAUSE_DIST_SCHEDULE:
+	case OMP_CLAUSE_DEVICE:
 	case OMP_CLAUSE_SCHEDULE:
 	case OMP_CLAUSE_NOWAIT:
 	case OMP_CLAUSE_ORDERED:
@@ -6484,7 +6797,9 @@ gimplify_adjust_omp_clauses (tree *list_
 	case OMP_CLAUSE_COLLAPSE:
 	case OMP_CLAUSE_FINAL:
 	case OMP_CLAUSE_MERGEABLE:
+	case OMP_CLAUSE_PROC_BIND:
 	case OMP_CLAUSE_SAFELEN:
+	case OMP_CLAUSE_DEPEND:
 	  break;
 
 	default:
@@ -6577,12 +6892,39 @@ gimplify_omp_task (tree *expr_p, gimple_
   *expr_p = NULL_TREE;
 }
 
+/* Helper function of gimplify_omp_for, find OMP_FOR resp. OMP_SIMD
+   with non-NULL OMP_FOR_INIT.  */
+
+static tree
+find_combined_omp_for (tree *tp, int *walk_subtrees, void *)
+{
+  *walk_subtrees = 0;
+  switch (TREE_CODE (*tp))
+    {
+    case OMP_FOR:
+      *walk_subtrees = 1;
+      /* FALLTHRU */
+    case OMP_SIMD:
+      if (OMP_FOR_INIT (*tp) != NULL_TREE)
+	return *tp;
+      break;
+    case BIND_EXPR:
+    case STATEMENT_LIST:
+    case OMP_PARALLEL:
+      *walk_subtrees = 1;
+      break;
+    default:
+      break;
+    }
+  return NULL_TREE;
+}
+
 /* Gimplify the gross structure of an OMP_FOR statement.  */
 
 static enum gimplify_status
 gimplify_omp_for (tree *expr_p, gimple_seq *pre_p)
 {
-  tree for_stmt, decl, var, t;
+  tree for_stmt, orig_for_stmt, decl, var, t;
   enum gimplify_status ret = GS_ALL_DONE;
   enum gimplify_status tret;
   gimple gfor;
@@ -6591,9 +6933,9 @@ gimplify_omp_for (tree *expr_p, gimple_s
   bool simd;
   bitmap has_decl_expr = NULL;
 
-  for_stmt = *expr_p;
+  orig_for_stmt = for_stmt = *expr_p;
 
-  simd = TREE_CODE (for_stmt) == OMP_SIMD; 
+  simd = TREE_CODE (for_stmt) == OMP_SIMD;
   gimplify_scan_omp_clauses (&OMP_FOR_CLAUSES (for_stmt), pre_p,
 			     simd ? ORT_SIMD : ORT_WORKSHARE);
 
@@ -6604,7 +6946,7 @@ gimplify_omp_for (tree *expr_p, gimple_s
       has_decl_expr = BITMAP_ALLOC (NULL);
       if (TREE_CODE (OMP_FOR_PRE_BODY (for_stmt)) == DECL_EXPR
 	  && TREE_CODE (DECL_EXPR_DECL (OMP_FOR_PRE_BODY (for_stmt)))
-	  == VAR_DECL)
+	     == VAR_DECL)
 	{
 	  t = OMP_FOR_PRE_BODY (for_stmt);
 	  bitmap_set_bit (has_decl_expr, DECL_UID (DECL_EXPR_DECL (t)));
@@ -6625,6 +6967,14 @@ gimplify_omp_for (tree *expr_p, gimple_s
   gimplify_and_add (OMP_FOR_PRE_BODY (for_stmt), &for_pre_body);
   OMP_FOR_PRE_BODY (for_stmt) = NULL_TREE;
 
+  if (OMP_FOR_INIT (for_stmt) == NULL_TREE)
+    {
+      for_stmt = walk_tree (&OMP_FOR_BODY (for_stmt), find_combined_omp_for,
+			    NULL, NULL);
+      gcc_assert (for_stmt != NULL_TREE);
+      gimplify_omp_ctxp->combined_loop = true;
+    }
+
   for_body = NULL;
   gcc_assert (TREE_VEC_LENGTH (OMP_FOR_INIT (for_stmt))
 	      == TREE_VEC_LENGTH (OMP_FOR_COND (for_stmt)));
@@ -6641,7 +6991,9 @@ gimplify_omp_for (tree *expr_p, gimple_s
 
       /* Make sure the iteration variable is private.  */
       tree c = NULL_TREE;
-      if (simd)
+      if (orig_for_stmt != for_stmt)
+	/* Do this only on innermost construct for combined ones.  */;
+      else if (simd)
 	{
 	  splay_tree_node n = splay_tree_lookup (gimplify_omp_ctxp->variables,
 						 (splay_tree_key)decl);
@@ -6685,7 +7037,9 @@ gimplify_omp_for (tree *expr_p, gimple_s
       /* If DECL is not a gimple register, create a temporary variable to act
 	 as an iteration counter.  This is valid, since DECL cannot be
 	 modified in the body of the loop.  */
-      if (!is_gimple_reg (decl))
+      if (orig_for_stmt != for_stmt)
+	var = decl;
+      else if (!is_gimple_reg (decl))
 	{
 	  var = create_tmp_var (TREE_TYPE (decl), get_name (decl));
 	  TREE_OPERAND (t, 0) = var;
@@ -6718,6 +7072,8 @@ gimplify_omp_for (tree *expr_p, gimple_s
 	{
 	case PREINCREMENT_EXPR:
 	case POSTINCREMENT_EXPR:
+	  if (orig_for_stmt != for_stmt)
+	    break;
 	  t = build_int_cst (TREE_TYPE (decl), 1);
 	  if (c)
 	    OMP_CLAUSE_LINEAR_STEP (c) = t;
@@ -6728,6 +7084,8 @@ gimplify_omp_for (tree *expr_p, gimple_s
 
 	case PREDECREMENT_EXPR:
 	case POSTDECREMENT_EXPR:
+	  if (orig_for_stmt != for_stmt)
+	    break;
 	  t = build_int_cst (TREE_TYPE (decl), -1);
 	  if (c)
 	    OMP_CLAUSE_LINEAR_STEP (c) = t;
@@ -6784,9 +7142,9 @@ gimplify_omp_for (tree *expr_p, gimple_s
 	  gcc_unreachable ();
 	}
 
-      if (var != decl || TREE_VEC_LENGTH (OMP_FOR_INIT (for_stmt)) > 1)
+      if ((var != decl || TREE_VEC_LENGTH (OMP_FOR_INIT (for_stmt)) > 1)
+	  && orig_for_stmt == for_stmt)
 	{
-	  tree c;
 	  for (c = OMP_FOR_CLAUSES (for_stmt); c ; c = OMP_CLAUSE_CHAIN (c))
 	    if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_LASTPRIVATE
 		&& OMP_CLAUSE_DECL (c) == decl
@@ -6810,21 +7168,49 @@ gimplify_omp_for (tree *expr_p, gimple_s
 
   BITMAP_FREE (has_decl_expr);
 
-  gimplify_and_add (OMP_FOR_BODY (for_stmt), &for_body);
+  gimplify_and_add (OMP_FOR_BODY (orig_for_stmt), &for_body);
 
-  gimplify_adjust_omp_clauses (&OMP_FOR_CLAUSES (for_stmt));
+  if (orig_for_stmt != for_stmt)
+    for (i = 0; i < TREE_VEC_LENGTH (OMP_FOR_INIT (for_stmt)); i++)
+      {
+	t = TREE_VEC_ELT (OMP_FOR_INIT (for_stmt), i);
+	decl = TREE_OPERAND (t, 0);
+	var = create_tmp_var (TREE_TYPE (decl), get_name (decl));
+	omp_add_variable (gimplify_omp_ctxp, var, GOVD_PRIVATE | GOVD_SEEN);
+	TREE_OPERAND (t, 0) = var;
+	t = TREE_VEC_ELT (OMP_FOR_INCR (for_stmt), i);
+	TREE_OPERAND (t, 1) = copy_node (TREE_OPERAND (t, 1));
+	TREE_OPERAND (TREE_OPERAND (t, 1), 0) = var;
+      }
+
+  gimplify_adjust_omp_clauses (&OMP_FOR_CLAUSES (orig_for_stmt));
 
   int kind;
-  switch (TREE_CODE (for_stmt))
+  switch (TREE_CODE (orig_for_stmt))
     {
     case OMP_FOR: kind = GF_OMP_FOR_KIND_FOR; break;
     case OMP_SIMD: kind = GF_OMP_FOR_KIND_SIMD; break;
+    case OMP_DISTRIBUTE: kind = GF_OMP_FOR_KIND_DISTRIBUTE; break;
     default:
       gcc_unreachable ();
     }
-  gfor = gimple_build_omp_for (for_body, kind, OMP_FOR_CLAUSES (for_stmt),
+  gfor = gimple_build_omp_for (for_body, kind, OMP_FOR_CLAUSES (orig_for_stmt),
 			       TREE_VEC_LENGTH (OMP_FOR_INIT (for_stmt)),
 			       for_pre_body);
+  if (orig_for_stmt != for_stmt)
+    gimple_omp_for_set_combined_p (gfor, true);
+  if (gimplify_omp_ctxp
+      && (gimplify_omp_ctxp->combined_loop
+	  || (gimplify_omp_ctxp->region_type == ORT_COMBINED_PARALLEL
+	      && gimplify_omp_ctxp->outer_context
+	      && gimplify_omp_ctxp->outer_context->combined_loop)))
+    {
+      gimple_omp_for_set_combined_into_p (gfor, true);
+      if (gimplify_omp_ctxp->combined_loop)
+	gcc_assert (TREE_CODE (orig_for_stmt) == OMP_SIMD);
+      else
+	gcc_assert (TREE_CODE (orig_for_stmt) == OMP_FOR);
+    }
 
   for (i = 0; i < TREE_VEC_LENGTH (OMP_FOR_INIT (for_stmt)); i++)
     {
@@ -6845,8 +7231,9 @@ gimplify_omp_for (tree *expr_p, gimple_s
   return GS_ALL_DONE;
 }
 
-/* Gimplify the gross structure of other OpenMP worksharing constructs.
-   In particular, OMP_SECTIONS and OMP_SINGLE.  */
+/* Gimplify the gross structure of other OpenMP constructs.
+   In particular, OMP_SECTIONS, OMP_SINGLE, OMP_TARGET, OMP_TARGET_DATA
+   and OMP_TEAMS.  */
 
 static void
 gimplify_omp_workshare (tree *expr_p, gimple_seq *pre_p)
@@ -6854,19 +7241,93 @@ gimplify_omp_workshare (tree *expr_p, gi
   tree expr = *expr_p;
   gimple stmt;
   gimple_seq body = NULL;
+  enum omp_region_type ort = ORT_WORKSHARE;
 
-  gimplify_scan_omp_clauses (&OMP_CLAUSES (expr), pre_p, ORT_WORKSHARE);
-  gimplify_and_add (OMP_BODY (expr), &body);
+  switch (TREE_CODE (expr))
+    {
+    case OMP_SECTIONS:
+    case OMP_SINGLE:
+      break;
+    case OMP_TARGET:
+      ort = ORT_TARGET;
+      break;
+    case OMP_TARGET_DATA:
+      ort = ORT_TARGET_DATA;
+      break;
+    case OMP_TEAMS:
+      ort = ORT_TEAMS;
+      break;
+    default:
+      gcc_unreachable ();
+    }
+  gimplify_scan_omp_clauses (&OMP_CLAUSES (expr), pre_p, ort);
+  if (ort == ORT_TARGET || ort == ORT_TARGET_DATA)
+    {
+      struct gimplify_ctx gctx;
+      push_gimplify_context (&gctx);
+      gimple g = gimplify_and_return_first (OMP_BODY (expr), &body);
+      if (gimple_code (g) == GIMPLE_BIND)
+	pop_gimplify_context (g);
+      else
+	pop_gimplify_context (NULL);
+      if (ort == ORT_TARGET_DATA)
+	{
+	  gimple_seq cleanup = NULL;
+	  tree fn = builtin_decl_explicit (BUILT_IN_GOMP_TARGET_END_DATA);
+	  g = gimple_build_call (fn, 0);
+	  gimple_seq_add_stmt (&cleanup, g);
+	  g = gimple_build_try (body, cleanup, GIMPLE_TRY_FINALLY);
+	  body = NULL;
+	  gimple_seq_add_stmt (&body, g);
+	}
+    }
+  else
+    gimplify_and_add (OMP_BODY (expr), &body);
   gimplify_adjust_omp_clauses (&OMP_CLAUSES (expr));
 
-  if (TREE_CODE (expr) == OMP_SECTIONS)
-    stmt = gimple_build_omp_sections (body, OMP_CLAUSES (expr));
-  else if (TREE_CODE (expr) == OMP_SINGLE)
-    stmt = gimple_build_omp_single (body, OMP_CLAUSES (expr));
-  else
-    gcc_unreachable ();
+  switch (TREE_CODE (expr))
+    {
+    case OMP_SECTIONS:
+      stmt = gimple_build_omp_sections (body, OMP_CLAUSES (expr));
+      break;
+    case OMP_SINGLE:
+      stmt = gimple_build_omp_single (body, OMP_CLAUSES (expr));
+      break;
+    case OMP_TARGET:
+      stmt = gimple_build_omp_target (body, GF_OMP_TARGET_KIND_REGION,
+				      OMP_CLAUSES (expr));
+      break;
+    case OMP_TARGET_DATA:
+      stmt = gimple_build_omp_target (body, GF_OMP_TARGET_KIND_DATA,
+				      OMP_CLAUSES (expr));
+      break;
+    case OMP_TEAMS:
+      stmt = gimple_build_omp_teams (body, OMP_CLAUSES (expr));
+      break;
+    default:
+      gcc_unreachable ();
+    }
+
+  gimplify_seq_add_stmt (pre_p, stmt);
+  *expr_p = NULL_TREE;
+}
+
+/* Gimplify the gross structure of OpenMP target update construct.  */
+
+static void
+gimplify_omp_target_update (tree *expr_p, gimple_seq *pre_p)
+{
+  tree expr = *expr_p;
+  gimple stmt;
+
+  gimplify_scan_omp_clauses (&OMP_TARGET_UPDATE_CLAUSES (expr), pre_p,
+			     ORT_WORKSHARE);
+  gimplify_adjust_omp_clauses (&OMP_TARGET_UPDATE_CLAUSES (expr));
+  stmt = gimple_build_omp_target (NULL, GF_OMP_TARGET_KIND_UPDATE,
+				  OMP_TARGET_UPDATE_CLAUSES (expr));
 
   gimplify_seq_add_stmt (pre_p, stmt);
+  *expr_p = NULL_TREE;
 }
 
 /* A subroutine of gimplify_omp_atomic.  The front end is supposed to have
@@ -7005,6 +7466,11 @@ gimplify_omp_atomic (tree *expr_p, gimpl
     rhs = tmp_load;
   storestmt = gimple_build_omp_atomic_store (rhs);
   gimplify_seq_add_stmt (pre_p, storestmt);
+  if (OMP_ATOMIC_SEQ_CST (*expr_p))
+    {
+      gimple_omp_atomic_set_seq_cst (loadstmt);
+      gimple_omp_atomic_set_seq_cst (storestmt);
+    }
   switch (TREE_CODE (*expr_p))
     {
     case OMP_ATOMIC_READ:
@@ -7021,7 +7487,7 @@ gimplify_omp_atomic (tree *expr_p, gimpl
       break;
     }
 
-   return GS_ALL_DONE;
+  return GS_ALL_DONE;
 }
 
 /* Gimplify a TRANSACTION_EXPR.  This involves gimplification of the
@@ -7761,17 +8227,27 @@ gimplify_expr (tree *expr_p, gimple_seq
 
 	case OMP_FOR:
 	case OMP_SIMD:
+	case OMP_DISTRIBUTE:
 	  ret = gimplify_omp_for (expr_p, pre_p);
 	  break;
 
 	case OMP_SECTIONS:
 	case OMP_SINGLE:
+	case OMP_TARGET:
+	case OMP_TARGET_DATA:
+	case OMP_TEAMS:
 	  gimplify_omp_workshare (expr_p, pre_p);
 	  ret = GS_ALL_DONE;
 	  break;
 
+	case OMP_TARGET_UPDATE:
+	  gimplify_omp_target_update (expr_p, pre_p);
+	  ret = GS_ALL_DONE;
+	  break;
+
 	case OMP_SECTION:
 	case OMP_MASTER:
+	case OMP_TASKGROUP:
 	case OMP_ORDERED:
 	case OMP_CRITICAL:
 	  {
@@ -7787,6 +8263,19 @@ gimplify_expr (tree *expr_p, gimple_seq
 	      case OMP_MASTER:
 	        g = gimple_build_omp_master (body);
 		break;
+	      case OMP_TASKGROUP:
+		{
+		  gimple_seq cleanup = NULL;
+		  tree fn
+		    = builtin_decl_explicit (BUILT_IN_GOMP_TASKGROUP_END);
+		  g = gimple_build_call (fn, 0);
+		  gimple_seq_add_stmt (&cleanup, g);
+		  g = gimple_build_try (body, cleanup, GIMPLE_TRY_FINALLY);
+		  body = NULL;
+		  gimple_seq_add_stmt (&body, g);
+		  g = gimple_build_omp_taskgroup (body);
+		}
+		break;
 	      case OMP_ORDERED:
 		g = gimple_build_omp_ordered (body);
 		break;
@@ -8119,6 +8608,7 @@ gimplify_expr (tree *expr_p, gimple_seq
 		  && code != OMP_CRITICAL
 		  && code != OMP_FOR
 		  && code != OMP_MASTER
+		  && code != OMP_TASKGROUP
 		  && code != OMP_ORDERED
 		  && code != OMP_PARALLEL
 		  && code != OMP_SECTIONS
@@ -8343,6 +8833,13 @@ gimplify_body (tree fndecl, bool do_parm
   gcc_assert (gimplify_ctxp == NULL);
   push_gimplify_context (&gctx);
 
+  if (flag_openmp)
+    {
+      gcc_assert (gimplify_omp_ctxp == NULL);
+      if (lookup_attribute ("omp declare target", DECL_ATTRIBUTES (fndecl)))
+	gimplify_omp_ctxp = new_omp_context (ORT_TARGET);
+    }
+
   /* Unshare most shared trees in the body and in that of any nested functions.
      It would seem we don't have to do this for nested functions because
      they are supposed to be output and then the outer function gimplified
@@ -8405,6 +8902,12 @@ gimplify_body (tree fndecl, bool do_parm
       nonlocal_vlas = NULL;
     }
 
+  if (flag_openmp && gimplify_omp_ctxp)
+    {
+      delete_omp_context (gimplify_omp_ctxp);
+      gimplify_omp_ctxp = NULL;
+    }
+
   pop_gimplify_context (outer_bind);
   gcc_assert (gimplify_ctxp == NULL);
 
--- gcc/langhooks-def.h	(.../trunk)	(revision 203241)
+++ gcc/langhooks-def.h	(.../branches/gomp-4_0-branch)	(revision 203287)
@@ -77,6 +77,7 @@ extern tree lhd_omp_assignment (tree, tr
 struct gimplify_omp_ctx;
 extern void lhd_omp_firstprivatize_type_sizes (struct gimplify_omp_ctx *,
 					       tree);
+extern bool lhd_omp_mappable_type (tree);
 
 #define LANG_HOOKS_NAME			"GNU unknown"
 #define LANG_HOOKS_IDENTIFIER_SIZE	sizeof (struct lang_identifier)
@@ -166,6 +167,7 @@ extern tree lhd_make_node (enum tree_cod
 #define LANG_HOOKS_TYPE_MAX_SIZE	lhd_return_null_const_tree
 #define LANG_HOOKS_OMP_FIRSTPRIVATIZE_TYPE_SIZES \
   lhd_omp_firstprivatize_type_sizes
+#define LANG_HOOKS_OMP_MAPPABLE_TYPE	lhd_omp_mappable_type
 #define LANG_HOOKS_TYPE_HASH_EQ		NULL
 #define LANG_HOOKS_GET_ARRAY_DESCR_INFO	NULL
 #define LANG_HOOKS_GET_SUBRANGE_BOUNDS	NULL
@@ -184,6 +186,7 @@ extern tree lhd_make_node (enum tree_cod
   LANG_HOOKS_INCOMPLETE_TYPE_ERROR, \
   LANG_HOOKS_TYPE_MAX_SIZE, \
   LANG_HOOKS_OMP_FIRSTPRIVATIZE_TYPE_SIZES, \
+  LANG_HOOKS_OMP_MAPPABLE_TYPE, \
   LANG_HOOKS_TYPE_HASH_EQ, \
   LANG_HOOKS_GET_ARRAY_DESCR_INFO, \
   LANG_HOOKS_GET_SUBRANGE_BOUNDS, \
--- gcc/langhooks.c	(.../trunk)	(revision 203241)
+++ gcc/langhooks.c	(.../branches/gomp-4_0-branch)	(revision 203287)
@@ -523,6 +523,15 @@ lhd_omp_firstprivatize_type_sizes (struc
 {
 }
 
+/* Return true if TYPE is an OpenMP mappable type.  By default return true
+   if type is complete.  */
+
+bool
+lhd_omp_mappable_type (tree type)
+{
+  return COMPLETE_TYPE_P (type);
+}
+
 /* Common function for add_builtin_function and
    add_builtin_function_ext_scope.  */
 static tree
--- gcc/langhooks.h	(.../trunk)	(revision 203241)
+++ gcc/langhooks.h	(.../branches/gomp-4_0-branch)	(revision 203287)
@@ -111,6 +111,9 @@ struct lang_hooks_for_types
      firstprivate variables.  */
   void (*omp_firstprivatize_type_sizes) (struct gimplify_omp_ctx *, tree);
 
+  /* Return true if TYPE is a mappable type.  */
+  bool (*omp_mappable_type) (tree type);
+
   /* Return TRUE if TYPE1 and TYPE2 are identical for type hashing purposes.
      Called only after doing all language independent checks.
      At present, this function is only called when both TYPE1 and TYPE2 are
--- gcc/lto/lto-lang.c	(.../trunk)	(revision 203241)
+++ gcc/lto/lto-lang.c	(.../branches/gomp-4_0-branch)	(revision 203287)
@@ -140,6 +140,7 @@ enum lto_builtin_type
 #define DEF_FUNCTION_TYPE_5(NAME, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5) NAME,
 #define DEF_FUNCTION_TYPE_6(NAME, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5, ARG6) NAME,
 #define DEF_FUNCTION_TYPE_7(NAME, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5, ARG6, ARG7) NAME,
+#define DEF_FUNCTION_TYPE_8(NAME, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5, ARG6, ARG7, ARG8) NAME,
 #define DEF_FUNCTION_TYPE_VAR_0(NAME, RETURN) NAME,
 #define DEF_FUNCTION_TYPE_VAR_1(NAME, RETURN, ARG1) NAME,
 #define DEF_FUNCTION_TYPE_VAR_2(NAME, RETURN, ARG1, ARG2) NAME,
@@ -158,6 +159,7 @@ enum lto_builtin_type
 #undef DEF_FUNCTION_TYPE_5
 #undef DEF_FUNCTION_TYPE_6
 #undef DEF_FUNCTION_TYPE_7
+#undef DEF_FUNCTION_TYPE_8
 #undef DEF_FUNCTION_TYPE_VAR_0
 #undef DEF_FUNCTION_TYPE_VAR_1
 #undef DEF_FUNCTION_TYPE_VAR_2
@@ -631,6 +633,10 @@ lto_define_builtins (tree va_list_ref_ty
 #define DEF_FUNCTION_TYPE_7(ENUM, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5, \
 			    ARG6, ARG7)					\
   def_fn_type (ENUM, RETURN, 0, 7, ARG1, ARG2, ARG3, ARG4, ARG5, ARG6, ARG7);
+#define DEF_FUNCTION_TYPE_8(ENUM, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5, \
+			    ARG6, ARG7, ARG8)				\
+  def_fn_type (ENUM, RETURN, 0, 8, ARG1, ARG2, ARG3, ARG4, ARG5, ARG6,	\
+	       ARG7, ARG8);
 #define DEF_FUNCTION_TYPE_VAR_0(ENUM, RETURN) \
   def_fn_type (ENUM, RETURN, 1, 0);
 #define DEF_FUNCTION_TYPE_VAR_1(ENUM, RETURN, ARG1) \
--- gcc/omp-builtins.def	(.../trunk)	(revision 203241)
+++ gcc/omp-builtins.def	(.../branches/gomp-4_0-branch)	(revision 203287)
@@ -28,6 +28,10 @@ DEF_GOMP_BUILTIN (BUILT_IN_OMP_GET_THREA
 		  BT_FN_INT, ATTR_CONST_NOTHROW_LEAF_LIST)
 DEF_GOMP_BUILTIN (BUILT_IN_OMP_GET_NUM_THREADS, "omp_get_num_threads",
 		  BT_FN_INT, ATTR_CONST_NOTHROW_LEAF_LIST)
+DEF_GOMP_BUILTIN (BUILT_IN_OMP_GET_TEAM_NUM, "omp_get_team_num",
+		  BT_FN_INT, ATTR_CONST_NOTHROW_LEAF_LIST)
+DEF_GOMP_BUILTIN (BUILT_IN_OMP_GET_NUM_TEAMS, "omp_get_num_teams",
+		  BT_FN_INT, ATTR_CONST_NOTHROW_LEAF_LIST)
 
 DEF_GOMP_BUILTIN (BUILT_IN_GOMP_ATOMIC_START, "GOMP_atomic_start",
 		  BT_FN_VOID, ATTR_NOTHROW_LEAF_LIST)
@@ -35,10 +39,20 @@ DEF_GOMP_BUILTIN (BUILT_IN_GOMP_ATOMIC_E
 		  BT_FN_VOID, ATTR_NOTHROW_LEAF_LIST)
 DEF_GOMP_BUILTIN (BUILT_IN_GOMP_BARRIER, "GOMP_barrier",
 		  BT_FN_VOID, ATTR_NOTHROW_LEAF_LIST)
+DEF_GOMP_BUILTIN (BUILT_IN_GOMP_BARRIER_CANCEL, "GOMP_barrier_cancel",
+		  BT_FN_BOOL, ATTR_NOTHROW_LEAF_LIST)
 DEF_GOMP_BUILTIN (BUILT_IN_GOMP_TASKWAIT, "GOMP_taskwait",
 		  BT_FN_VOID, ATTR_NOTHROW_LEAF_LIST)
 DEF_GOMP_BUILTIN (BUILT_IN_GOMP_TASKYIELD, "GOMP_taskyield",
 		  BT_FN_VOID, ATTR_NOTHROW_LEAF_LIST)
+DEF_GOMP_BUILTIN (BUILT_IN_GOMP_TASKGROUP_START, "GOMP_taskgroup_start",
+		  BT_FN_VOID, ATTR_NOTHROW_LEAF_LIST)
+DEF_GOMP_BUILTIN (BUILT_IN_GOMP_TASKGROUP_END, "GOMP_taskgroup_end",
+		  BT_FN_VOID, ATTR_NOTHROW_LEAF_LIST)
+DEF_GOMP_BUILTIN (BUILT_IN_GOMP_CANCEL, "GOMP_cancel",
+		  BT_FN_BOOL_INT_BOOL, ATTR_NOTHROW_LEAF_LIST)
+DEF_GOMP_BUILTIN (BUILT_IN_GOMP_CANCELLATION_POINT, "GOMP_cancellation_point",
+		  BT_FN_BOOL_INT, ATTR_NOTHROW_LEAF_LIST)
 DEF_GOMP_BUILTIN (BUILT_IN_GOMP_CRITICAL_START, "GOMP_critical_start",
 		  BT_FN_VOID, ATTR_NOTHROW_LEAF_LIST)
 DEF_GOMP_BUILTIN (BUILT_IN_GOMP_CRITICAL_END, "GOMP_critical_end",
@@ -156,49 +170,52 @@ DEF_GOMP_BUILTIN (BUILT_IN_GOMP_LOOP_ULL
 DEF_GOMP_BUILTIN (BUILT_IN_GOMP_LOOP_ULL_ORDERED_RUNTIME_NEXT,
 		  "GOMP_loop_ull_ordered_runtime_next",
 		  BT_FN_BOOL_ULONGLONGPTR_ULONGLONGPTR, ATTR_NOTHROW_LEAF_LIST)
-/* NOTE: Do not change the order of BUILT_IN_GOMP_PARALLEL_LOOP_*_START.
+/* NOTE: Do not change the order of BUILT_IN_GOMP_PARALLEL_LOOP_*.
    They are used in index arithmetic with enum omp_clause_schedule_kind
    in omp-low.c.  */
-DEF_GOMP_BUILTIN (BUILT_IN_GOMP_PARALLEL_LOOP_STATIC_START,
-		  "GOMP_parallel_loop_static_start",
-		  BT_FN_VOID_OMPFN_PTR_UINT_LONG_LONG_LONG_LONG,
-		  ATTR_NOTHROW_LIST)
-DEF_GOMP_BUILTIN (BUILT_IN_GOMP_PARALLEL_LOOP_DYNAMIC_START,
-		  "GOMP_parallel_loop_dynamic_start",
-		  BT_FN_VOID_OMPFN_PTR_UINT_LONG_LONG_LONG_LONG,
-		  ATTR_NOTHROW_LIST)
-DEF_GOMP_BUILTIN (BUILT_IN_GOMP_PARALLEL_LOOP_GUIDED_START,
-		  "GOMP_parallel_loop_guided_start",
-		  BT_FN_VOID_OMPFN_PTR_UINT_LONG_LONG_LONG_LONG,
-		  ATTR_NOTHROW_LIST)
-DEF_GOMP_BUILTIN (BUILT_IN_GOMP_PARALLEL_LOOP_RUNTIME_START,
-		  "GOMP_parallel_loop_runtime_start",
-		  BT_FN_VOID_OMPFN_PTR_UINT_LONG_LONG_LONG,
+DEF_GOMP_BUILTIN (BUILT_IN_GOMP_PARALLEL_LOOP_STATIC,
+		  "GOMP_parallel_loop_static",
+		  BT_FN_VOID_OMPFN_PTR_UINT_LONG_LONG_LONG_LONG_UINT,
+		  ATTR_NOTHROW_LIST)
+DEF_GOMP_BUILTIN (BUILT_IN_GOMP_PARALLEL_LOOP_DYNAMIC,
+		  "GOMP_parallel_loop_dynamic",
+		  BT_FN_VOID_OMPFN_PTR_UINT_LONG_LONG_LONG_LONG_UINT,
+		  ATTR_NOTHROW_LIST)
+DEF_GOMP_BUILTIN (BUILT_IN_GOMP_PARALLEL_LOOP_GUIDED,
+		  "GOMP_parallel_loop_guided",
+		  BT_FN_VOID_OMPFN_PTR_UINT_LONG_LONG_LONG_LONG_UINT,
+		  ATTR_NOTHROW_LIST)
+DEF_GOMP_BUILTIN (BUILT_IN_GOMP_PARALLEL_LOOP_RUNTIME,
+		  "GOMP_parallel_loop_runtime",
+		  BT_FN_VOID_OMPFN_PTR_UINT_LONG_LONG_LONG_UINT,
 		  ATTR_NOTHROW_LIST)
 DEF_GOMP_BUILTIN (BUILT_IN_GOMP_LOOP_END, "GOMP_loop_end",
 		  BT_FN_VOID, ATTR_NOTHROW_LEAF_LIST)
+DEF_GOMP_BUILTIN (BUILT_IN_GOMP_LOOP_END_CANCEL, "GOMP_loop_end_cancel",
+		  BT_FN_BOOL, ATTR_NOTHROW_LEAF_LIST)
 DEF_GOMP_BUILTIN (BUILT_IN_GOMP_LOOP_END_NOWAIT, "GOMP_loop_end_nowait",
 		  BT_FN_VOID, ATTR_NOTHROW_LEAF_LIST)
 DEF_GOMP_BUILTIN (BUILT_IN_GOMP_ORDERED_START, "GOMP_ordered_start",
 		  BT_FN_VOID, ATTR_NOTHROW_LEAF_LIST)
 DEF_GOMP_BUILTIN (BUILT_IN_GOMP_ORDERED_END, "GOMP_ordered_end",
 		  BT_FN_VOID, ATTR_NOTHROW_LEAF_LIST)
-DEF_GOMP_BUILTIN (BUILT_IN_GOMP_PARALLEL_START, "GOMP_parallel_start",
-		  BT_FN_VOID_OMPFN_PTR_UINT, ATTR_NOTHROW_LIST)
-DEF_GOMP_BUILTIN (BUILT_IN_GOMP_PARALLEL_END, "GOMP_parallel_end",
-		  BT_FN_VOID, ATTR_NOTHROW_LEAF_LIST)
+DEF_GOMP_BUILTIN (BUILT_IN_GOMP_PARALLEL, "GOMP_parallel",
+		  BT_FN_VOID_OMPFN_PTR_UINT_UINT, ATTR_NOTHROW_LIST)
 DEF_GOMP_BUILTIN (BUILT_IN_GOMP_TASK, "GOMP_task",
-		  BT_FN_VOID_OMPFN_PTR_OMPCPYFN_LONG_LONG_BOOL_UINT,
+		  BT_FN_VOID_OMPFN_PTR_OMPCPYFN_LONG_LONG_BOOL_UINT_PTR,
 		  ATTR_NOTHROW_LIST)
 DEF_GOMP_BUILTIN (BUILT_IN_GOMP_SECTIONS_START, "GOMP_sections_start",
 		  BT_FN_UINT_UINT, ATTR_NOTHROW_LEAF_LIST)
 DEF_GOMP_BUILTIN (BUILT_IN_GOMP_SECTIONS_NEXT, "GOMP_sections_next",
 		  BT_FN_UINT, ATTR_NOTHROW_LEAF_LIST)
-DEF_GOMP_BUILTIN (BUILT_IN_GOMP_PARALLEL_SECTIONS_START,
-		  "GOMP_parallel_sections_start",
-		  BT_FN_VOID_OMPFN_PTR_UINT_UINT, ATTR_NOTHROW_LIST)
+DEF_GOMP_BUILTIN (BUILT_IN_GOMP_PARALLEL_SECTIONS,
+		  "GOMP_parallel_sections",
+		  BT_FN_VOID_OMPFN_PTR_UINT_UINT_UINT, ATTR_NOTHROW_LIST)
 DEF_GOMP_BUILTIN (BUILT_IN_GOMP_SECTIONS_END, "GOMP_sections_end",
 		  BT_FN_VOID, ATTR_NOTHROW_LEAF_LIST)
+DEF_GOMP_BUILTIN (BUILT_IN_GOMP_SECTIONS_END_CANCEL,
+		  "GOMP_sections_end_cancel",
+		  BT_FN_BOOL, ATTR_NOTHROW_LEAF_LIST)
 DEF_GOMP_BUILTIN (BUILT_IN_GOMP_SECTIONS_END_NOWAIT,
 		  "GOMP_sections_end_nowait",
 		  BT_FN_VOID, ATTR_NOTHROW_LEAF_LIST)
@@ -208,3 +225,14 @@ DEF_GOMP_BUILTIN (BUILT_IN_GOMP_SINGLE_C
 		  BT_FN_PTR, ATTR_NOTHROW_LEAF_LIST)
 DEF_GOMP_BUILTIN (BUILT_IN_GOMP_SINGLE_COPY_END, "GOMP_single_copy_end",
 		  BT_FN_VOID_PTR, ATTR_NOTHROW_LEAF_LIST)
+DEF_GOMP_BUILTIN (BUILT_IN_GOMP_TARGET, "GOMP_target",
+		  BT_FN_VOID_INT_OMPFN_PTR_SIZE_PTR_PTR_PTR,
+		  ATTR_NOTHROW_LIST)
+DEF_GOMP_BUILTIN (BUILT_IN_GOMP_TARGET_DATA, "GOMP_target_data",
+		  BT_FN_VOID_INT_PTR_SIZE_PTR_PTR_PTR, ATTR_NOTHROW_LIST)
+DEF_GOMP_BUILTIN (BUILT_IN_GOMP_TARGET_END_DATA, "GOMP_target_end_data",
+		  BT_FN_VOID, ATTR_NOTHROW_LIST)
+DEF_GOMP_BUILTIN (BUILT_IN_GOMP_TARGET_UPDATE, "GOMP_target_update",
+		  BT_FN_VOID_INT_PTR_SIZE_PTR_PTR_PTR, ATTR_NOTHROW_LIST)
+DEF_GOMP_BUILTIN (BUILT_IN_GOMP_TEAMS, "GOMP_teams",
+		  BT_FN_VOID_UINT_UINT, ATTR_NOTHROW_LIST)
--- gcc/omp-low.c	(.../trunk)	(revision 203241)
+++ gcc/omp-low.c	(.../branches/gomp-4_0-branch)	(revision 203287)
@@ -90,6 +90,10 @@ typedef struct omp_context
      construct.  In the case of a parallel, this is in the child function.  */
   tree block_vars;
 
+  /* Label to which GOMP_cancel{,llation_point} and explicit and implicit
+     barriers should jump to during omplower pass.  */
+  tree cancel_label;
+
   /* What to do with variables with implicitly determined sharing
      attributes.  */
   enum omp_clause_default_kind default_kind;
@@ -101,6 +105,9 @@ typedef struct omp_context
 
   /* True if this parallel directive is nested within another.  */
   bool is_nested;
+
+  /* True if this construct can be cancelled.  */
+  bool cancellable;
 } omp_context;
 
 
@@ -127,6 +134,7 @@ struct omp_for_data
 
 static splay_tree all_contexts;
 static int taskreg_nesting_level;
+static int target_nesting_level;
 struct omp_region *root_omp_region;
 static bitmap task_shared_vars;
 
@@ -224,6 +232,8 @@ extract_omp_for_data (gimple for_stmt, s
   struct omp_for_data_loop dummy_loop;
   location_t loc = gimple_location (for_stmt);
   bool simd = gimple_omp_for_kind (for_stmt) == GF_OMP_FOR_KIND_SIMD;
+  bool distribute = gimple_omp_for_kind (for_stmt)
+		    == GF_OMP_FOR_KIND_DISTRIBUTE;
 
   fd->for_stmt = for_stmt;
   fd->pre = NULL;
@@ -233,7 +243,8 @@ extract_omp_for_data (gimple for_stmt, s
   else
     fd->loops = &fd->loop;
 
-  fd->have_nowait = fd->have_ordered = false;
+  fd->have_nowait = distribute || simd;
+  fd->have_ordered = false;
   fd->sched_kind = OMP_CLAUSE_SCHEDULE_STATIC;
   fd->chunk_size = NULL_TREE;
   collapse_iter = NULL;
@@ -249,9 +260,14 @@ extract_omp_for_data (gimple for_stmt, s
 	fd->have_ordered = true;
 	break;
       case OMP_CLAUSE_SCHEDULE:
+	gcc_assert (!distribute);
 	fd->sched_kind = OMP_CLAUSE_SCHEDULE_KIND (t);
 	fd->chunk_size = OMP_CLAUSE_SCHEDULE_CHUNK_EXPR (t);
 	break;
+      case OMP_CLAUSE_DIST_SCHEDULE:
+	gcc_assert (distribute);
+	fd->chunk_size = OMP_CLAUSE_DIST_SCHEDULE_CHUNK_EXPR (t);
+	break;
       case OMP_CLAUSE_COLLAPSE:
 	if (fd->collapse > 1)
 	  {
@@ -279,8 +295,7 @@ extract_omp_for_data (gimple for_stmt, s
       /* We only need to compute a default chunk size for ordered
 	 static loops and dynamic loops.  */
       if (fd->sched_kind != OMP_CLAUSE_SCHEDULE_STATIC
-	  || fd->have_ordered
-	  || fd->collapse > 1)
+	  || fd->have_ordered)
 	fd->chunk_size = (fd->sched_kind == OMP_CLAUSE_SCHEDULE_STATIC)
 			 ? integer_zero_node : integer_one_node;
     }
@@ -294,7 +309,6 @@ extract_omp_for_data (gimple for_stmt, s
       else
 	loop = &dummy_loop;
 
-
       loop->v = gimple_omp_for_index (for_stmt, i);
       gcc_assert (SSA_VAR_P (loop->v));
       gcc_assert (TREE_CODE (TREE_TYPE (loop->v)) == INTEGER_TYPE
@@ -351,7 +365,9 @@ extract_omp_for_data (gimple for_stmt, s
 	  gcc_unreachable ();
 	}
 
-      if (simd)
+      if (simd
+	  || (fd->sched_kind == OMP_CLAUSE_SCHEDULE_STATIC
+	      && !fd->have_ordered))
 	{
 	  if (fd->collapse == 1)
 	    iter_type = TREE_TYPE (loop->v);
@@ -360,7 +376,7 @@ extract_omp_for_data (gimple for_stmt, s
 		      < TYPE_PRECISION (TREE_TYPE (loop->v)))
 	    iter_type
 	      = build_nonstandard_integer_type
-	      (TYPE_PRECISION (TREE_TYPE (loop->v)), 1);
+		  (TYPE_PRECISION (TREE_TYPE (loop->v)), 1);
 	}
       else if (iter_type != long_long_unsigned_type_node)
 	{
@@ -459,7 +475,9 @@ extract_omp_for_data (gimple for_stmt, s
     }
 
   if (count
-      && !simd)
+      && !simd
+      && (fd->sched_kind != OMP_CLAUSE_SCHEDULE_STATIC
+	  || fd->have_ordered))
     {
       if (!tree_int_cst_lt (count, TYPE_MAX_VALUE (long_integer_type_node)))
 	iter_type = long_long_unsigned_type_node;
@@ -570,7 +588,7 @@ workshare_safe_to_combine_p (basic_block
    expanded.  */
 
 static vec<tree, va_gc> *
-get_ws_args_for (gimple ws_stmt)
+get_ws_args_for (gimple par_stmt, gimple ws_stmt)
 {
   tree t;
   location_t loc = gimple_location (ws_stmt);
@@ -579,15 +597,31 @@ get_ws_args_for (gimple ws_stmt)
   if (gimple_code (ws_stmt) == GIMPLE_OMP_FOR)
     {
       struct omp_for_data fd;
+      tree n1, n2;
 
       extract_omp_for_data (ws_stmt, &fd, NULL);
+      n1 = fd.loop.n1;
+      n2 = fd.loop.n2;
+
+      if (gimple_omp_for_combined_into_p (ws_stmt))
+	{
+	  tree innerc
+	    = find_omp_clause (gimple_omp_parallel_clauses (par_stmt),
+			       OMP_CLAUSE__LOOPTEMP_);
+	  gcc_assert (innerc);
+	  n1 = OMP_CLAUSE_DECL (innerc);
+	  innerc = find_omp_clause (OMP_CLAUSE_CHAIN (innerc),
+				    OMP_CLAUSE__LOOPTEMP_);
+	  gcc_assert (innerc);
+	  n2 = OMP_CLAUSE_DECL (innerc);
+	}
 
       vec_alloc (ws_args, 3 + (fd.chunk_size != 0));
 
-      t = fold_convert_loc (loc, long_integer_type_node, fd.loop.n1);
+      t = fold_convert_loc (loc, long_integer_type_node, n1);
       ws_args->quick_push (t);
 
-      t = fold_convert_loc (loc, long_integer_type_node, fd.loop.n2);
+      t = fold_convert_loc (loc, long_integer_type_node, n2);
       ws_args->quick_push (t);
 
       t = fold_convert_loc (loc, long_integer_type_node, fd.loop.step);
@@ -650,6 +684,7 @@ determine_parallel_type (struct omp_regi
 	  || (last_and_only_stmt (ws_entry_bb)
 	      && last_and_only_stmt (par_exit_bb))))
     {
+      gimple par_stmt = last_stmt (par_entry_bb);
       gimple ws_stmt = last_stmt (ws_entry_bb);
 
       if (region->inner->type == GIMPLE_OMP_FOR)
@@ -677,7 +712,7 @@ determine_parallel_type (struct omp_regi
 
       region->is_combined_parallel = true;
       region->inner->is_combined_parallel = true;
-      region->ws_args = get_ws_args_for (ws_stmt);
+      region->ws_args = get_ws_args_for (par_stmt, ws_stmt);
     }
 }
 
@@ -984,7 +1019,12 @@ install_var_field (tree var, bool by_ref
 	      || !splay_tree_lookup (ctx->sfield_map, (splay_tree_key) var));
 
   type = TREE_TYPE (var);
-  if (by_ref)
+  if (mask & 4)
+    {
+      gcc_assert (TREE_CODE (type) == ARRAY_TYPE);
+      type = build_pointer_type (build_pointer_type (type));
+    }
+  else if (by_ref)
     type = build_pointer_type (type);
   else if ((mask & 3) == 1 && is_reference (var))
     type = TREE_TYPE (type);
@@ -1421,6 +1461,9 @@ scan_sharing_clauses (tree clauses, omp_
 	  break;
 
 	case OMP_CLAUSE_SHARED:
+	  /* Ignore shared directives in teams construct.  */
+	  if (gimple_code (ctx->stmt) == GIMPLE_OMP_TEAMS)
+	    break;
 	  gcc_assert (is_taskreg_ctx (ctx));
 	  decl = OMP_CLAUSE_DECL (c);
 	  gcc_assert (!COMPLETE_TYPE_P (TREE_TYPE (decl))
@@ -1480,6 +1523,13 @@ scan_sharing_clauses (tree clauses, omp_
 	  install_var_local (decl, ctx);
 	  break;
 
+	case OMP_CLAUSE__LOOPTEMP_:
+	  gcc_assert (is_parallel_ctx (ctx));
+	  decl = OMP_CLAUSE_DECL (c);
+	  install_var_field (decl, false, 3, ctx);
+	  install_var_local (decl, ctx);
+	  break;
+
 	case OMP_CLAUSE_COPYPRIVATE:
 	case OMP_CLAUSE_COPYIN:
 	  decl = OMP_CLAUSE_DECL (c);
@@ -1494,19 +1544,113 @@ scan_sharing_clauses (tree clauses, omp_
 	case OMP_CLAUSE_FINAL:
 	case OMP_CLAUSE_IF:
 	case OMP_CLAUSE_NUM_THREADS:
+	case OMP_CLAUSE_NUM_TEAMS:
+	case OMP_CLAUSE_THREAD_LIMIT:
+	case OMP_CLAUSE_DEVICE:
 	case OMP_CLAUSE_SCHEDULE:
+	case OMP_CLAUSE_DIST_SCHEDULE:
+	case OMP_CLAUSE_DEPEND:
 	  if (ctx->outer)
 	    scan_omp_op (&OMP_CLAUSE_OPERAND (c, 0), ctx->outer);
 	  break;
 
+	case OMP_CLAUSE_TO:
+	case OMP_CLAUSE_FROM:
+	case OMP_CLAUSE_MAP:
+	  if (ctx->outer)
+	    scan_omp_op (&OMP_CLAUSE_SIZE (c), ctx->outer);
+	  decl = OMP_CLAUSE_DECL (c);
+	  /* Global variables with "omp declare target" attribute
+	     don't need to be copied, the receiver side will use them
+	     directly.  */
+	  if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_MAP
+	      && DECL_P (decl)
+	      && is_global_var (maybe_lookup_decl_in_outer_ctx (decl, ctx))
+	      && lookup_attribute ("omp declare target",
+				   DECL_ATTRIBUTES (decl)))
+	    break;
+	  if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_MAP
+	      && OMP_CLAUSE_MAP_KIND (c) == OMP_CLAUSE_MAP_POINTER)
+	    {
+	      /* Ignore OMP_CLAUSE_MAP_POINTER kind for arrays in
+		 #pragma omp target data, there is nothing to map for
+		 those.  */
+	      if (gimple_omp_target_kind (ctx->stmt) == GF_OMP_TARGET_KIND_DATA
+		  && !POINTER_TYPE_P (TREE_TYPE (decl)))
+		break;
+	    }
+	  if (DECL_P (decl))
+	    {
+	      if (DECL_SIZE (decl)
+		  && TREE_CODE (DECL_SIZE (decl)) != INTEGER_CST)
+		{
+		  tree decl2 = DECL_VALUE_EXPR (decl);
+		  gcc_assert (TREE_CODE (decl2) == INDIRECT_REF);
+		  decl2 = TREE_OPERAND (decl2, 0);
+		  gcc_assert (DECL_P (decl2));
+		  install_var_field (decl2, true, 3, ctx);
+		  install_var_local (decl2, ctx);
+		  install_var_local (decl, ctx);
+		}
+	      else
+		{
+		  if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_MAP
+		      && OMP_CLAUSE_MAP_KIND (c) == OMP_CLAUSE_MAP_POINTER
+		      && !OMP_CLAUSE_MAP_ZERO_BIAS_ARRAY_SECTION (c)
+		      && TREE_CODE (TREE_TYPE (decl)) == ARRAY_TYPE)
+		    install_var_field (decl, true, 7, ctx);
+		  else
+		    install_var_field (decl, true, 3, ctx);
+		  if (gimple_omp_target_kind (ctx->stmt)
+		      == GF_OMP_TARGET_KIND_REGION)
+		    install_var_local (decl, ctx);
+		}
+	    }
+	  else
+	    {
+	      tree base = get_base_address (decl);
+	      tree nc = OMP_CLAUSE_CHAIN (c);
+	      if (DECL_P (base)
+		  && nc != NULL_TREE
+		  && OMP_CLAUSE_CODE (nc) == OMP_CLAUSE_MAP
+		  && OMP_CLAUSE_DECL (nc) == base
+		  && OMP_CLAUSE_MAP_KIND (nc) == OMP_CLAUSE_MAP_POINTER
+		  && integer_zerop (OMP_CLAUSE_SIZE (nc)))
+		{
+		  OMP_CLAUSE_MAP_ZERO_BIAS_ARRAY_SECTION (c) = 1;
+		  OMP_CLAUSE_MAP_ZERO_BIAS_ARRAY_SECTION (nc) = 1;
+		}
+	      else
+		{
+		  gcc_assert (!splay_tree_lookup (ctx->field_map,
+						  (splay_tree_key) decl));
+		  tree field
+		    = build_decl (OMP_CLAUSE_LOCATION (c),
+				  FIELD_DECL, NULL_TREE, ptr_type_node);
+		  DECL_ALIGN (field) = TYPE_ALIGN (ptr_type_node);
+		  insert_field_into_struct (ctx->record_type, field);
+		  splay_tree_insert (ctx->field_map, (splay_tree_key) decl,
+				     (splay_tree_value) field);
+		}
+	    }
+	  break;
+
 	case OMP_CLAUSE_NOWAIT:
 	case OMP_CLAUSE_ORDERED:
 	case OMP_CLAUSE_COLLAPSE:
 	case OMP_CLAUSE_UNTIED:
 	case OMP_CLAUSE_MERGEABLE:
+	case OMP_CLAUSE_PROC_BIND:
 	case OMP_CLAUSE_SAFELEN:
 	  break;
 
+	case OMP_CLAUSE_ALIGNED:
+	  decl = OMP_CLAUSE_DECL (c);
+	  if (is_global_var (decl)
+	      && TREE_CODE (TREE_TYPE (decl)) == ARRAY_TYPE)
+	    install_var_local (decl, ctx);
+	  break;
+
 	default:
 	  gcc_unreachable ();
 	}
@@ -1541,24 +1685,71 @@ scan_sharing_clauses (tree clauses, omp_
 	  break;
 
 	case OMP_CLAUSE_SHARED:
+	  /* Ignore shared directives in teams construct.  */
+	  if (gimple_code (ctx->stmt) == GIMPLE_OMP_TEAMS)
+	    break;
 	  decl = OMP_CLAUSE_DECL (c);
 	  if (! is_global_var (maybe_lookup_decl_in_outer_ctx (decl, ctx)))
 	    fixup_remapped_decl (decl, ctx, false);
 	  break;
 
+	case OMP_CLAUSE_MAP:
+	  if (gimple_omp_target_kind (ctx->stmt) == GF_OMP_TARGET_KIND_DATA)
+	    break;
+	  decl = OMP_CLAUSE_DECL (c);
+	  if (DECL_P (decl)
+	      && is_global_var (maybe_lookup_decl_in_outer_ctx (decl, ctx))
+	      && lookup_attribute ("omp declare target",
+				   DECL_ATTRIBUTES (decl)))
+	    break;
+	  if (DECL_P (decl))
+	    {
+	      if (OMP_CLAUSE_MAP_KIND (c) == OMP_CLAUSE_MAP_POINTER
+		  && TREE_CODE (TREE_TYPE (decl)) == ARRAY_TYPE
+		  && !COMPLETE_TYPE_P (TREE_TYPE (decl)))
+		{
+		  tree new_decl = lookup_decl (decl, ctx);
+		  TREE_TYPE (new_decl)
+		    = remap_type (TREE_TYPE (decl), &ctx->cb);
+		}
+	      else if (DECL_SIZE (decl)
+		       && TREE_CODE (DECL_SIZE (decl)) != INTEGER_CST)
+		{
+		  tree decl2 = DECL_VALUE_EXPR (decl);
+		  gcc_assert (TREE_CODE (decl2) == INDIRECT_REF);
+		  decl2 = TREE_OPERAND (decl2, 0);
+		  gcc_assert (DECL_P (decl2));
+		  fixup_remapped_decl (decl2, ctx, false);
+		  fixup_remapped_decl (decl, ctx, true);
+		}
+	      else
+		fixup_remapped_decl (decl, ctx, false);
+	    }
+	  break;
+
 	case OMP_CLAUSE_COPYPRIVATE:
 	case OMP_CLAUSE_COPYIN:
 	case OMP_CLAUSE_DEFAULT:
 	case OMP_CLAUSE_IF:
 	case OMP_CLAUSE_NUM_THREADS:
+	case OMP_CLAUSE_NUM_TEAMS:
+	case OMP_CLAUSE_THREAD_LIMIT:
+	case OMP_CLAUSE_DEVICE:
 	case OMP_CLAUSE_SCHEDULE:
+	case OMP_CLAUSE_DIST_SCHEDULE:
 	case OMP_CLAUSE_NOWAIT:
 	case OMP_CLAUSE_ORDERED:
 	case OMP_CLAUSE_COLLAPSE:
 	case OMP_CLAUSE_UNTIED:
 	case OMP_CLAUSE_FINAL:
 	case OMP_CLAUSE_MERGEABLE:
+	case OMP_CLAUSE_PROC_BIND:
 	case OMP_CLAUSE_SAFELEN:
+	case OMP_CLAUSE_ALIGNED:
+	case OMP_CLAUSE_DEPEND:
+	case OMP_CLAUSE__LOOPTEMP_:
+	case OMP_CLAUSE_TO:
+	case OMP_CLAUSE_FROM:
 	  break;
 
 	default:
@@ -1623,6 +1814,26 @@ create_omp_child_function (omp_context *
   DECL_EXTERNAL (decl) = 0;
   DECL_CONTEXT (decl) = NULL_TREE;
   DECL_INITIAL (decl) = make_node (BLOCK);
+  bool target_p = false;
+  if (lookup_attribute ("omp declare target",
+			DECL_ATTRIBUTES (current_function_decl)))
+    target_p = true;
+  else
+    {
+      omp_context *octx;
+      for (octx = ctx; octx; octx = octx->outer)
+	if (gimple_code (octx->stmt) == GIMPLE_OMP_TARGET
+	    && gimple_omp_target_kind (octx->stmt)
+	       == GF_OMP_TARGET_KIND_REGION)
+	  {
+	    target_p = true;
+	    break;
+	  }
+    }
+  if (target_p)
+    DECL_ATTRIBUTES (decl)
+      = tree_cons (get_identifier ("omp declare target"),
+		   NULL_TREE, DECL_ATTRIBUTES (decl));
 
   t = build_decl (DECL_SOURCE_LOCATION (decl),
 		  RESULT_DECL, NULL_TREE, void_type_node);
@@ -1664,6 +1875,35 @@ create_omp_child_function (omp_context *
   pop_cfun ();
 }
 
+/* Callback for walk_gimple_seq.  Check if combined parallel
+   contains gimple_omp_for_combined_into_p OMP_FOR.  */
+
+static tree
+find_combined_for (gimple_stmt_iterator *gsi_p,
+		   bool *handled_ops_p,
+		   struct walk_stmt_info *wi)
+{
+  gimple stmt = gsi_stmt (*gsi_p);
+
+  *handled_ops_p = true;
+  switch (gimple_code (stmt))
+    {
+    WALK_SUBSTMTS;
+
+    case GIMPLE_OMP_FOR:
+      if (gimple_omp_for_combined_into_p (stmt)
+	  && gimple_omp_for_kind (stmt) == GF_OMP_FOR_KIND_FOR)
+	{
+	  wi->info = stmt;
+	  return integer_zero_node;
+	}
+      break;
+    default:
+      break;
+    }
+  return NULL;
+}
+
 /* Scan an OpenMP parallel directive.  */
 
 static void
@@ -1684,6 +1924,40 @@ scan_omp_parallel (gimple_stmt_iterator
       return;
     }
 
+  if (gimple_omp_parallel_combined_p (stmt))
+    {
+      gimple for_stmt;
+      struct walk_stmt_info wi;
+
+      memset (&wi, 0, sizeof (wi));
+      wi.val_only = true;
+      walk_gimple_seq (gimple_omp_body (stmt),
+		       find_combined_for, NULL, &wi);
+      for_stmt = (gimple) wi.info;
+      if (for_stmt)
+	{
+	  struct omp_for_data fd;
+	  extract_omp_for_data (for_stmt, &fd, NULL);
+	  /* We need two temporaries with fd.loop.v type (istart/iend)
+	     and then (fd.collapse - 1) temporaries with the same
+	     type for count2 ... countN-1 vars if not constant.  */
+	  size_t count = 2, i;
+	  tree type = fd.iter_type;
+	  if (fd.collapse > 1
+	      && TREE_CODE (fd.loop.n2) != INTEGER_CST)
+	    count += fd.collapse - 1;
+	  for (i = 0; i < count; i++)
+	    {
+	      tree temp = create_tmp_var (type, NULL);
+	      tree c = build_omp_clause (UNKNOWN_LOCATION,
+					 OMP_CLAUSE__LOOPTEMP_);
+	      OMP_CLAUSE_DECL (c) = temp;
+	      OMP_CLAUSE_CHAIN (c) = gimple_omp_parallel_clauses (stmt);
+	      gimple_omp_parallel_set_clauses (stmt, c);
+	    }
+	}
+    }
+
   ctx = new_omp_context (stmt, outer_ctx);
   if (taskreg_nesting_level > 1)
     ctx->is_nested = true;
@@ -1858,6 +2132,63 @@ scan_omp_single (gimple stmt, omp_contex
     layout_type (ctx->record_type);
 }
 
+/* Scan an OpenMP target{, data, update} directive.  */
+
+static void
+scan_omp_target (gimple stmt, omp_context *outer_ctx)
+{
+  omp_context *ctx;
+  tree name;
+  int kind = gimple_omp_target_kind (stmt);
+
+  ctx = new_omp_context (stmt, outer_ctx);
+  ctx->field_map = splay_tree_new (splay_tree_compare_pointers, 0, 0);
+  ctx->default_kind = OMP_CLAUSE_DEFAULT_SHARED;
+  ctx->record_type = lang_hooks.types.make_type (RECORD_TYPE);
+  name = create_tmp_var_name (".omp_data_t");
+  name = build_decl (gimple_location (stmt),
+		     TYPE_DECL, name, ctx->record_type);
+  DECL_ARTIFICIAL (name) = 1;
+  DECL_NAMELESS (name) = 1;
+  TYPE_NAME (ctx->record_type) = name;
+  if (kind == GF_OMP_TARGET_KIND_REGION)
+    {
+      create_omp_child_function (ctx, false);
+      gimple_omp_target_set_child_fn (stmt, ctx->cb.dst_fn);
+    }
+
+  scan_sharing_clauses (gimple_omp_target_clauses (stmt), ctx);
+  scan_omp (gimple_omp_body_ptr (stmt), ctx);
+
+  if (TYPE_FIELDS (ctx->record_type) == NULL)
+    ctx->record_type = ctx->receiver_decl = NULL;
+  else
+    {
+      TYPE_FIELDS (ctx->record_type)
+	= nreverse (TYPE_FIELDS (ctx->record_type));
+#ifdef ENABLE_CHECKING
+      tree field;
+      unsigned int align = DECL_ALIGN (TYPE_FIELDS (ctx->record_type));
+      for (field = TYPE_FIELDS (ctx->record_type);
+	   field;
+	   field = DECL_CHAIN (field))
+	gcc_assert (DECL_ALIGN (field) == align);
+#endif
+      layout_type (ctx->record_type);
+      if (kind == GF_OMP_TARGET_KIND_REGION)
+	fixup_child_record_type (ctx);
+    }
+}
+
+/* Scan an OpenMP teams directive.  */
+
+static void
+scan_omp_teams (gimple stmt, omp_context *outer_ctx)
+{
+  omp_context *ctx = new_omp_context (stmt, outer_ctx);
+  scan_sharing_clauses (gimple_omp_teams_clauses (stmt), ctx);
+  scan_omp (gimple_omp_body_ptr (stmt), ctx);
+}
 
 /* Check OpenMP nesting restrictions.  */
 static bool
@@ -1872,16 +2203,149 @@ check_omp_nesting_restrictions (gimple s
 		    "OpenMP constructs may not be nested inside simd region");
 	  return false;
 	}
+      else if (gimple_code (ctx->stmt) == GIMPLE_OMP_TEAMS)
+	{
+	  if ((gimple_code (stmt) != GIMPLE_OMP_FOR
+	       || (gimple_omp_for_kind (stmt)
+		   != GF_OMP_FOR_KIND_DISTRIBUTE))
+	      && gimple_code (stmt) != GIMPLE_OMP_PARALLEL)
+	    {
+	      error_at (gimple_location (stmt),
+			"only distribute or parallel constructs are allowed to "
+			"be closely nested inside teams construct");
+	      return false;
+	    }
+	}
     }
   switch (gimple_code (stmt))
     {
     case GIMPLE_OMP_FOR:
       if (gimple_omp_for_kind (stmt) == GF_OMP_FOR_KIND_SIMD)
 	return true;
+      if (gimple_omp_for_kind (stmt) == GF_OMP_FOR_KIND_DISTRIBUTE)
+	{
+	  if (ctx != NULL && gimple_code (ctx->stmt) != GIMPLE_OMP_TEAMS)
+	    {
+	      error_at (gimple_location (stmt),
+			"distribute construct must be closely nested inside "
+			"teams construct");
+	      return false;
+	    }
+	  return true;
+	}
+      /* FALLTHRU */
+    case GIMPLE_CALL:
+      if (is_gimple_call (stmt)
+	  && (DECL_FUNCTION_CODE (gimple_call_fndecl (stmt))
+	      == BUILT_IN_GOMP_CANCEL
+	      || DECL_FUNCTION_CODE (gimple_call_fndecl (stmt))
+		 == BUILT_IN_GOMP_CANCELLATION_POINT))
+	{
+	  const char *bad = NULL;
+	  const char *kind = NULL;
+	  if (ctx == NULL)
+	    {
+	      error_at (gimple_location (stmt), "orphaned %qs construct",
+			DECL_FUNCTION_CODE (gimple_call_fndecl (stmt))
+			== BUILT_IN_GOMP_CANCEL
+			? "#pragma omp cancel"
+			: "#pragma omp cancellation point");
+	      return false;
+	    }
+	  switch (host_integerp (gimple_call_arg (stmt, 0), 0)
+		  ? tree_low_cst (gimple_call_arg (stmt, 0), 0)
+		  : 0)
+	    {
+	    case 1:
+	      if (gimple_code (ctx->stmt) != GIMPLE_OMP_PARALLEL)
+		bad = "#pragma omp parallel";
+	      else if (DECL_FUNCTION_CODE (gimple_call_fndecl (stmt))
+		       == BUILT_IN_GOMP_CANCEL
+		       && !integer_zerop (gimple_call_arg (stmt, 1)))
+		ctx->cancellable = true;
+	      kind = "parallel";
+	      break;
+	    case 2:
+	      if (gimple_code (ctx->stmt) != GIMPLE_OMP_FOR
+		  || gimple_omp_for_kind (ctx->stmt) != GF_OMP_FOR_KIND_FOR)
+		bad = "#pragma omp for";
+	      else if (DECL_FUNCTION_CODE (gimple_call_fndecl (stmt))
+		       == BUILT_IN_GOMP_CANCEL
+		       && !integer_zerop (gimple_call_arg (stmt, 1)))
+		{
+		  ctx->cancellable = true;
+		  if (find_omp_clause (gimple_omp_for_clauses (ctx->stmt),
+				       OMP_CLAUSE_NOWAIT))
+		    warning_at (gimple_location (stmt), 0,
+				"%<#pragma omp cancel for%> inside "
+				"%<nowait%> for construct");
+		  if (find_omp_clause (gimple_omp_for_clauses (ctx->stmt),
+				       OMP_CLAUSE_ORDERED))
+		    warning_at (gimple_location (stmt), 0,
+				"%<#pragma omp cancel for%> inside "
+				"%<ordered%> for construct");
+		}
+	      kind = "for";
+	      break;
+	    case 4:
+	      if (gimple_code (ctx->stmt) != GIMPLE_OMP_SECTIONS
+		  && gimple_code (ctx->stmt) != GIMPLE_OMP_SECTION)
+		bad = "#pragma omp sections";
+	      else if (DECL_FUNCTION_CODE (gimple_call_fndecl (stmt))
+		       == BUILT_IN_GOMP_CANCEL
+		       && !integer_zerop (gimple_call_arg (stmt, 1)))
+		{
+		  if (gimple_code (ctx->stmt) == GIMPLE_OMP_SECTIONS)
+		    {
+		      ctx->cancellable = true;
+		      if (find_omp_clause (gimple_omp_sections_clauses
+								(ctx->stmt),
+					   OMP_CLAUSE_NOWAIT))
+			warning_at (gimple_location (stmt), 0,
+				    "%<#pragma omp cancel sections%> inside "
+				    "%<nowait%> sections construct");
+		    }
+		  else
+		    {
+		      gcc_assert (ctx->outer
+				  && gimple_code (ctx->outer->stmt)
+				     == GIMPLE_OMP_SECTIONS);
+		      ctx->outer->cancellable = true;
+		      if (find_omp_clause (gimple_omp_sections_clauses
+							(ctx->outer->stmt),
+					   OMP_CLAUSE_NOWAIT))
+			warning_at (gimple_location (stmt), 0,
+				    "%<#pragma omp cancel sections%> inside "
+				    "%<nowait%> sections construct");
+		    }
+		}
+	      kind = "sections";
+	      break;
+	    case 8:
+	      if (gimple_code (ctx->stmt) != GIMPLE_OMP_TASK)
+		bad = "#pragma omp task";
+	      else
+		ctx->cancellable = true;
+	      kind = "taskgroup";
+	      break;
+	    default:
+	      error_at (gimple_location (stmt), "invalid arguments");
+	      return false;
+	    }
+	  if (bad)
+	    {
+	      error_at (gimple_location (stmt),
+			"%<%s %s%> construct not closely nested inside of %qs",
+			DECL_FUNCTION_CODE (gimple_call_fndecl (stmt))
+			== BUILT_IN_GOMP_CANCEL
+			? "#pragma omp cancel"
+			: "#pragma omp cancellation point", kind, bad);
+	      return false;
+	    }
+	}
       /* FALLTHRU */
     case GIMPLE_OMP_SECTIONS:
     case GIMPLE_OMP_SINGLE:
-    case GIMPLE_CALL:
       for (; ctx != NULL; ctx = ctx->outer)
 	switch (gimple_code (ctx->stmt))
 	  {
@@ -1891,8 +2355,12 @@ check_omp_nesting_restrictions (gimple s
 	  case GIMPLE_OMP_ORDERED:
 	  case GIMPLE_OMP_MASTER:
 	  case GIMPLE_OMP_TASK:
+	  case GIMPLE_OMP_CRITICAL:
 	    if (is_gimple_call (stmt))
 	      {
+		if (DECL_FUNCTION_CODE (gimple_call_fndecl (stmt))
+		    != BUILT_IN_GOMP_BARRIER)
+		  return true;
 		error_at (gimple_location (stmt),
 			  "barrier region may not be closely nested inside "
 			  "of work-sharing, critical, ordered, master or "
@@ -1949,7 +2417,10 @@ check_omp_nesting_restrictions (gimple s
 	      }
 	    return true;
 	  case GIMPLE_OMP_PARALLEL:
-	    return true;
+	    error_at (gimple_location (stmt),
+		      "ordered region must be closely nested inside "
+		      "a loop region with an ordered clause");
+	    return false;
 	  default:
 	    break;
 	  }
@@ -1966,6 +2437,17 @@ check_omp_nesting_restrictions (gimple s
 	    return false;
 	  }
       break;
+    case GIMPLE_OMP_TEAMS:
+      if (ctx == NULL
+	  || gimple_code (ctx->stmt) != GIMPLE_OMP_TARGET
+	  || gimple_omp_target_kind (ctx->stmt) != GF_OMP_TARGET_KIND_REGION)
+	{
+	  error_at (gimple_location (stmt),
+		    "teams construct not closely nested inside of target "
+		    "region");
+	  return false;
+	}
+      break;
     default:
       break;
     }
@@ -2038,23 +2520,33 @@ scan_omp_1_stmt (gimple_stmt_iterator *g
     input_location = gimple_location (stmt);
 
   /* Check the OpenMP nesting restrictions.  */
-  if (ctx != NULL)
-    {
-      bool remove = false;
-      if (is_gimple_omp (stmt))
-	remove = !check_omp_nesting_restrictions (stmt, ctx);
-      else if (is_gimple_call (stmt))
-	{
-	  tree fndecl = gimple_call_fndecl (stmt);
-	  if (fndecl && DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_NORMAL
-	      && DECL_FUNCTION_CODE (fndecl) == BUILT_IN_GOMP_BARRIER)
+  bool remove = false;
+  if (is_gimple_omp (stmt))
+    remove = !check_omp_nesting_restrictions (stmt, ctx);
+  else if (is_gimple_call (stmt))
+    {
+      tree fndecl = gimple_call_fndecl (stmt);
+      if (fndecl
+	  && DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_NORMAL)
+	switch (DECL_FUNCTION_CODE (fndecl))
+	  {
+	  case BUILT_IN_GOMP_BARRIER:
+	  case BUILT_IN_GOMP_CANCEL:
+	  case BUILT_IN_GOMP_CANCELLATION_POINT:
+	  case BUILT_IN_GOMP_TASKYIELD:
+	  case BUILT_IN_GOMP_TASKWAIT:
+	  case BUILT_IN_GOMP_TASKGROUP_START:
+	  case BUILT_IN_GOMP_TASKGROUP_END:
 	    remove = !check_omp_nesting_restrictions (stmt, ctx);
-	}
-      if (remove)
-	{
-	  stmt = gimple_build_nop ();
-	  gsi_replace (gsi, stmt, false);
-	}
+	    break;
+	  default:
+	    break;
+	  }
+    }
+  if (remove)
+    {
+      stmt = gimple_build_nop ();
+      gsi_replace (gsi, stmt, false);
     }
 
   *handled_ops_p = true;
@@ -2087,12 +2579,21 @@ scan_omp_1_stmt (gimple_stmt_iterator *g
 
     case GIMPLE_OMP_SECTION:
     case GIMPLE_OMP_MASTER:
+    case GIMPLE_OMP_TASKGROUP:
     case GIMPLE_OMP_ORDERED:
     case GIMPLE_OMP_CRITICAL:
       ctx = new_omp_context (stmt, ctx);
       scan_omp (gimple_omp_body_ptr (stmt), ctx);
       break;
 
+    case GIMPLE_OMP_TARGET:
+      scan_omp_target (stmt, ctx);
+      break;
+
+    case GIMPLE_OMP_TEAMS:
+      scan_omp_teams (stmt, ctx);
+      break;
+
     case GIMPLE_BIND:
       {
 	tree var;
@@ -2135,10 +2636,15 @@ scan_omp (gimple_seq *body_p, omp_contex
 
 /* Build a call to GOMP_barrier.  */
 
-static tree
-build_omp_barrier (void)
+static gimple
+build_omp_barrier (tree lhs)
 {
-  return build_call_expr (builtin_decl_explicit (BUILT_IN_GOMP_BARRIER), 0);
+  tree fndecl = builtin_decl_explicit (lhs ? BUILT_IN_GOMP_BARRIER_CANCEL
+					   : BUILT_IN_GOMP_BARRIER);
+  gimple g = gimple_build_call (fndecl, 0);
+  if (lhs)
+    gimple_call_set_lhs (g, lhs);
+  return g;
 }
 
 /* If a context was created for STMT when it was scanned, return it.  */
@@ -2299,6 +2805,49 @@ omp_reduction_init (tree clause, tree ty
     }
 }
 
+/* Return alignment to be assumed for var in CLAUSE, which should be
+   OMP_CLAUSE_ALIGNED.  */
+
+static tree
+omp_clause_aligned_alignment (tree clause)
+{
+  if (OMP_CLAUSE_ALIGNED_ALIGNMENT (clause))
+    return OMP_CLAUSE_ALIGNED_ALIGNMENT (clause);
+
+  /* Otherwise return implementation defined alignment.  */
+  unsigned int al = 1;
+  enum machine_mode mode, vmode;
+  int vs = targetm.vectorize.autovectorize_vector_sizes ();
+  if (vs)
+    vs = 1 << floor_log2 (vs);
+  static enum mode_class classes[]
+    = { MODE_INT, MODE_VECTOR_INT, MODE_FLOAT, MODE_VECTOR_FLOAT };
+  for (int i = 0; i < 4; i += 2)
+    for (mode = GET_CLASS_NARROWEST_MODE (classes[i]);
+	 mode != VOIDmode;
+	 mode = GET_MODE_WIDER_MODE (mode))
+      {
+	vmode = targetm.vectorize.preferred_simd_mode (mode);
+	if (GET_MODE_CLASS (vmode) != classes[i + 1])
+	  continue;
+	while (vs
+	       && GET_MODE_SIZE (vmode) < vs
+	       && GET_MODE_2XWIDER_MODE (vmode) != VOIDmode)
+	  vmode = GET_MODE_2XWIDER_MODE (vmode);
+	
+	tree type = lang_hooks.types.type_for_mode (mode, 1);
+	if (type == NULL_TREE || TYPE_MODE (type) != mode)
+	  continue;
+	type = build_vector_type (type, GET_MODE_SIZE (vmode)
+					/ GET_MODE_SIZE (mode));
+	if (TYPE_MODE (type) != vmode)
+	  continue;
+	if (TYPE_ALIGN_UNIT (type) > al)
+	  al = TYPE_ALIGN_UNIT (type);
+      }
+  return build_int_cst (integer_type_node, al);
+}
+
 /* Return maximum possible vectorization factor for the target.  */
 
 static int
@@ -2362,8 +2911,11 @@ lower_rec_simd_input_clauses (tree new_v
 		 NULL_TREE, NULL_TREE);
   lvar = build4 (ARRAY_REF, TREE_TYPE (new_var), avar, lane,
 		 NULL_TREE, NULL_TREE);
-  SET_DECL_VALUE_EXPR (new_var, lvar);
-  DECL_HAS_VALUE_EXPR_P (new_var) = 1;
+  if (DECL_P (new_var))
+    {
+      SET_DECL_VALUE_EXPR (new_var, lvar);
+      DECL_HAS_VALUE_EXPR_P (new_var) = 1;
+    }
   return true;
 }
 
@@ -2374,11 +2926,12 @@ lower_rec_simd_input_clauses (tree new_v
 
 static void
 lower_rec_input_clauses (tree clauses, gimple_seq *ilist, gimple_seq *dlist,
-			 omp_context *ctx)
+			 omp_context *ctx, struct omp_for_data *fd)
 {
   tree c, dtor, copyin_seq, x, ptr;
   bool copyin_by_ref = false;
   bool lastprivate_firstprivate = false;
+  bool reduction_omp_orig_ref = false;
   int pass;
   bool is_simd = (gimple_code (ctx->stmt) == GIMPLE_OMP_FOR
 		  && gimple_omp_for_kind (ctx->stmt) == GF_OMP_FOR_KIND_SIMD);
@@ -2398,9 +2951,6 @@ lower_rec_input_clauses (tree clauses, g
       switch (OMP_CLAUSE_CODE (c))
 	{
 	case OMP_CLAUSE_REDUCTION:
-	  if (OMP_CLAUSE_REDUCTION_PLACEHOLDER (c))
-	    max_vf = 1;
-	  /* FALLTHRU */
 	case OMP_CLAUSE_PRIVATE:
 	case OMP_CLAUSE_FIRSTPRIVATE:
 	case OMP_CLAUSE_LASTPRIVATE:
@@ -2432,6 +2982,9 @@ lower_rec_input_clauses (tree clauses, g
 		continue;
 	      break;
 	    case OMP_CLAUSE_SHARED:
+	      /* Ignore shared directives in teams construct.  */
+	      if (gimple_code (ctx->stmt) == GIMPLE_OMP_TEAMS)
+		continue;
 	      if (maybe_lookup_decl (OMP_CLAUSE_DECL (c), ctx) == NULL)
 		{
 		  gcc_assert (is_global_var (OMP_CLAUSE_DECL (c)));
@@ -2439,9 +2992,16 @@ lower_rec_input_clauses (tree clauses, g
 		}
 	    case OMP_CLAUSE_FIRSTPRIVATE:
 	    case OMP_CLAUSE_COPYIN:
+	    case OMP_CLAUSE_LINEAR:
+	      break;
 	    case OMP_CLAUSE_REDUCTION:
+	      if (OMP_CLAUSE_REDUCTION_OMP_ORIG_REF (c))
+		reduction_omp_orig_ref = true;
 	      break;
-	    case OMP_CLAUSE_LINEAR:
+	    case OMP_CLAUSE__LOOPTEMP_:
+	      /* Handle _looptemp_ clauses only on parallel.  */
+	      if (fd)
+		continue;
 	      break;
 	    case OMP_CLAUSE_LASTPRIVATE:
 	      if (OMP_CLAUSE_LASTPRIVATE_FIRSTPRIVATE (c))
@@ -2451,6 +3011,42 @@ lower_rec_input_clauses (tree clauses, g
 		    continue;
 		}
 	      break;
+	    case OMP_CLAUSE_ALIGNED:
+	      if (pass == 0)
+		continue;
+	      var = OMP_CLAUSE_DECL (c);
+	      if (TREE_CODE (TREE_TYPE (var)) == POINTER_TYPE
+		  && !is_global_var (var))
+		{
+		  new_var = maybe_lookup_decl (var, ctx);
+		  if (new_var == NULL_TREE)
+		    new_var = maybe_lookup_decl_in_outer_ctx (var, ctx);
+		  x = builtin_decl_explicit (BUILT_IN_ASSUME_ALIGNED);
+		  x = build_call_expr_loc (clause_loc, x, 2, new_var,
+					   omp_clause_aligned_alignment (c));
+		  x = fold_convert_loc (clause_loc, TREE_TYPE (new_var), x);
+		  x = build2 (MODIFY_EXPR, TREE_TYPE (new_var), new_var, x);
+		  gimplify_and_add (x, ilist);
+		}
+	      else if (TREE_CODE (TREE_TYPE (var)) == ARRAY_TYPE
+		       && is_global_var (var))
+		{
+		  tree ptype = build_pointer_type (TREE_TYPE (var)), t, t2;
+		  new_var = lookup_decl (var, ctx);
+		  t = maybe_lookup_decl_in_outer_ctx (var, ctx);
+		  t = build_fold_addr_expr_loc (clause_loc, t);
+		  t2 = builtin_decl_explicit (BUILT_IN_ASSUME_ALIGNED);
+		  t = build_call_expr_loc (clause_loc, t2, 2, t,
+					   omp_clause_aligned_alignment (c));
+		  t = fold_convert_loc (clause_loc, ptype, t);
+		  x = create_tmp_var (ptype, NULL);
+		  t = build2 (MODIFY_EXPR, ptype, x, t);
+		  gimplify_and_add (t, ilist);
+		  t = build_simple_mem_ref_loc (clause_loc, x);
+		  SET_DECL_VALUE_EXPR (new_var, t);
+		  DECL_HAS_VALUE_EXPR_P (new_var) = 1;
+		}
+	      continue;
 	    default:
 	      continue;
 	    }
@@ -2502,10 +3098,7 @@ lower_rec_input_clauses (tree clauses, g
 		 allocate new backing storage for the new pointer
 		 variable.  This allows us to avoid changing all the
 		 code that expects a pointer to something that expects
-		 a direct variable.  Note that this doesn't apply to
-		 C++, since reference types are disallowed in data
-		 sharing clauses there, except for NRV optimized
-		 return values.  */
+		 a direct variable.  */
 	      if (pass == 0)
 		continue;
 
@@ -2550,6 +3143,9 @@ lower_rec_input_clauses (tree clauses, g
 	  switch (OMP_CLAUSE_CODE (c))
 	    {
 	    case OMP_CLAUSE_SHARED:
+	      /* Ignore shared directives in teams construct.  */
+	      if (gimple_code (ctx->stmt) == GIMPLE_OMP_TEAMS)
+		continue;
 	      /* Shared global vars are just accessed directly.  */
 	      if (is_global_var (new_var))
 		break;
@@ -2588,19 +3184,20 @@ lower_rec_input_clauses (tree clauses, g
 	      else
 		x = NULL;
 	    do_private:
-	      x = lang_hooks.decls.omp_clause_default_ctor (c, new_var, x);
+	      tree nx;
+	      nx = lang_hooks.decls.omp_clause_default_ctor (c, new_var, x);
 	      if (is_simd)
 		{
 		  tree y = lang_hooks.decls.omp_clause_dtor (c, new_var);
-		  if ((TREE_ADDRESSABLE (new_var) || x || y
+		  if ((TREE_ADDRESSABLE (new_var) || nx || y
 		       || OMP_CLAUSE_CODE (c) == OMP_CLAUSE_LASTPRIVATE)
 		      && lower_rec_simd_input_clauses (new_var, ctx, max_vf,
 						       idx, lane, ivar, lvar))
 		    {
-		      if (x)
+		      if (nx)
 			x = lang_hooks.decls.omp_clause_default_ctor
 						(c, unshare_expr (ivar), x);
-		      if (x)
+		      if (nx && x)
 			gimplify_and_add (x, &llist[0]);
 		      if (y)
 			{
@@ -2617,8 +3214,8 @@ lower_rec_input_clauses (tree clauses, g
 		      break;
 		    }
 		}
-	      if (x)
-		gimplify_and_add (x, ilist);
+	      if (nx)
+		gimplify_and_add (nx, ilist);
 	      /* FALLTHRU */
 
 	    do_dtor:
@@ -2661,6 +3258,44 @@ lower_rec_input_clauses (tree clauses, g
 	      x = build_outer_var_ref (var, ctx);
 	      if (is_simd)
 		{
+		  if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_LINEAR
+		      && gimple_omp_for_combined_into_p (ctx->stmt))
+		    {
+		      tree stept = POINTER_TYPE_P (TREE_TYPE (x))
+				   ? sizetype : TREE_TYPE (x);
+		      tree t = fold_convert (stept,
+					     OMP_CLAUSE_LINEAR_STEP (c));
+		      tree c = find_omp_clause (clauses,
+						OMP_CLAUSE__LOOPTEMP_);
+		      gcc_assert (c);
+		      tree l = OMP_CLAUSE_DECL (c);
+		      if (fd->collapse == 1)
+			{
+			  tree n1 = fd->loop.n1;
+			  tree step = fd->loop.step;
+			  tree itype = TREE_TYPE (l);
+			  if (POINTER_TYPE_P (itype))
+			    itype = signed_type_for (itype);
+			  l = fold_build2 (MINUS_EXPR, itype, l, n1);
+			  if (TYPE_UNSIGNED (itype)
+			      && fd->loop.cond_code == GT_EXPR)
+			    l = fold_build2 (TRUNC_DIV_EXPR, itype,
+					     fold_build1 (NEGATE_EXPR,
+							  itype, l),
+					     fold_build1 (NEGATE_EXPR,
+							  itype, step));
+			  else
+			    l = fold_build2 (TRUNC_DIV_EXPR, itype, l, step);
+			}
+		      t = fold_build2 (MULT_EXPR, stept,
+				       fold_convert (stept, l), t);
+		      if (POINTER_TYPE_P (TREE_TYPE (x)))
+			x = fold_build2 (POINTER_PLUS_EXPR,
+					 TREE_TYPE (x), x, t);
+		      else
+			x = fold_build2 (PLUS_EXPR, TREE_TYPE (x), x, t);
+		    }
+
 		  if ((OMP_CLAUSE_CODE (c) != OMP_CLAUSE_LINEAR
 		       || TREE_ADDRESSABLE (new_var))
 		      && lower_rec_simd_input_clauses (new_var, ctx, max_vf,
@@ -2708,6 +3343,13 @@ lower_rec_input_clauses (tree clauses, g
 	      gimplify_and_add (x, ilist);
 	      goto do_dtor;
 
+	    case OMP_CLAUSE__LOOPTEMP_:
+	      gcc_assert (is_parallel_ctx (ctx));
+	      x = build_outer_var_ref (var, ctx);
+	      x = build2 (MODIFY_EXPR, TREE_TYPE (new_var), new_var, x);
+	      gimplify_and_add (x, ilist);
+	      break;
+
 	    case OMP_CLAUSE_COPYIN:
 	      by_ref = use_pointer_for_field (var, NULL);
 	      x = build_receiver_ref (var, by_ref, ctx);
@@ -2720,19 +3362,89 @@ lower_rec_input_clauses (tree clauses, g
 	      if (OMP_CLAUSE_REDUCTION_PLACEHOLDER (c))
 		{
 		  tree placeholder = OMP_CLAUSE_REDUCTION_PLACEHOLDER (c);
+		  gimple tseq;
 		  x = build_outer_var_ref (var, ctx);
 
-		  /* FIXME: Not handled yet.  */
-		  gcc_assert (!is_simd);
-		  if (is_reference (var))
+		  if (is_reference (var)
+		      && !useless_type_conversion_p (TREE_TYPE (placeholder),
+						     TREE_TYPE (x)))
 		    x = build_fold_addr_expr_loc (clause_loc, x);
 		  SET_DECL_VALUE_EXPR (placeholder, x);
 		  DECL_HAS_VALUE_EXPR_P (placeholder) = 1;
-		  lower_omp (&OMP_CLAUSE_REDUCTION_GIMPLE_INIT (c), ctx);
-		  gimple_seq_add_seq (ilist,
-				      OMP_CLAUSE_REDUCTION_GIMPLE_INIT (c));
+		  tree new_vard = new_var;
+		  if (is_reference (var))
+		    {
+		      gcc_assert (TREE_CODE (new_var) == MEM_REF);
+		      new_vard = TREE_OPERAND (new_var, 0);
+		      gcc_assert (DECL_P (new_vard));
+		    }
+		  if (is_simd
+		      && lower_rec_simd_input_clauses (new_var, ctx, max_vf,
+						       idx, lane, ivar, lvar))
+		    {
+		      if (new_vard == new_var)
+			{
+			  gcc_assert (DECL_VALUE_EXPR (new_var) == lvar);
+			  SET_DECL_VALUE_EXPR (new_var, ivar);
+			}
+		      else
+			{
+			  SET_DECL_VALUE_EXPR (new_vard,
+					       build_fold_addr_expr (ivar));
+			  DECL_HAS_VALUE_EXPR_P (new_vard) = 1;
+			}
+		      x = lang_hooks.decls.omp_clause_default_ctor
+				(c, unshare_expr (ivar),
+				 build_outer_var_ref (var, ctx));
+		      if (x)
+			gimplify_and_add (x, &llist[0]);
+		      if (OMP_CLAUSE_REDUCTION_GIMPLE_INIT (c))
+			{
+			  tseq = OMP_CLAUSE_REDUCTION_GIMPLE_INIT (c);
+			  lower_omp (&tseq, ctx);
+			  gimple_seq_add_seq (&llist[0], tseq);
+			}
+		      OMP_CLAUSE_REDUCTION_GIMPLE_INIT (c) = NULL;
+		      tseq = OMP_CLAUSE_REDUCTION_GIMPLE_MERGE (c);
+		      lower_omp (&tseq, ctx);
+		      gimple_seq_add_seq (&llist[1], tseq);
+		      OMP_CLAUSE_REDUCTION_GIMPLE_MERGE (c) = NULL;
+		      DECL_HAS_VALUE_EXPR_P (placeholder) = 0;
+		      if (new_vard == new_var)
+			SET_DECL_VALUE_EXPR (new_var, lvar);
+		      else
+			SET_DECL_VALUE_EXPR (new_vard,
+					     build_fold_addr_expr (lvar));
+		      x = lang_hooks.decls.omp_clause_dtor (c, ivar);
+		      if (x)
+			{
+			  tseq = NULL;
+			  dtor = x;
+			  gimplify_stmt (&dtor, &tseq);
+			  gimple_seq_add_seq (&llist[1], tseq);
+			}
+		      break;
+		    }
+		  x = lang_hooks.decls.omp_clause_default_ctor
+				(c, new_var, unshare_expr (x));
+		  if (x)
+		    gimplify_and_add (x, ilist);
+		  if (OMP_CLAUSE_REDUCTION_GIMPLE_INIT (c))
+		    {
+		      tseq = OMP_CLAUSE_REDUCTION_GIMPLE_INIT (c);
+		      lower_omp (&tseq, ctx);
+		      gimple_seq_add_seq (ilist, tseq);
+		    }
 		  OMP_CLAUSE_REDUCTION_GIMPLE_INIT (c) = NULL;
+		  if (is_simd)
+		    {
+		      tseq = OMP_CLAUSE_REDUCTION_GIMPLE_MERGE (c);
+		      lower_omp (&tseq, ctx);
+		      gimple_seq_add_seq (dlist, tseq);
+		      OMP_CLAUSE_REDUCTION_GIMPLE_MERGE (c) = NULL;
+		    }
 		  DECL_HAS_VALUE_EXPR_P (placeholder) = 0;
+		  goto do_dtor;
 		}
 	      else
 		{
@@ -2835,14 +3547,15 @@ lower_rec_input_clauses (tree clauses, g
      master thread doesn't modify it before it is copied over in all
      threads.  Similarly for variables in both firstprivate and
      lastprivate clauses we need to ensure the lastprivate copying
-     happens after firstprivate copying in all threads.  */
-  if (copyin_by_ref || lastprivate_firstprivate)
+     happens after firstprivate copying in all threads.  And similarly
+     for UDRs if initializer expression refers to omp_orig.  */
+  if (copyin_by_ref || lastprivate_firstprivate || reduction_omp_orig_ref)
     {
       /* Don't add any barrier for #pragma omp simd or
 	 #pragma omp distribute.  */
       if (gimple_code (ctx->stmt) != GIMPLE_OMP_FOR
 	  || gimple_omp_for_kind (ctx->stmt) == GF_OMP_FOR_KIND_FOR)
-	gimplify_and_add (build_omp_barrier (), ilist);
+	gimple_seq_add_stmt (ilist, build_omp_barrier (NULL_TREE));
     }
 
   /* If max_vf is non-zero, then we can use only a vectorization factor
@@ -2871,7 +3584,7 @@ lower_rec_input_clauses (tree clauses, g
 
 static void
 lower_lastprivate_clauses (tree clauses, tree predicate, gimple_seq *stmt_list,
-			    omp_context *ctx)
+			   omp_context *ctx)
 {
   tree x, c, label = NULL, orig_clauses = clauses;
   bool par_clauses = false;
@@ -3025,7 +3738,7 @@ lower_reduction_clauses (tree clauses, g
       {
 	if (OMP_CLAUSE_REDUCTION_PLACEHOLDER (c))
 	  {
-	    /* Never use OMP_ATOMIC for array reductions.  */
+	    /* Never use OMP_ATOMIC for array reductions or UDRs.  */
 	    count = -1;
 	    break;
 	  }
@@ -3072,7 +3785,9 @@ lower_reduction_clauses (tree clauses, g
 	{
 	  tree placeholder = OMP_CLAUSE_REDUCTION_PLACEHOLDER (c);
 
-	  if (is_reference (var))
+	  if (is_reference (var)
+	      && !useless_type_conversion_p (TREE_TYPE (placeholder),
+					     TREE_TYPE (ref)))
 	    ref = build_fold_addr_expr_loc (clause_loc, ref);
 	  SET_DECL_VALUE_EXPR (placeholder, ref);
 	  DECL_HAS_VALUE_EXPR_P (placeholder) = 1;
@@ -3175,6 +3890,7 @@ lower_send_clauses (tree clauses, gimple
 	case OMP_CLAUSE_COPYIN:
 	case OMP_CLAUSE_LASTPRIVATE:
 	case OMP_CLAUSE_REDUCTION:
+	case OMP_CLAUSE__LOOPTEMP_:
 	  break;
 	default:
 	  continue;
@@ -3195,6 +3911,7 @@ lower_send_clauses (tree clauses, gimple
 	case OMP_CLAUSE_PRIVATE:
 	case OMP_CLAUSE_FIRSTPRIVATE:
 	case OMP_CLAUSE_COPYIN:
+	case OMP_CLAUSE__LOOPTEMP_:
 	  do_in = true;
 	  break;
 
@@ -3317,7 +4034,7 @@ static void
 expand_parallel_call (struct omp_region *region, basic_block bb,
 		      gimple entry_stmt, vec<tree, va_gc> *ws_args)
 {
-  tree t, t1, t2, val, cond, c, clauses;
+  tree t, t1, t2, val, cond, c, clauses, flags;
   gimple_stmt_iterator gsi;
   gimple stmt;
   enum built_in_function start_ix;
@@ -3327,23 +4044,23 @@ expand_parallel_call (struct omp_region
 
   clauses = gimple_omp_parallel_clauses (entry_stmt);
 
-  /* Determine what flavor of GOMP_parallel_start we will be
+  /* Determine what flavor of GOMP_parallel we will be
      emitting.  */
-  start_ix = BUILT_IN_GOMP_PARALLEL_START;
+  start_ix = BUILT_IN_GOMP_PARALLEL;
   if (is_combined_parallel (region))
     {
       switch (region->inner->type)
 	{
 	case GIMPLE_OMP_FOR:
 	  gcc_assert (region->inner->sched_kind != OMP_CLAUSE_SCHEDULE_AUTO);
-	  start_ix2 = ((int)BUILT_IN_GOMP_PARALLEL_LOOP_STATIC_START
+	  start_ix2 = ((int)BUILT_IN_GOMP_PARALLEL_LOOP_STATIC
 		       + (region->inner->sched_kind
 			  == OMP_CLAUSE_SCHEDULE_RUNTIME
 			  ? 3 : region->inner->sched_kind));
 	  start_ix = (enum built_in_function)start_ix2;
 	  break;
 	case GIMPLE_OMP_SECTIONS:
-	  start_ix = BUILT_IN_GOMP_PARALLEL_SECTIONS_START;
+	  start_ix = BUILT_IN_GOMP_PARALLEL_SECTIONS;
 	  break;
 	default:
 	  gcc_unreachable ();
@@ -3354,6 +4071,7 @@ expand_parallel_call (struct omp_region
      and there is no conditional.  */
   cond = NULL_TREE;
   val = build_int_cst (unsigned_type_node, 0);
+  flags = build_int_cst (unsigned_type_node, 0);
 
   c = find_omp_clause (clauses, OMP_CLAUSE_IF);
   if (c)
@@ -3368,6 +4086,10 @@ expand_parallel_call (struct omp_region
   else
     clause_loc = gimple_location (entry_stmt);
 
+  c = find_omp_clause (clauses, OMP_CLAUSE_PROC_BIND);
+  if (c)
+    flags = build_int_cst (unsigned_type_node, OMP_CLAUSE_PROC_BIND_KIND (c));
+
   /* Ensure 'val' is of the correct type.  */
   val = fold_convert_loc (clause_loc, unsigned_type_node, val);
 
@@ -3459,34 +4181,19 @@ expand_parallel_call (struct omp_region
     t1 = build_fold_addr_expr (t);
   t2 = build_fold_addr_expr (gimple_omp_parallel_child_fn (entry_stmt));
 
-  vec_alloc (args, 3 + vec_safe_length (ws_args));
+  vec_alloc (args, 4 + vec_safe_length (ws_args));
   args->quick_push (t2);
   args->quick_push (t1);
   args->quick_push (val);
   if (ws_args)
     args->splice (*ws_args);
+  args->quick_push (flags);
 
   t = build_call_expr_loc_vec (UNKNOWN_LOCATION,
 			       builtin_decl_explicit (start_ix), args);
 
   force_gimple_operand_gsi (&gsi, t, true, NULL_TREE,
 			    false, GSI_CONTINUE_LINKING);
-
-  t = gimple_omp_parallel_data_arg (entry_stmt);
-  if (t == NULL)
-    t = null_pointer_node;
-  else
-    t = build_fold_addr_expr (t);
-  t = build_call_expr_loc (gimple_location (entry_stmt),
-			   gimple_omp_parallel_child_fn (entry_stmt), 1, t);
-  force_gimple_operand_gsi (&gsi, t, true, NULL_TREE,
-			    false, GSI_CONTINUE_LINKING);
-
-  t = build_call_expr_loc (gimple_location (entry_stmt),
-			   builtin_decl_explicit (BUILT_IN_GOMP_PARALLEL_END),
-			   0);
-  force_gimple_operand_gsi (&gsi, t, true, NULL_TREE,
-			    false, GSI_CONTINUE_LINKING);
 }
 
 
@@ -3496,7 +4203,7 @@ expand_parallel_call (struct omp_region
 static void
 expand_task_call (basic_block bb, gimple entry_stmt)
 {
-  tree t, t1, t2, t3, flags, cond, c, c2, clauses;
+  tree t, t1, t2, t3, flags, cond, c, c2, clauses, depend;
   gimple_stmt_iterator gsi;
   location_t loc = gimple_location (entry_stmt);
 
@@ -3510,8 +4217,9 @@ expand_task_call (basic_block bb, gimple
 
   c = find_omp_clause (clauses, OMP_CLAUSE_UNTIED);
   c2 = find_omp_clause (clauses, OMP_CLAUSE_MERGEABLE);
+  depend = find_omp_clause (clauses, OMP_CLAUSE_DEPEND);
   flags = build_int_cst (unsigned_type_node,
-			 (c ? 1 : 0) + (c2 ? 4 : 0));
+			 (c ? 1 : 0) + (c2 ? 4 : 0) + (depend ? 8 : 0));
 
   c = find_omp_clause (clauses, OMP_CLAUSE_FINAL);
   if (c)
@@ -3522,6 +4230,10 @@ expand_task_call (basic_block bb, gimple
 			   build_int_cst (unsigned_type_node, 0));
       flags = fold_build2_loc (loc, PLUS_EXPR, unsigned_type_node, flags, c);
     }
+  if (depend)
+    depend = OMP_CLAUSE_DECL (depend);
+  else
+    depend = build_int_cst (ptr_type_node, 0);
 
   gsi = gsi_last_bb (bb);
   t = gimple_omp_task_data_arg (entry_stmt);
@@ -3537,9 +4249,10 @@ expand_task_call (basic_block bb, gimple
     t3 = build_fold_addr_expr_loc (loc, t);
 
   t = build_call_expr (builtin_decl_explicit (BUILT_IN_GOMP_TASK),
-		       7, t1, t2, t3,
+		       8, t1, t2, t3,
 		       gimple_omp_task_arg_size (entry_stmt),
-		       gimple_omp_task_arg_align (entry_stmt), cond, flags);
+		       gimple_omp_task_arg_align (entry_stmt), cond, flags,
+		       depend);
 
   force_gimple_operand_gsi (&gsi, t, true, NULL_TREE,
 			    false, GSI_CONTINUE_LINKING);
@@ -4064,7 +4777,9 @@ expand_omp_taskreg (struct omp_region *r
 	count = count1 * count2 * count3;
    Furthermore, if ZERO_ITER_BB is NULL, create a BB which does:
 	count = 0;
-   and set ZERO_ITER_BB to that bb.  */
+   and set ZERO_ITER_BB to that bb.  If this isn't the outermost
+   of the combined loop constructs, just initialize COUNTS array
+   from the _looptemp_ clauses.  */
 
 /* NOTE: It *could* be better to moosh all of the BBs together,
    creating one larger BB with all the computation and the unexpected
@@ -4106,6 +4821,28 @@ expand_omp_for_init_counts (struct omp_f
   /* Collapsed loops need work for expansion into SSA form.  */
   gcc_assert (!gimple_in_ssa_p (cfun));
 
+  if (gimple_omp_for_combined_into_p (fd->for_stmt)
+      && TREE_CODE (fd->loop.n2) != INTEGER_CST)
+    {
+      /* First two _looptemp_ clauses are for istart/iend, counts[0]
+	 isn't supposed to be handled, as the inner loop doesn't
+	 use it.  */
+      tree innerc = find_omp_clause (gimple_omp_for_clauses (fd->for_stmt),
+				     OMP_CLAUSE__LOOPTEMP_);
+      gcc_assert (innerc);
+      for (i = 0; i < fd->collapse; i++)
+	{
+	  innerc = find_omp_clause (OMP_CLAUSE_CHAIN (innerc),
+				    OMP_CLAUSE__LOOPTEMP_);
+	  gcc_assert (innerc);
+	  if (i)
+	    counts[i] = OMP_CLAUSE_DECL (innerc);
+	  else
+	    counts[0] = NULL_TREE;
+	}
+      return;
+    }
+
   for (i = 0; i < fd->collapse; i++)
     {
       tree itype = TREE_TYPE (fd->loops[i].v);
@@ -4209,13 +4946,49 @@ expand_omp_for_init_counts (struct omp_f
 	V2 = N21 + (T % count2) * STEP2;
 	T = T / count2;
 	V1 = N11 + T * STEP1;
-   if this loop doesn't have an inner loop construct combined with it.  */
+   if this loop doesn't have an inner loop construct combined with it.
+   If it does have an inner loop construct combined with it and the
+   iteration count isn't known constant, store values from counts array
+   into its _looptemp_ temporaries instead.  */
 
 static void
 expand_omp_for_init_vars (struct omp_for_data *fd, gimple_stmt_iterator *gsi,
-			  tree *counts, tree startvar)
+			  tree *counts, gimple inner_stmt, tree startvar)
 {
   int i;
+  if (gimple_omp_for_combined_p (fd->for_stmt))
+    {
+      /* If fd->loop.n2 is constant, then no propagation of the counts
+	 is needed, they are constant.  */
+      if (TREE_CODE (fd->loop.n2) == INTEGER_CST)
+	return;
+
+      tree clauses = gimple_code (inner_stmt) == GIMPLE_OMP_PARALLEL
+		     ? gimple_omp_parallel_clauses (inner_stmt)
+		     : gimple_omp_for_clauses (inner_stmt);
+      /* First two _looptemp_ clauses are for istart/iend, counts[0]
+	 isn't supposed to be handled, as the inner loop doesn't
+	 use it.  */
+      tree innerc = find_omp_clause (clauses, OMP_CLAUSE__LOOPTEMP_);
+      gcc_assert (innerc);
+      for (i = 0; i < fd->collapse; i++)
+	{
+	  innerc = find_omp_clause (OMP_CLAUSE_CHAIN (innerc),
+				    OMP_CLAUSE__LOOPTEMP_);
+	  gcc_assert (innerc);
+	  if (i)
+	    {
+	      tree tem = OMP_CLAUSE_DECL (innerc);
+	      tree t = fold_convert (TREE_TYPE (tem), counts[i]);
+	      t = force_gimple_operand_gsi (gsi, t, false, NULL_TREE,
+					    false, GSI_CONTINUE_LINKING);
+	      gimple stmt = gimple_build_assign (tem, t);
+	      gsi_insert_after (gsi, stmt, GSI_CONTINUE_LINKING);
+	    }
+	}
+      return;
+    }
+
   tree type = TREE_TYPE (fd->loop.v);
   tree tem = create_tmp_reg (type, ".tem");
   gimple stmt = gimple_build_assign (tem, startvar);
@@ -4368,6 +5141,10 @@ extract_omp_for_update_vars (struct omp_
 
     If this is a combined omp parallel loop, instead of the call to
     GOMP_loop_foo_start, we call GOMP_loop_foo_next.
+    If this is gimple_omp_for_combined_p loop, then instead of assigning
+    V and iend in L0 we assign the first two _looptemp_ clause decls of the
+    inner GIMPLE_OMP_FOR and V += STEP; and
+    if (V cond iend) goto L1; else goto L2; are removed.
 
     For collapsed loops, given parameters:
       collapse(3)
@@ -4437,7 +5214,8 @@ static void
 expand_omp_for_generic (struct omp_region *region,
 			struct omp_for_data *fd,
 			enum built_in_function start_fn,
-			enum built_in_function next_fn)
+			enum built_in_function next_fn,
+			gimple inner_stmt)
 {
   tree type, istart0, iend0, iend;
   tree t, vmain, vback, bias = NULL_TREE;
@@ -4552,6 +5330,17 @@ expand_omp_for_generic (struct omp_regio
       t2 = fold_convert (fd->iter_type, fd->loop.step);
       t1 = fd->loop.n2;
       t0 = fd->loop.n1;
+      if (gimple_omp_for_combined_into_p (fd->for_stmt))
+	{
+	  tree innerc = find_omp_clause (gimple_omp_for_clauses (fd->for_stmt),
+					 OMP_CLAUSE__LOOPTEMP_);
+	  gcc_assert (innerc);
+	  t0 = OMP_CLAUSE_DECL (innerc);
+	  innerc = find_omp_clause (OMP_CLAUSE_CHAIN (innerc),
+				    OMP_CLAUSE__LOOPTEMP_);
+	  gcc_assert (innerc);
+	  t1 = OMP_CLAUSE_DECL (innerc);
+	}
       if (POINTER_TYPE_P (TREE_TYPE (t0))
 	  && TYPE_PRECISION (TREE_TYPE (t0))
 	     != TYPE_PRECISION (fd->iter_type))
@@ -4622,6 +5411,21 @@ expand_omp_for_generic (struct omp_regio
   tree startvar = fd->loop.v;
   tree endvar = NULL_TREE;
 
+  if (gimple_omp_for_combined_p (fd->for_stmt))
+    {
+      gcc_assert (gimple_code (inner_stmt) == GIMPLE_OMP_FOR
+		  && gimple_omp_for_kind (inner_stmt)
+		     == GF_OMP_FOR_KIND_SIMD);
+      tree innerc = find_omp_clause (gimple_omp_for_clauses (inner_stmt),
+				     OMP_CLAUSE__LOOPTEMP_);
+      gcc_assert (innerc);
+      startvar = OMP_CLAUSE_DECL (innerc);
+      innerc = find_omp_clause (OMP_CLAUSE_CHAIN (innerc),
+				OMP_CLAUSE__LOOPTEMP_);
+      gcc_assert (innerc);
+      endvar = OMP_CLAUSE_DECL (innerc);
+    }
+
   gsi = gsi_start_bb (l0_bb);
   t = istart0;
   if (bias)
@@ -4650,7 +5454,7 @@ expand_omp_for_generic (struct omp_regio
       gsi_insert_after (&gsi, stmt, GSI_CONTINUE_LINKING);
     }
   if (fd->collapse > 1)
-    expand_omp_for_init_vars (fd, &gsi, counts, startvar);
+    expand_omp_for_init_vars (fd, &gsi, counts, inner_stmt, startvar);
 
   if (!broken_loop)
     {
@@ -4662,8 +5466,7 @@ expand_omp_for_generic (struct omp_regio
       vmain = gimple_omp_continue_control_use (stmt);
       vback = gimple_omp_continue_control_def (stmt);
 
-      /* OMP4 placeholder: if (!gimple_omp_for_combined_p (fd->for_stmt)).  */
-      if (1)
+      if (!gimple_omp_for_combined_p (fd->for_stmt))
 	{
 	  if (POINTER_TYPE_P (type))
 	    t = fold_build_pointer_plus (vmain, fd->loop.step);
@@ -4686,7 +5489,7 @@ expand_omp_for_generic (struct omp_regio
       /* Remove GIMPLE_OMP_CONTINUE.  */
       gsi_remove (&gsi, true);
 
-      if (fd->collapse > 1)
+      if (fd->collapse > 1 && !gimple_omp_for_combined_p (fd->for_stmt))
 	collapse_bb = extract_omp_for_update_vars (fd, cont_bb, l1_bb);
 
       /* Emit code to get the next parallel iteration in L2_BB.  */
@@ -4708,9 +5511,13 @@ expand_omp_for_generic (struct omp_regio
   gsi = gsi_last_bb (exit_bb);
   if (gimple_omp_return_nowait_p (gsi_stmt (gsi)))
     t = builtin_decl_explicit (BUILT_IN_GOMP_LOOP_END_NOWAIT);
+  else if (gimple_omp_return_lhs (gsi_stmt (gsi)))
+    t = builtin_decl_explicit (BUILT_IN_GOMP_LOOP_END_CANCEL);
   else
     t = builtin_decl_explicit (BUILT_IN_GOMP_LOOP_END);
   stmt = gimple_build_call (t, 0);
+  if (gimple_omp_return_lhs (gsi_stmt (gsi)))
+    gimple_call_set_lhs (stmt, gimple_omp_return_lhs (gsi_stmt (gsi)));
   gsi_insert_after (&gsi, stmt, GSI_SAME_STMT);
   gsi_remove (&gsi, true);
 
@@ -4738,9 +5545,11 @@ expand_omp_for_generic (struct omp_regio
       if (current_loops)
 	add_bb_to_loop (l2_bb, cont_bb->loop_father);
       e = find_edge (cont_bb, l1_bb);
-      /* OMP4 placeholder for gimple_omp_for_combined_p (fd->for_stmt).  */
-      if (0)
-	;
+      if (gimple_omp_for_combined_p (fd->for_stmt))
+	{
+	  remove_edge (e);
+	  e = NULL;
+	}
       else if (fd->collapse > 1)
 	{
 	  remove_edge (e);
@@ -4774,8 +5583,7 @@ expand_omp_for_generic (struct omp_regio
       outer_loop->latch = l2_bb;
       add_loop (outer_loop, l0_bb->loop_father);
 
-      /* OMP4 placeholder: if (!gimple_omp_for_combined_p (fd->for_stmt)).  */
-      if (1)
+      if (!gimple_omp_for_combined_p (fd->for_stmt))
 	{
 	  struct loop *loop = alloc_loop ();
 	  loop->header = l1_bb;
@@ -4825,16 +5633,22 @@ expand_omp_for_generic (struct omp_regio
 
 static void
 expand_omp_for_static_nochunk (struct omp_region *region,
-			       struct omp_for_data *fd)
+			       struct omp_for_data *fd,
+			       gimple inner_stmt)
 {
   tree n, q, s0, e0, e, t, tt, nthreads, threadid;
   tree type, itype, vmain, vback;
   basic_block entry_bb, second_bb, third_bb, exit_bb, seq_start_bb;
-  basic_block body_bb, cont_bb;
+  basic_block body_bb, cont_bb, collapse_bb = NULL;
   basic_block fin_bb;
   gimple_stmt_iterator gsi;
   gimple stmt;
   edge ep;
+  enum built_in_function get_num_threads = BUILT_IN_OMP_GET_NUM_THREADS;
+  enum built_in_function get_thread_num = BUILT_IN_OMP_GET_THREAD_NUM;
+  bool broken_loop = region->cont == NULL;
+  tree *counts = NULL;
+  tree n1, n2, step;
 
   itype = type = TREE_TYPE (fd->loop.v);
   if (POINTER_TYPE_P (type))
@@ -4843,25 +5657,49 @@ expand_omp_for_static_nochunk (struct om
   entry_bb = region->entry;
   cont_bb = region->cont;
   gcc_assert (EDGE_COUNT (entry_bb->succs) == 2);
-  gcc_assert (BRANCH_EDGE (entry_bb)->dest == FALLTHRU_EDGE (cont_bb)->dest);
+  fin_bb = BRANCH_EDGE (entry_bb)->dest;
+  gcc_assert (broken_loop
+	      || (fin_bb == FALLTHRU_EDGE (cont_bb)->dest));
   seq_start_bb = split_edge (FALLTHRU_EDGE (entry_bb));
   body_bb = single_succ (seq_start_bb);
-  gcc_assert (BRANCH_EDGE (cont_bb)->dest == body_bb);
-  gcc_assert (EDGE_COUNT (cont_bb->succs) == 2);
-  fin_bb = FALLTHRU_EDGE (cont_bb)->dest;
+  if (!broken_loop)
+    {
+      gcc_assert (BRANCH_EDGE (cont_bb)->dest == body_bb);
+      gcc_assert (EDGE_COUNT (cont_bb->succs) == 2);
+    }
   exit_bb = region->exit;
 
   /* Iteration space partitioning goes in ENTRY_BB.  */
   gsi = gsi_last_bb (entry_bb);
   gcc_assert (gimple_code (gsi_stmt (gsi)) == GIMPLE_OMP_FOR);
 
-  t = fold_binary (fd->loop.cond_code, boolean_type_node,
-		   fold_convert (type, fd->loop.n1),
-		   fold_convert (type, fd->loop.n2));
-  if (TYPE_UNSIGNED (type)
+  if (gimple_omp_for_kind (fd->for_stmt) == GF_OMP_FOR_KIND_DISTRIBUTE)
+    {
+      get_num_threads = BUILT_IN_OMP_GET_NUM_TEAMS;
+      get_thread_num = BUILT_IN_OMP_GET_TEAM_NUM;
+    }
+
+  if (fd->collapse > 1)
+    {
+      int first_zero_iter = -1;
+      basic_block l2_dom_bb = NULL;
+
+      counts = XALLOCAVEC (tree, fd->collapse);
+      expand_omp_for_init_counts (fd, &gsi, entry_bb, counts,
+				  fin_bb, first_zero_iter,
+				  l2_dom_bb);
+      t = NULL_TREE;
+    }
+  else if (gimple_omp_for_combined_into_p (fd->for_stmt))
+    t = integer_one_node;
+  else
+    t = fold_binary (fd->loop.cond_code, boolean_type_node,
+		     fold_convert (type, fd->loop.n1),
+		     fold_convert (type, fd->loop.n2));
+  if (fd->collapse == 1
+      && TYPE_UNSIGNED (type)
       && (t == NULL_TREE || !integer_onep (t)))
     {
-      tree n1, n2;
       n1 = fold_convert (type, unshare_expr (fd->loop.n1));
       n1 = force_gimple_operand_gsi (&gsi, n1, true, NULL_TREE,
 				     true, GSI_SAME_STMT);
@@ -4899,36 +5737,47 @@ expand_omp_for_static_nochunk (struct om
       gsi = gsi_last_bb (entry_bb);
     }
 
-  t = build_call_expr (builtin_decl_explicit (BUILT_IN_OMP_GET_NUM_THREADS), 0);
+  t = build_call_expr (builtin_decl_explicit (get_num_threads), 0);
   t = fold_convert (itype, t);
   nthreads = force_gimple_operand_gsi (&gsi, t, true, NULL_TREE,
 				       true, GSI_SAME_STMT);
 
-  t = build_call_expr (builtin_decl_explicit (BUILT_IN_OMP_GET_THREAD_NUM), 0);
+  t = build_call_expr (builtin_decl_explicit (get_thread_num), 0);
   t = fold_convert (itype, t);
   threadid = force_gimple_operand_gsi (&gsi, t, true, NULL_TREE,
 				       true, GSI_SAME_STMT);
 
-  fd->loop.n1
-    = force_gimple_operand_gsi (&gsi, fold_convert (type, fd->loop.n1),
-				true, NULL_TREE, true, GSI_SAME_STMT);
-  fd->loop.n2
-    = force_gimple_operand_gsi (&gsi, fold_convert (itype, fd->loop.n2),
-				true, NULL_TREE, true, GSI_SAME_STMT);
-  fd->loop.step
-    = force_gimple_operand_gsi (&gsi, fold_convert (itype, fd->loop.step),
-				true, NULL_TREE, true, GSI_SAME_STMT);
+  n1 = fd->loop.n1;
+  n2 = fd->loop.n2;
+  step = fd->loop.step;
+  if (gimple_omp_for_combined_into_p (fd->for_stmt))
+    {
+      tree innerc = find_omp_clause (gimple_omp_for_clauses (fd->for_stmt),
+				     OMP_CLAUSE__LOOPTEMP_);
+      gcc_assert (innerc);
+      n1 = OMP_CLAUSE_DECL (innerc);
+      innerc = find_omp_clause (OMP_CLAUSE_CHAIN (innerc),
+				OMP_CLAUSE__LOOPTEMP_);
+      gcc_assert (innerc);
+      n2 = OMP_CLAUSE_DECL (innerc);
+    }
+  n1 = force_gimple_operand_gsi (&gsi, fold_convert (type, n1),
+				 true, NULL_TREE, true, GSI_SAME_STMT);
+  n2 = force_gimple_operand_gsi (&gsi, fold_convert (itype, n2),
+				 true, NULL_TREE, true, GSI_SAME_STMT);
+  step = force_gimple_operand_gsi (&gsi, fold_convert (itype, step),
+				   true, NULL_TREE, true, GSI_SAME_STMT);
 
   t = build_int_cst (itype, (fd->loop.cond_code == LT_EXPR ? -1 : 1));
-  t = fold_build2 (PLUS_EXPR, itype, fd->loop.step, t);
-  t = fold_build2 (PLUS_EXPR, itype, t, fd->loop.n2);
-  t = fold_build2 (MINUS_EXPR, itype, t, fold_convert (itype, fd->loop.n1));
+  t = fold_build2 (PLUS_EXPR, itype, step, t);
+  t = fold_build2 (PLUS_EXPR, itype, t, n2);
+  t = fold_build2 (MINUS_EXPR, itype, t, fold_convert (itype, n1));
   if (TYPE_UNSIGNED (itype) && fd->loop.cond_code == GT_EXPR)
     t = fold_build2 (TRUNC_DIV_EXPR, itype,
 		     fold_build1 (NEGATE_EXPR, itype, t),
-		     fold_build1 (NEGATE_EXPR, itype, fd->loop.step));
+		     fold_build1 (NEGATE_EXPR, itype, step));
   else
-    t = fold_build2 (TRUNC_DIV_EXPR, itype, t, fd->loop.step);
+    t = fold_build2 (TRUNC_DIV_EXPR, itype, t, step);
   t = fold_convert (itype, t);
   n = force_gimple_operand_gsi (&gsi, t, true, NULL_TREE, true, GSI_SAME_STMT);
 
@@ -4976,58 +5825,96 @@ expand_omp_for_static_nochunk (struct om
   /* Setup code for sequential iteration goes in SEQ_START_BB.  */
   gsi = gsi_start_bb (seq_start_bb);
 
+  tree startvar = fd->loop.v;
+  tree endvar = NULL_TREE;
+
+  if (gimple_omp_for_combined_p (fd->for_stmt))
+    {
+      tree clauses = gimple_code (inner_stmt) == GIMPLE_OMP_PARALLEL
+		     ? gimple_omp_parallel_clauses (inner_stmt)
+		     : gimple_omp_for_clauses (inner_stmt);
+      tree innerc = find_omp_clause (clauses, OMP_CLAUSE__LOOPTEMP_);
+      gcc_assert (innerc);
+      startvar = OMP_CLAUSE_DECL (innerc);
+      innerc = find_omp_clause (OMP_CLAUSE_CHAIN (innerc),
+				OMP_CLAUSE__LOOPTEMP_);
+      gcc_assert (innerc);
+      endvar = OMP_CLAUSE_DECL (innerc);
+    }
   t = fold_convert (itype, s0);
-  t = fold_build2 (MULT_EXPR, itype, t, fd->loop.step);
+  t = fold_build2 (MULT_EXPR, itype, t, step);
   if (POINTER_TYPE_P (type))
-    t = fold_build_pointer_plus (fd->loop.n1, t);
+    t = fold_build_pointer_plus (n1, t);
   else
-    t = fold_build2 (PLUS_EXPR, type, t, fd->loop.n1);
+    t = fold_build2 (PLUS_EXPR, type, t, n1);
+  t = fold_convert (TREE_TYPE (startvar), t);
   t = force_gimple_operand_gsi (&gsi, t,
-				DECL_P (fd->loop.v)
-				&& TREE_ADDRESSABLE (fd->loop.v),
+				DECL_P (startvar)
+				&& TREE_ADDRESSABLE (startvar),
 				NULL_TREE, false, GSI_CONTINUE_LINKING);
-  stmt = gimple_build_assign (fd->loop.v, t);
+  stmt = gimple_build_assign (startvar, t);
   gsi_insert_after (&gsi, stmt, GSI_CONTINUE_LINKING);
 
   t = fold_convert (itype, e0);
-  t = fold_build2 (MULT_EXPR, itype, t, fd->loop.step);
+  t = fold_build2 (MULT_EXPR, itype, t, step);
   if (POINTER_TYPE_P (type))
-    t = fold_build_pointer_plus (fd->loop.n1, t);
+    t = fold_build_pointer_plus (n1, t);
   else
-    t = fold_build2 (PLUS_EXPR, type, t, fd->loop.n1);
+    t = fold_build2 (PLUS_EXPR, type, t, n1);
+  t = fold_convert (TREE_TYPE (startvar), t);
   e = force_gimple_operand_gsi (&gsi, t, true, NULL_TREE,
 				false, GSI_CONTINUE_LINKING);
+  if (endvar)
+    {
+      stmt = gimple_build_assign (endvar, e);
+      gsi_insert_after (&gsi, stmt, GSI_CONTINUE_LINKING);
+    }
+  if (fd->collapse > 1)
+    expand_omp_for_init_vars (fd, &gsi, counts, inner_stmt, startvar);
 
-  /* The code controlling the sequential loop replaces the
-     GIMPLE_OMP_CONTINUE.  */
-  gsi = gsi_last_bb (cont_bb);
-  stmt = gsi_stmt (gsi);
-  gcc_assert (gimple_code (stmt) == GIMPLE_OMP_CONTINUE);
-  vmain = gimple_omp_continue_control_use (stmt);
-  vback = gimple_omp_continue_control_def (stmt);
+  if (!broken_loop)
+    {
+      /* The code controlling the sequential loop replaces the
+	 GIMPLE_OMP_CONTINUE.  */
+      gsi = gsi_last_bb (cont_bb);
+      stmt = gsi_stmt (gsi);
+      gcc_assert (gimple_code (stmt) == GIMPLE_OMP_CONTINUE);
+      vmain = gimple_omp_continue_control_use (stmt);
+      vback = gimple_omp_continue_control_def (stmt);
 
-  if (POINTER_TYPE_P (type))
-    t = fold_build_pointer_plus (vmain, fd->loop.step);
-  else
-    t = fold_build2 (PLUS_EXPR, type, vmain, fd->loop.step);
-  t = force_gimple_operand_gsi (&gsi, t,
-				DECL_P (vback) && TREE_ADDRESSABLE (vback),
-				NULL_TREE, true, GSI_SAME_STMT);
-  stmt = gimple_build_assign (vback, t);
-  gsi_insert_before (&gsi, stmt, GSI_SAME_STMT);
+      if (!gimple_omp_for_combined_p (fd->for_stmt))
+	{
+	  if (POINTER_TYPE_P (type))
+	    t = fold_build_pointer_plus (vmain, step);
+	  else
+	    t = fold_build2 (PLUS_EXPR, type, vmain, step);
+	  t = force_gimple_operand_gsi (&gsi, t,
+					DECL_P (vback)
+					&& TREE_ADDRESSABLE (vback),
+					NULL_TREE, true, GSI_SAME_STMT);
+	  stmt = gimple_build_assign (vback, t);
+	  gsi_insert_before (&gsi, stmt, GSI_SAME_STMT);
 
-  t = build2 (fd->loop.cond_code, boolean_type_node,
-	      DECL_P (vback) && TREE_ADDRESSABLE (vback) ? t : vback, e);
-  gsi_insert_before (&gsi, gimple_build_cond_empty (t), GSI_SAME_STMT);
+	  t = build2 (fd->loop.cond_code, boolean_type_node,
+		      DECL_P (vback) && TREE_ADDRESSABLE (vback)
+		      ? t : vback, e);
+	  gsi_insert_before (&gsi, gimple_build_cond_empty (t), GSI_SAME_STMT);
+	}
 
-  /* Remove the GIMPLE_OMP_CONTINUE statement.  */
-  gsi_remove (&gsi, true);
+      /* Remove the GIMPLE_OMP_CONTINUE statement.  */
+      gsi_remove (&gsi, true);
+
+      if (fd->collapse > 1 && !gimple_omp_for_combined_p (fd->for_stmt))
+	collapse_bb = extract_omp_for_update_vars (fd, cont_bb, body_bb);
+    }
 
   /* Replace the GIMPLE_OMP_RETURN with a barrier, or nothing.  */
   gsi = gsi_last_bb (exit_bb);
   if (!gimple_omp_return_nowait_p (gsi_stmt (gsi)))
-    force_gimple_operand_gsi (&gsi, build_omp_barrier (), false, NULL_TREE,
-			      false, GSI_SAME_STMT);
+    {
+      t = gimple_omp_return_lhs (gsi_stmt (gsi));
+      gsi_insert_after (&gsi, build_omp_barrier (t), GSI_SAME_STMT);
+    }
   gsi_remove (&gsi, true);
 
   /* Connect all the blocks.  */
@@ -5039,21 +5926,42 @@ expand_omp_for_static_nochunk (struct om
   find_edge (third_bb, seq_start_bb)->flags = EDGE_FALSE_VALUE;
   find_edge (third_bb, fin_bb)->flags = EDGE_TRUE_VALUE;
 
-  find_edge (cont_bb, body_bb)->flags = EDGE_TRUE_VALUE;
-  find_edge (cont_bb, fin_bb)->flags = EDGE_FALSE_VALUE;
+  if (!broken_loop)
+    {
+      ep = find_edge (cont_bb, body_bb);
+      if (gimple_omp_for_combined_p (fd->for_stmt))
+	{
+	  remove_edge (ep);
+	  ep = NULL;
+	}
+      else if (fd->collapse > 1)
+	{
+	  remove_edge (ep);
+	  ep = make_edge (cont_bb, collapse_bb, EDGE_TRUE_VALUE);
+	}
+      else
+	ep->flags = EDGE_TRUE_VALUE;
+      find_edge (cont_bb, fin_bb)->flags
+	= ep ? EDGE_FALSE_VALUE : EDGE_FALLTHRU;
+    }
 
   set_immediate_dominator (CDI_DOMINATORS, second_bb, entry_bb);
   set_immediate_dominator (CDI_DOMINATORS, third_bb, entry_bb);
   set_immediate_dominator (CDI_DOMINATORS, seq_start_bb, third_bb);
+
   set_immediate_dominator (CDI_DOMINATORS, body_bb,
 			   recompute_dominator (CDI_DOMINATORS, body_bb));
   set_immediate_dominator (CDI_DOMINATORS, fin_bb,
 			   recompute_dominator (CDI_DOMINATORS, fin_bb));
 
-  struct loop *loop = alloc_loop ();
-  loop->header = body_bb;
-  loop->latch = cont_bb;
-  add_loop (loop, body_bb->loop_father);
+  if (!broken_loop && !gimple_omp_for_combined_p (fd->for_stmt))
+    {
+      struct loop *loop = alloc_loop ();
+      loop->header = body_bb;
+      if (collapse_bb == NULL)
+	loop->latch = cont_bb;
+      add_loop (loop, body_bb->loop_father);
+    }
 }
 
 
@@ -5096,16 +6004,22 @@ expand_omp_for_static_nochunk (struct om
 */
 
 static void
-expand_omp_for_static_chunk (struct omp_region *region, struct omp_for_data *fd)
+expand_omp_for_static_chunk (struct omp_region *region,
+			     struct omp_for_data *fd, gimple inner_stmt)
 {
   tree n, s0, e0, e, t;
   tree trip_var, trip_init, trip_main, trip_back, nthreads, threadid;
   tree type, itype, v_main, v_back, v_extra;
   basic_block entry_bb, exit_bb, body_bb, seq_start_bb, iter_part_bb;
-  basic_block trip_update_bb, cont_bb, fin_bb;
+  basic_block trip_update_bb = NULL, cont_bb, collapse_bb = NULL, fin_bb;
   gimple_stmt_iterator si;
   gimple stmt;
   edge se;
+  enum built_in_function get_num_threads = BUILT_IN_OMP_GET_NUM_THREADS;
+  enum built_in_function get_thread_num = BUILT_IN_OMP_GET_THREAD_NUM;
+  bool broken_loop = region->cont == NULL;
+  tree *counts = NULL;
+  tree n1, n2, step;
 
   itype = type = TREE_TYPE (fd->loop.v);
   if (POINTER_TYPE_P (type))
@@ -5117,27 +6031,50 @@ expand_omp_for_static_chunk (struct omp_
   iter_part_bb = se->dest;
   cont_bb = region->cont;
   gcc_assert (EDGE_COUNT (iter_part_bb->succs) == 2);
-  gcc_assert (BRANCH_EDGE (iter_part_bb)->dest
-	      == FALLTHRU_EDGE (cont_bb)->dest);
+  fin_bb = BRANCH_EDGE (iter_part_bb)->dest;
+  gcc_assert (broken_loop
+	      || fin_bb == FALLTHRU_EDGE (cont_bb)->dest);
   seq_start_bb = split_edge (FALLTHRU_EDGE (iter_part_bb));
   body_bb = single_succ (seq_start_bb);
-  gcc_assert (BRANCH_EDGE (cont_bb)->dest == body_bb);
-  gcc_assert (EDGE_COUNT (cont_bb->succs) == 2);
-  fin_bb = FALLTHRU_EDGE (cont_bb)->dest;
-  trip_update_bb = split_edge (FALLTHRU_EDGE (cont_bb));
+  if (!broken_loop)
+    {
+      gcc_assert (BRANCH_EDGE (cont_bb)->dest == body_bb);
+      gcc_assert (EDGE_COUNT (cont_bb->succs) == 2);
+      trip_update_bb = split_edge (FALLTHRU_EDGE (cont_bb));
+    }
   exit_bb = region->exit;
 
   /* Trip and adjustment setup goes in ENTRY_BB.  */
   si = gsi_last_bb (entry_bb);
   gcc_assert (gimple_code (gsi_stmt (si)) == GIMPLE_OMP_FOR);
 
-  t = fold_binary (fd->loop.cond_code, boolean_type_node,
-		   fold_convert (type, fd->loop.n1),
-		   fold_convert (type, fd->loop.n2));
-  if (TYPE_UNSIGNED (type)
+  if (gimple_omp_for_kind (fd->for_stmt) == GF_OMP_FOR_KIND_DISTRIBUTE)
+    {
+      get_num_threads = BUILT_IN_OMP_GET_NUM_TEAMS;
+      get_thread_num = BUILT_IN_OMP_GET_TEAM_NUM;
+    }
+
+  if (fd->collapse > 1)
+    {
+      int first_zero_iter = -1;
+      basic_block l2_dom_bb = NULL;
+
+      counts = XALLOCAVEC (tree, fd->collapse);
+      expand_omp_for_init_counts (fd, &si, entry_bb, counts,
+				  fin_bb, first_zero_iter,
+				  l2_dom_bb);
+      t = NULL_TREE;
+    }
+  else if (gimple_omp_for_combined_into_p (fd->for_stmt))
+    t = integer_one_node;
+  else
+    t = fold_binary (fd->loop.cond_code, boolean_type_node,
+		     fold_convert (type, fd->loop.n1),
+		     fold_convert (type, fd->loop.n2));
+  if (fd->collapse == 1
+      && TYPE_UNSIGNED (type)
       && (t == NULL_TREE || !integer_onep (t)))
     {
-      tree n1, n2;
       n1 = fold_convert (type, unshare_expr (fd->loop.n1));
       n1 = force_gimple_operand_gsi (&si, n1, true, NULL_TREE,
 				     true, GSI_SAME_STMT);
@@ -5175,39 +6112,50 @@ expand_omp_for_static_chunk (struct omp_
       si = gsi_last_bb (entry_bb);
     }
 
-  t = build_call_expr (builtin_decl_explicit (BUILT_IN_OMP_GET_NUM_THREADS), 0);
+  t = build_call_expr (builtin_decl_explicit (get_num_threads), 0);
   t = fold_convert (itype, t);
   nthreads = force_gimple_operand_gsi (&si, t, true, NULL_TREE,
 				       true, GSI_SAME_STMT);
 
-  t = build_call_expr (builtin_decl_explicit (BUILT_IN_OMP_GET_THREAD_NUM), 0);
+  t = build_call_expr (builtin_decl_explicit (get_thread_num), 0);
   t = fold_convert (itype, t);
   threadid = force_gimple_operand_gsi (&si, t, true, NULL_TREE,
 				       true, GSI_SAME_STMT);
 
-  fd->loop.n1
-    = force_gimple_operand_gsi (&si, fold_convert (type, fd->loop.n1),
-				true, NULL_TREE, true, GSI_SAME_STMT);
-  fd->loop.n2
-    = force_gimple_operand_gsi (&si, fold_convert (itype, fd->loop.n2),
-				true, NULL_TREE, true, GSI_SAME_STMT);
-  fd->loop.step
-    = force_gimple_operand_gsi (&si, fold_convert (itype, fd->loop.step),
-				true, NULL_TREE, true, GSI_SAME_STMT);
+  n1 = fd->loop.n1;
+  n2 = fd->loop.n2;
+  step = fd->loop.step;
+  if (gimple_omp_for_combined_into_p (fd->for_stmt))
+    {
+      tree innerc = find_omp_clause (gimple_omp_for_clauses (fd->for_stmt),
+				     OMP_CLAUSE__LOOPTEMP_);
+      gcc_assert (innerc);
+      n1 = OMP_CLAUSE_DECL (innerc);
+      innerc = find_omp_clause (OMP_CLAUSE_CHAIN (innerc),
+				OMP_CLAUSE__LOOPTEMP_);
+      gcc_assert (innerc);
+      n2 = OMP_CLAUSE_DECL (innerc);
+    }
+  n1 = force_gimple_operand_gsi (&si, fold_convert (type, n1),
+				 true, NULL_TREE, true, GSI_SAME_STMT);
+  n2 = force_gimple_operand_gsi (&si, fold_convert (itype, n2),
+				 true, NULL_TREE, true, GSI_SAME_STMT);
+  step = force_gimple_operand_gsi (&si, fold_convert (itype, step),
+				   true, NULL_TREE, true, GSI_SAME_STMT);
   fd->chunk_size
     = force_gimple_operand_gsi (&si, fold_convert (itype, fd->chunk_size),
 				true, NULL_TREE, true, GSI_SAME_STMT);
 
   t = build_int_cst (itype, (fd->loop.cond_code == LT_EXPR ? -1 : 1));
-  t = fold_build2 (PLUS_EXPR, itype, fd->loop.step, t);
-  t = fold_build2 (PLUS_EXPR, itype, t, fd->loop.n2);
-  t = fold_build2 (MINUS_EXPR, itype, t, fold_convert (itype, fd->loop.n1));
+  t = fold_build2 (PLUS_EXPR, itype, step, t);
+  t = fold_build2 (PLUS_EXPR, itype, t, n2);
+  t = fold_build2 (MINUS_EXPR, itype, t, fold_convert (itype, n1));
   if (TYPE_UNSIGNED (itype) && fd->loop.cond_code == GT_EXPR)
     t = fold_build2 (TRUNC_DIV_EXPR, itype,
 		     fold_build1 (NEGATE_EXPR, itype, t),
-		     fold_build1 (NEGATE_EXPR, itype, fd->loop.step));
+		     fold_build1 (NEGATE_EXPR, itype, step));
   else
-    t = fold_build2 (TRUNC_DIV_EXPR, itype, t, fd->loop.step);
+    t = fold_build2 (TRUNC_DIV_EXPR, itype, t, step);
   t = fold_convert (itype, t);
   n = force_gimple_operand_gsi (&si, t, true, NULL_TREE,
 				true, GSI_SAME_STMT);
@@ -5230,11 +6178,11 @@ expand_omp_for_static_chunk (struct omp_
   gsi_insert_before (&si, stmt, GSI_SAME_STMT);
 
   t = fold_build2 (MULT_EXPR, itype, threadid, fd->chunk_size);
-  t = fold_build2 (MULT_EXPR, itype, t, fd->loop.step);
+  t = fold_build2 (MULT_EXPR, itype, t, step);
   if (POINTER_TYPE_P (type))
-    t = fold_build_pointer_plus (fd->loop.n1, t);
+    t = fold_build_pointer_plus (n1, t);
   else
-    t = fold_build2 (PLUS_EXPR, type, t, fd->loop.n1);
+    t = fold_build2 (PLUS_EXPR, type, t, n1);
   v_extra = force_gimple_operand_gsi (&si, t, true, NULL_TREE,
 				      true, GSI_SAME_STMT);
 
@@ -5261,77 +6209,130 @@ expand_omp_for_static_chunk (struct omp_
   /* Setup code for sequential iteration goes in SEQ_START_BB.  */
   si = gsi_start_bb (seq_start_bb);
 
+  tree startvar = fd->loop.v;
+  tree endvar = NULL_TREE;
+
+  if (gimple_omp_for_combined_p (fd->for_stmt))
+    {
+      tree clauses = gimple_code (inner_stmt) == GIMPLE_OMP_PARALLEL
+		     ? gimple_omp_parallel_clauses (inner_stmt)
+		     : gimple_omp_for_clauses (inner_stmt);
+      tree innerc = find_omp_clause (clauses, OMP_CLAUSE__LOOPTEMP_);
+      gcc_assert (innerc);
+      startvar = OMP_CLAUSE_DECL (innerc);
+      innerc = find_omp_clause (OMP_CLAUSE_CHAIN (innerc),
+				OMP_CLAUSE__LOOPTEMP_);
+      gcc_assert (innerc);
+      endvar = OMP_CLAUSE_DECL (innerc);
+    }
+
   t = fold_convert (itype, s0);
-  t = fold_build2 (MULT_EXPR, itype, t, fd->loop.step);
+  t = fold_build2 (MULT_EXPR, itype, t, step);
   if (POINTER_TYPE_P (type))
-    t = fold_build_pointer_plus (fd->loop.n1, t);
+    t = fold_build_pointer_plus (n1, t);
   else
-    t = fold_build2 (PLUS_EXPR, type, t, fd->loop.n1);
+    t = fold_build2 (PLUS_EXPR, type, t, n1);
+  t = fold_convert (TREE_TYPE (startvar), t);
   t = force_gimple_operand_gsi (&si, t,
-				DECL_P (fd->loop.v)
-				&& TREE_ADDRESSABLE (fd->loop.v),
+				DECL_P (startvar)
+				&& TREE_ADDRESSABLE (startvar),
 				NULL_TREE, false, GSI_CONTINUE_LINKING);
-  stmt = gimple_build_assign (fd->loop.v, t);
+  stmt = gimple_build_assign (startvar, t);
   gsi_insert_after (&si, stmt, GSI_CONTINUE_LINKING);
 
   t = fold_convert (itype, e0);
-  t = fold_build2 (MULT_EXPR, itype, t, fd->loop.step);
+  t = fold_build2 (MULT_EXPR, itype, t, step);
   if (POINTER_TYPE_P (type))
-    t = fold_build_pointer_plus (fd->loop.n1, t);
+    t = fold_build_pointer_plus (n1, t);
   else
-    t = fold_build2 (PLUS_EXPR, type, t, fd->loop.n1);
+    t = fold_build2 (PLUS_EXPR, type, t, n1);
+  t = fold_convert (TREE_TYPE (startvar), t);
   e = force_gimple_operand_gsi (&si, t, true, NULL_TREE,
 				false, GSI_CONTINUE_LINKING);
+  if (endvar)
+    {
+      stmt = gimple_build_assign (endvar, e);
+      gsi_insert_after (&si, stmt, GSI_CONTINUE_LINKING);
+    }
+  if (fd->collapse > 1)
+    expand_omp_for_init_vars (fd, &si, counts, inner_stmt, startvar);
+
+  if (!broken_loop)
+    {
+      /* The code controlling the sequential loop goes in CONT_BB,
+	 replacing the GIMPLE_OMP_CONTINUE.  */
+      si = gsi_last_bb (cont_bb);
+      stmt = gsi_stmt (si);
+      gcc_assert (gimple_code (stmt) == GIMPLE_OMP_CONTINUE);
+      v_main = gimple_omp_continue_control_use (stmt);
+      v_back = gimple_omp_continue_control_def (stmt);
 
-  /* The code controlling the sequential loop goes in CONT_BB,
-     replacing the GIMPLE_OMP_CONTINUE.  */
-  si = gsi_last_bb (cont_bb);
-  stmt = gsi_stmt (si);
-  gcc_assert (gimple_code (stmt) == GIMPLE_OMP_CONTINUE);
-  v_main = gimple_omp_continue_control_use (stmt);
-  v_back = gimple_omp_continue_control_def (stmt);
+      if (!gimple_omp_for_combined_p (fd->for_stmt))
+	{
+	  if (POINTER_TYPE_P (type))
+	    t = fold_build_pointer_plus (v_main, step);
+	  else
+	    t = fold_build2 (PLUS_EXPR, type, v_main, step);
+	  if (DECL_P (v_back) && TREE_ADDRESSABLE (v_back))
+	    t = force_gimple_operand_gsi (&si, t, true, NULL_TREE,
+					  true, GSI_SAME_STMT);
+	  stmt = gimple_build_assign (v_back, t);
+	  gsi_insert_before (&si, stmt, GSI_SAME_STMT);
 
-  if (POINTER_TYPE_P (type))
-    t = fold_build_pointer_plus (v_main, fd->loop.step);
-  else
-    t = fold_build2 (PLUS_EXPR, type, v_main, fd->loop.step);
-  if (DECL_P (v_back) && TREE_ADDRESSABLE (v_back))
-    t = force_gimple_operand_gsi (&si, t, true, NULL_TREE,
-				  true, GSI_SAME_STMT);
-  stmt = gimple_build_assign (v_back, t);
-  gsi_insert_before (&si, stmt, GSI_SAME_STMT);
+	  t = build2 (fd->loop.cond_code, boolean_type_node,
+		      DECL_P (v_back) && TREE_ADDRESSABLE (v_back)
+		      ? t : v_back, e);
+	  gsi_insert_before (&si, gimple_build_cond_empty (t), GSI_SAME_STMT);
+	}
 
-  t = build2 (fd->loop.cond_code, boolean_type_node,
-	      DECL_P (v_back) && TREE_ADDRESSABLE (v_back)
-	      ? t : v_back, e);
-  gsi_insert_before (&si, gimple_build_cond_empty (t), GSI_SAME_STMT);
+      /* Remove GIMPLE_OMP_CONTINUE.  */
+      gsi_remove (&si, true);
 
-  /* Remove GIMPLE_OMP_CONTINUE.  */
-  gsi_remove (&si, true);
+      if (fd->collapse > 1 && !gimple_omp_for_combined_p (fd->for_stmt))
+	collapse_bb = extract_omp_for_update_vars (fd, cont_bb, body_bb);
 
-  /* Trip update code goes into TRIP_UPDATE_BB.  */
-  si = gsi_start_bb (trip_update_bb);
+      /* Trip update code goes into TRIP_UPDATE_BB.  */
+      si = gsi_start_bb (trip_update_bb);
 
-  t = build_int_cst (itype, 1);
-  t = build2 (PLUS_EXPR, itype, trip_main, t);
-  stmt = gimple_build_assign (trip_back, t);
-  gsi_insert_after (&si, stmt, GSI_CONTINUE_LINKING);
+      t = build_int_cst (itype, 1);
+      t = build2 (PLUS_EXPR, itype, trip_main, t);
+      stmt = gimple_build_assign (trip_back, t);
+      gsi_insert_after (&si, stmt, GSI_CONTINUE_LINKING);
+    }
 
   /* Replace the GIMPLE_OMP_RETURN with a barrier, or nothing.  */
   si = gsi_last_bb (exit_bb);
   if (!gimple_omp_return_nowait_p (gsi_stmt (si)))
-    force_gimple_operand_gsi (&si, build_omp_barrier (), false, NULL_TREE,
-			      false, GSI_SAME_STMT);
+    {
+      t = gimple_omp_return_lhs (gsi_stmt (si));
+      gsi_insert_after (&si, build_omp_barrier (t), GSI_SAME_STMT);
+    }
   gsi_remove (&si, true);
 
   /* Connect the new blocks.  */
   find_edge (iter_part_bb, seq_start_bb)->flags = EDGE_TRUE_VALUE;
   find_edge (iter_part_bb, fin_bb)->flags = EDGE_FALSE_VALUE;
 
-  find_edge (cont_bb, body_bb)->flags = EDGE_TRUE_VALUE;
-  find_edge (cont_bb, trip_update_bb)->flags = EDGE_FALSE_VALUE;
+  if (!broken_loop)
+    {
+      se = find_edge (cont_bb, body_bb);
+      if (gimple_omp_for_combined_p (fd->for_stmt))
+	{
+	  remove_edge (se);
+	  se = NULL;
+	}
+      else if (fd->collapse > 1)
+	{
+	  remove_edge (se);
+	  se = make_edge (cont_bb, collapse_bb, EDGE_TRUE_VALUE);
+	}
+      else
+	se->flags = EDGE_TRUE_VALUE;
+      find_edge (cont_bb, trip_update_bb)->flags
+	= se ? EDGE_FALSE_VALUE : EDGE_FALLTHRU;
 
-  redirect_edge_and_branch (single_succ_edge (trip_update_bb), iter_part_bb);
+      redirect_edge_and_branch (single_succ_edge (trip_update_bb), iter_part_bb);
+    }
 
   if (gimple_in_ssa_p (cfun))
     {
@@ -5342,6 +6343,8 @@ expand_omp_for_static_chunk (struct omp_
       edge_var_map *vm;
       size_t i;
 
+      gcc_assert (fd->collapse == 1 && !broken_loop);
+
       /* When we redirect the edge from trip_update_bb to iter_part_bb, we
 	 remove arguments of the phi nodes in fin_bb.  We need to create
 	 appropriate phi nodes in iter_part_bb instead.  */
@@ -5391,7 +6394,8 @@ expand_omp_for_static_chunk (struct omp_
 		   UNKNOWN_LOCATION);
     }
 
-  set_immediate_dominator (CDI_DOMINATORS, trip_update_bb, cont_bb);
+  if (!broken_loop)
+    set_immediate_dominator (CDI_DOMINATORS, trip_update_bb, cont_bb);
   set_immediate_dominator (CDI_DOMINATORS, iter_part_bb,
 			   recompute_dominator (CDI_DOMINATORS, iter_part_bb));
   set_immediate_dominator (CDI_DOMINATORS, fin_bb,
@@ -5401,17 +6405,24 @@ expand_omp_for_static_chunk (struct omp_
   set_immediate_dominator (CDI_DOMINATORS, body_bb,
 			   recompute_dominator (CDI_DOMINATORS, body_bb));
 
-  struct loop *trip_loop = alloc_loop ();
-  trip_loop->header = iter_part_bb;
-  trip_loop->latch = trip_update_bb;
-  add_loop (trip_loop, iter_part_bb->loop_father);
+  if (!broken_loop)
+    {
+      struct loop *trip_loop = alloc_loop ();
+      trip_loop->header = iter_part_bb;
+      trip_loop->latch = trip_update_bb;
+      add_loop (trip_loop, iter_part_bb->loop_father);
 
-  struct loop *loop = alloc_loop ();
-  loop->header = body_bb;
-  loop->latch = cont_bb;
-  add_loop (loop, trip_loop);
+      if (!gimple_omp_for_combined_p (fd->for_stmt))
+	{
+	  struct loop *loop = alloc_loop ();
+	  loop->header = body_bb;
+	  loop->latch = cont_bb;
+	  add_loop (loop, trip_loop);
+	}
+    }
 }
 
+
 /* A subroutine of expand_omp_for.  Generate code for a simd non-worksharing
    loop.  Given parameters:
 
@@ -5487,7 +6498,7 @@ expand_omp_simd (struct omp_region *regi
 				  OMP_CLAUSE_SAFELEN);
   tree simduid = find_omp_clause (gimple_omp_for_clauses (fd->for_stmt),
 				  OMP_CLAUSE__SIMDUID_);
-  tree n2;
+  tree n1, n2;
 
   type = TREE_TYPE (fd->loop.v);
   entry_bb = region->entry;
@@ -5530,10 +6541,27 @@ expand_omp_simd (struct omp_region *regi
   if (l2_dom_bb == NULL)
     l2_dom_bb = l1_bb;
 
+  n1 = fd->loop.n1;
   n2 = fd->loop.n2;
-  if (0)
-    /* Place holder for gimple_omp_for_combined_into_p() in
-       the upcoming gomp-4_0-branch merge.  */;
+  if (gimple_omp_for_combined_into_p (fd->for_stmt))
+    {
+      tree innerc = find_omp_clause (gimple_omp_for_clauses (fd->for_stmt),
+				     OMP_CLAUSE__LOOPTEMP_);
+      gcc_assert (innerc);
+      n1 = OMP_CLAUSE_DECL (innerc);
+      innerc = find_omp_clause (OMP_CLAUSE_CHAIN (innerc),
+				OMP_CLAUSE__LOOPTEMP_);
+      gcc_assert (innerc);
+      n2 = OMP_CLAUSE_DECL (innerc);
+      expand_omp_build_assign (&gsi, fd->loop.v,
+			       fold_convert (type, n1));
+      if (fd->collapse > 1)
+	{
+	  gsi_prev (&gsi);
+	  expand_omp_for_init_vars (fd, &gsi, counts, NULL, n1);
+	  gsi_next (&gsi);
+	}
+    }
   else
     {
       expand_omp_build_assign (&gsi, fd->loop.v,
@@ -5706,7 +6734,7 @@ expand_omp_simd (struct omp_region *regi
 /* Expand the OpenMP loop defined by REGION.  */
 
 static void
-expand_omp_for (struct omp_region *region)
+expand_omp_for (struct omp_region *region, gimple inner_stmt)
 {
   struct omp_for_data fd;
   struct omp_for_data_loop *loops;
@@ -5736,14 +6764,12 @@ expand_omp_for (struct omp_region *regio
   if (gimple_omp_for_kind (fd.for_stmt) == GF_OMP_FOR_KIND_SIMD)
     expand_omp_simd (region, &fd);
   else if (fd.sched_kind == OMP_CLAUSE_SCHEDULE_STATIC
-      && !fd.have_ordered
-      && fd.collapse == 1
-      && region->cont != NULL)
+	   && !fd.have_ordered)
     {
       if (fd.chunk_size == NULL)
-	expand_omp_for_static_nochunk (region, &fd);
+	expand_omp_for_static_nochunk (region, &fd, inner_stmt);
       else
-	expand_omp_for_static_chunk (region, &fd);
+	expand_omp_for_static_chunk (region, &fd, inner_stmt);
     }
   else
     {
@@ -5768,7 +6794,7 @@ expand_omp_for (struct omp_region *regio
 		      - (int)BUILT_IN_GOMP_LOOP_STATIC_NEXT);
 	}
       expand_omp_for_generic (region, &fd, (enum built_in_function) start_ix,
-			      (enum built_in_function) next_ix);
+			      (enum built_in_function) next_ix, inner_stmt);
     }
 
   if (gimple_in_ssa_p (cfun))
@@ -5983,9 +7009,13 @@ expand_omp_sections (struct omp_region *
   si = gsi_last_bb (l2_bb);
   if (gimple_omp_return_nowait_p (gsi_stmt (si)))
     t = builtin_decl_explicit (BUILT_IN_GOMP_SECTIONS_END_NOWAIT);
+  else if (gimple_omp_return_lhs (gsi_stmt (si)))
+    t = builtin_decl_explicit (BUILT_IN_GOMP_SECTIONS_END_CANCEL);
   else
     t = builtin_decl_explicit (BUILT_IN_GOMP_SECTIONS_END);
   stmt = gimple_build_call (t, 0);
+  if (gimple_omp_return_lhs (gsi_stmt (si)))
+    gimple_call_set_lhs (stmt, gimple_omp_return_lhs (gsi_stmt (si)));
   gsi_insert_after (&si, stmt, GSI_SAME_STMT);
   gsi_remove (&si, true);
 
@@ -6001,26 +7031,21 @@ expand_omp_single (struct omp_region *re
 {
   basic_block entry_bb, exit_bb;
   gimple_stmt_iterator si;
-  bool need_barrier = false;
 
   entry_bb = region->entry;
   exit_bb = region->exit;
 
   si = gsi_last_bb (entry_bb);
-  /* The terminal barrier at the end of a GOMP_single_copy sequence cannot
-     be removed.  We need to ensure that the thread that entered the single
-     does not exit before the data is copied out by the other threads.  */
-  if (find_omp_clause (gimple_omp_single_clauses (gsi_stmt (si)),
-		       OMP_CLAUSE_COPYPRIVATE))
-    need_barrier = true;
   gcc_assert (gimple_code (gsi_stmt (si)) == GIMPLE_OMP_SINGLE);
   gsi_remove (&si, true);
   single_succ_edge (entry_bb)->flags = EDGE_FALLTHRU;
 
   si = gsi_last_bb (exit_bb);
-  if (!gimple_omp_return_nowait_p (gsi_stmt (si)) || need_barrier)
-    force_gimple_operand_gsi (&si, build_omp_barrier (), false, NULL_TREE,
-			      false, GSI_SAME_STMT);
+  if (!gimple_omp_return_nowait_p (gsi_stmt (si)))
+    {
+      tree t = gimple_omp_return_lhs (gsi_stmt (si));
+      gsi_insert_after (&si, build_omp_barrier (t), GSI_SAME_STMT);
+    }
   gsi_remove (&si, true);
   single_succ_edge (exit_bb)->flags = EDGE_FALLTHRU;
 }
@@ -6042,8 +7067,10 @@ expand_omp_synch (struct omp_region *reg
   si = gsi_last_bb (entry_bb);
   gcc_assert (gimple_code (gsi_stmt (si)) == GIMPLE_OMP_SINGLE
 	      || gimple_code (gsi_stmt (si)) == GIMPLE_OMP_MASTER
+	      || gimple_code (gsi_stmt (si)) == GIMPLE_OMP_TASKGROUP
 	      || gimple_code (gsi_stmt (si)) == GIMPLE_OMP_ORDERED
-	      || gimple_code (gsi_stmt (si)) == GIMPLE_OMP_CRITICAL);
+	      || gimple_code (gsi_stmt (si)) == GIMPLE_OMP_CRITICAL
+	      || gimple_code (gsi_stmt (si)) == GIMPLE_OMP_TEAMS);
   gsi_remove (&si, true);
   single_succ_edge (entry_bb)->flags = EDGE_FALLTHRU;
 
@@ -6088,7 +7115,10 @@ expand_omp_atomic_load (basic_block load
   itype = TREE_TYPE (TREE_TYPE (decl));
 
   call = build_call_expr_loc (loc, decl, 2, addr,
-			      build_int_cst (NULL, MEMMODEL_RELAXED));
+			      build_int_cst (NULL,
+					     gimple_omp_atomic_seq_cst_p (stmt)
+					     ? MEMMODEL_SEQ_CST
+					     : MEMMODEL_RELAXED));
   if (!useless_type_conversion_p (type, itype))
     call = fold_build1_loc (loc, VIEW_CONVERT_EXPR, type, call);
   call = build2_loc (loc, MODIFY_EXPR, void_type_node, loaded_val, call);
@@ -6160,7 +7190,10 @@ expand_omp_atomic_store (basic_block loa
   if (!useless_type_conversion_p (itype, type))
     stored_val = fold_build1_loc (loc, VIEW_CONVERT_EXPR, itype, stored_val);
   call = build_call_expr_loc (loc, decl, 3, addr, stored_val,
-			      build_int_cst (NULL, MEMMODEL_RELAXED));
+			      build_int_cst (NULL,
+					     gimple_omp_atomic_seq_cst_p (stmt)
+					     ? MEMMODEL_SEQ_CST
+					     : MEMMODEL_RELAXED));
   if (exchange)
     {
       if (!useless_type_conversion_p (type, itype))
@@ -6201,6 +7234,7 @@ expand_omp_atomic_fetch_op (basic_block
   enum tree_code code;
   bool need_old, need_new;
   enum machine_mode imode;
+  bool seq_cst;
 
   /* We expect to find the following sequences:
 
@@ -6226,6 +7260,7 @@ expand_omp_atomic_fetch_op (basic_block
     return false;
   need_new = gimple_omp_atomic_need_value_p (gsi_stmt (gsi));
   need_old = gimple_omp_atomic_need_value_p (last_stmt (load_bb));
+  seq_cst = gimple_omp_atomic_seq_cst_p (last_stmt (load_bb));
   gcc_checking_assert (!need_old || !need_new);
 
   if (!operand_equal_p (gimple_assign_lhs (stmt), stored_val, 0))
@@ -6292,7 +7327,9 @@ expand_omp_atomic_fetch_op (basic_block
      use the RELAXED memory model.  */
   call = build_call_expr_loc (loc, decl, 3, addr,
 			      fold_convert_loc (loc, itype, rhs),
-			      build_int_cst (NULL, MEMMODEL_RELAXED));
+			      build_int_cst (NULL,
+					     seq_cst ? MEMMODEL_SEQ_CST
+						     : MEMMODEL_RELAXED));
 
   if (need_old || need_new)
     {
@@ -6622,41 +7659,361 @@ expand_omp_atomic (struct omp_region *re
 }
 
 
-/* Expand the parallel region tree rooted at REGION.  Expansion
-   proceeds in depth-first order.  Innermost regions are expanded
-   first.  This way, parallel regions that require a new function to
-   be created (e.g., GIMPLE_OMP_PARALLEL) can be expanded without having any
-   internal dependencies in their body.  */
+/* Expand the OpenMP target{, data, update} directive starting at REGION.  */
 
 static void
-expand_omp (struct omp_region *region)
+expand_omp_target (struct omp_region *region)
 {
-  while (region)
+  basic_block entry_bb, exit_bb, new_bb;
+  struct function *child_cfun = NULL;
+  tree child_fn = NULL_TREE, block, t;
+  gimple_stmt_iterator gsi;
+  gimple entry_stmt, stmt;
+  edge e;
+
+  entry_stmt = last_stmt (region->entry);
+  new_bb = region->entry;
+  int kind = gimple_omp_target_kind (entry_stmt);
+  if (kind == GF_OMP_TARGET_KIND_REGION)
     {
-      location_t saved_location;
+      child_fn = gimple_omp_target_child_fn (entry_stmt);
+      child_cfun = DECL_STRUCT_FUNCTION (child_fn);
+    }
 
-      /* First, determine whether this is a combined parallel+workshare
-       	 region.  */
-      if (region->type == GIMPLE_OMP_PARALLEL)
-	determine_parallel_type (region);
+  entry_bb = region->entry;
+  exit_bb = region->exit;
 
-      if (region->inner)
-	expand_omp (region->inner);
+  if (kind == GF_OMP_TARGET_KIND_REGION)
+    {
+      unsigned srcidx, dstidx, num;
 
-      saved_location = input_location;
-      if (gimple_has_location (last_stmt (region->entry)))
-	input_location = gimple_location (last_stmt (region->entry));
+      /* If the target region needs data sent from the parent
+	 function, then the very first statement (except possible
+	 tree profile counter updates) of the parallel body
+	 is a copy assignment .OMP_DATA_I = &.OMP_DATA_O.  Since
+	 &.OMP_DATA_O is passed as an argument to the child function,
+	 we need to replace it with the argument as seen by the child
+	 function.
 
-      switch (region->type)
+	 In most cases, this will end up being the identity assignment
+	 .OMP_DATA_I = .OMP_DATA_I.  However, if the parallel body had
+	 a function call that has been inlined, the original PARM_DECL
+	 .OMP_DATA_I may have been converted into a different local
+	 variable.  In which case, we need to keep the assignment.  */
+      if (gimple_omp_target_data_arg (entry_stmt))
 	{
-	case GIMPLE_OMP_PARALLEL:
-	case GIMPLE_OMP_TASK:
-	  expand_omp_taskreg (region);
-	  break;
+	  basic_block entry_succ_bb = single_succ (entry_bb);
+	  gimple_stmt_iterator gsi;
+	  tree arg;
+	  gimple tgtcopy_stmt = NULL;
+	  tree sender
+	    = TREE_VEC_ELT (gimple_omp_target_data_arg (entry_stmt), 0);
 
-	case GIMPLE_OMP_FOR:
-	  expand_omp_for (region);
-	  break;
+	  for (gsi = gsi_start_bb (entry_succ_bb); ; gsi_next (&gsi))
+	    {
+	      gcc_assert (!gsi_end_p (gsi));
+	      stmt = gsi_stmt (gsi);
+	      if (gimple_code (stmt) != GIMPLE_ASSIGN)
+		continue;
+
+	      if (gimple_num_ops (stmt) == 2)
+		{
+		  tree arg = gimple_assign_rhs1 (stmt);
+
+		  /* We're ignoring the subcode because we're
+		     effectively doing a STRIP_NOPS.  */
+
+		  if (TREE_CODE (arg) == ADDR_EXPR
+		      && TREE_OPERAND (arg, 0) == sender)
+		    {
+		      tgtcopy_stmt = stmt;
+		      break;
+		    }
+		}
+	    }
+
+	  gcc_assert (tgtcopy_stmt != NULL);
+	  arg = DECL_ARGUMENTS (child_fn);
+
+	  gcc_assert (gimple_assign_lhs (tgtcopy_stmt) == arg);
+	  gsi_remove (&gsi, true);
+	}
+
+      /* Declare local variables needed in CHILD_CFUN.  */
+      block = DECL_INITIAL (child_fn);
+      BLOCK_VARS (block) = vec2chain (child_cfun->local_decls);
+      /* The gimplifier could record temporaries in target block
+	 rather than in containing function's local_decls chain,
+	 which would mean cgraph missed finalizing them.  Do it now.  */
+      for (t = BLOCK_VARS (block); t; t = DECL_CHAIN (t))
+	if (TREE_CODE (t) == VAR_DECL
+	    && TREE_STATIC (t)
+	    && !DECL_EXTERNAL (t))
+	  varpool_finalize_decl (t);
+      DECL_SAVED_TREE (child_fn) = NULL;
+      /* We'll create a CFG for child_fn, so no gimple body is needed.  */
+      gimple_set_body (child_fn, NULL);
+      TREE_USED (block) = 1;
+
+      /* Reset DECL_CONTEXT on function arguments.  */
+      for (t = DECL_ARGUMENTS (child_fn); t; t = DECL_CHAIN (t))
+	DECL_CONTEXT (t) = child_fn;
+
+      /* Split ENTRY_BB at GIMPLE_OMP_TARGET,
+	 so that it can be moved to the child function.  */
+      gsi = gsi_last_bb (entry_bb);
+      stmt = gsi_stmt (gsi);
+      gcc_assert (stmt && gimple_code (stmt) == GIMPLE_OMP_TARGET
+		  && gimple_omp_target_kind (stmt)
+		     == GF_OMP_TARGET_KIND_REGION);
+      gsi_remove (&gsi, true);
+      e = split_block (entry_bb, stmt);
+      entry_bb = e->dest;
+      single_succ_edge (entry_bb)->flags = EDGE_FALLTHRU;
+
+      /* Convert GIMPLE_OMP_RETURN into a RETURN_EXPR.  */
+      if (exit_bb)
+	{
+	  gsi = gsi_last_bb (exit_bb);
+	  gcc_assert (!gsi_end_p (gsi)
+		      && gimple_code (gsi_stmt (gsi)) == GIMPLE_OMP_RETURN);
+	  stmt = gimple_build_return (NULL);
+	  gsi_insert_after (&gsi, stmt, GSI_SAME_STMT);
+	  gsi_remove (&gsi, true);
+	}
+
+      /* Move the target region into CHILD_CFUN.  */
+
+      block = gimple_block (entry_stmt);
+
+      new_bb = move_sese_region_to_fn (child_cfun, entry_bb, exit_bb, block);
+      if (exit_bb)
+	single_succ_edge (new_bb)->flags = EDGE_FALLTHRU;
+      /* When the OMP expansion process cannot guarantee an up-to-date
+	 loop tree arrange for the child function to fixup loops.  */
+      if (loops_state_satisfies_p (LOOPS_NEED_FIXUP))
+	child_cfun->x_current_loops->state |= LOOPS_NEED_FIXUP;
+
+      /* Remove non-local VAR_DECLs from child_cfun->local_decls list.  */
+      num = vec_safe_length (child_cfun->local_decls);
+      for (srcidx = 0, dstidx = 0; srcidx < num; srcidx++)
+	{
+	  t = (*child_cfun->local_decls)[srcidx];
+	  if (DECL_CONTEXT (t) == cfun->decl)
+	    continue;
+	  if (srcidx != dstidx)
+	    (*child_cfun->local_decls)[dstidx] = t;
+	  dstidx++;
+	}
+      if (dstidx != num)
+	vec_safe_truncate (child_cfun->local_decls, dstidx);
+
+      /* Inform the callgraph about the new function.  */
+      DECL_STRUCT_FUNCTION (child_fn)->curr_properties = cfun->curr_properties;
+      cgraph_add_new_function (child_fn, true);
+
+      /* Fix the callgraph edges for child_cfun.  Those for cfun will be
+	 fixed in a following pass.  */
+      push_cfun (child_cfun);
+      rebuild_cgraph_edges ();
+
+      /* Some EH regions might become dead, see PR34608.  If
+	 pass_cleanup_cfg isn't the first pass to happen with the
+	 new child, these dead EH edges might cause problems.
+	 Clean them up now.  */
+      if (flag_exceptions)
+	{
+	  basic_block bb;
+	  bool changed = false;
+
+	  FOR_EACH_BB (bb)
+	    changed |= gimple_purge_dead_eh_edges (bb);
+	  if (changed)
+	    cleanup_tree_cfg ();
+	}
+      pop_cfun ();
+    }
+
+  /* Emit a library call to launch the target region, or do data
+     transfers.  */
+  tree t1, t2, t3, t4, device, cond, c, clauses;
+  enum built_in_function start_ix;
+  location_t clause_loc;
+
+  clauses = gimple_omp_target_clauses (entry_stmt);
+
+  if (kind == GF_OMP_TARGET_KIND_REGION)
+    start_ix = BUILT_IN_GOMP_TARGET;
+  else if (kind == GF_OMP_TARGET_KIND_DATA)
+    start_ix = BUILT_IN_GOMP_TARGET_DATA;
+  else
+    start_ix = BUILT_IN_GOMP_TARGET_UPDATE;
+
+  /* By default, the value of DEVICE is -1 (let runtime library choose)
+     and there is no conditional.  */
+  cond = NULL_TREE;
+  device = build_int_cst (integer_type_node, -1);
+
+  c = find_omp_clause (clauses, OMP_CLAUSE_IF);
+  if (c)
+    cond = OMP_CLAUSE_IF_EXPR (c);
+
+  c = find_omp_clause (clauses, OMP_CLAUSE_DEVICE);
+  if (c)
+    {
+      device = OMP_CLAUSE_DEVICE_ID (c);
+      clause_loc = OMP_CLAUSE_LOCATION (c);
+    }
+  else
+    clause_loc = gimple_location (entry_stmt);
+
+  /* Ensure 'device' is of the correct type.  */
+  device = fold_convert_loc (clause_loc, integer_type_node, device);
+
+  /* If we found the clause 'if (cond)', build
+     (cond ? device : -2).  */
+  if (cond)
+    {
+      cond = gimple_boolify (cond);
+
+      basic_block cond_bb, then_bb, else_bb;
+      edge e;
+      tree tmp_var;
+
+      tmp_var = create_tmp_var (TREE_TYPE (device), NULL);
+      if (kind != GF_OMP_TARGET_KIND_REGION)
+	{
+	  gsi = gsi_last_bb (new_bb);
+	  gsi_prev (&gsi);
+	  e = split_block (new_bb, gsi_stmt (gsi));
+	}
+      else
+	e = split_block (new_bb, NULL);
+      cond_bb = e->src;
+      new_bb = e->dest;
+      remove_edge (e);
+
+      then_bb = create_empty_bb (cond_bb);
+      else_bb = create_empty_bb (then_bb);
+      set_immediate_dominator (CDI_DOMINATORS, then_bb, cond_bb);
+      set_immediate_dominator (CDI_DOMINATORS, else_bb, cond_bb);
+
+      stmt = gimple_build_cond_empty (cond);
+      gsi = gsi_last_bb (cond_bb);
+      gsi_insert_after (&gsi, stmt, GSI_CONTINUE_LINKING);
+
+      gsi = gsi_start_bb (then_bb);
+      stmt = gimple_build_assign (tmp_var, device);
+      gsi_insert_after (&gsi, stmt, GSI_CONTINUE_LINKING);
+
+      gsi = gsi_start_bb (else_bb);
+      stmt = gimple_build_assign (tmp_var,
+				  build_int_cst (integer_type_node, -2));
+      gsi_insert_after (&gsi, stmt, GSI_CONTINUE_LINKING);
+
+      make_edge (cond_bb, then_bb, EDGE_TRUE_VALUE);
+      make_edge (cond_bb, else_bb, EDGE_FALSE_VALUE);
+      if (current_loops)
+	{
+	  add_bb_to_loop (then_bb, cond_bb->loop_father);
+	  add_bb_to_loop (else_bb, cond_bb->loop_father);
+	}
+      make_edge (then_bb, new_bb, EDGE_FALLTHRU);
+      make_edge (else_bb, new_bb, EDGE_FALLTHRU);
+
+      device = tmp_var;
+    }
+
+  gsi = gsi_last_bb (new_bb);
+  t = gimple_omp_target_data_arg (entry_stmt);
+  if (t == NULL)
+    {
+      t1 = size_zero_node;
+      t2 = build_zero_cst (ptr_type_node);
+      t3 = t2;
+      t4 = t2;
+    }
+  else
+    {
+      t1 = TYPE_MAX_VALUE (TYPE_DOMAIN (TREE_TYPE (TREE_VEC_ELT (t, 1))));
+      t1 = size_binop (PLUS_EXPR, t1, size_int (1));
+      t2 = build_fold_addr_expr (TREE_VEC_ELT (t, 0));
+      t3 = build_fold_addr_expr (TREE_VEC_ELT (t, 1));
+      t4 = build_fold_addr_expr (TREE_VEC_ELT (t, 2));
+    }
+
+  gimple g;
+  /* FIXME: This will be address of
+     extern char __OPENMP_TARGET__[] __attribute__((visibility ("hidden")))
+     symbol, as soon as the linker plugin is able to create it for us.  */
+  tree openmp_target = build_zero_cst (ptr_type_node);
+  if (kind == GF_OMP_TARGET_KIND_REGION)
+    {
+      tree fnaddr = build_fold_addr_expr (child_fn);
+      g = gimple_build_call (builtin_decl_explicit (start_ix), 7,
+			     device, fnaddr, openmp_target, t1, t2, t3, t4);
+    }
+  else
+    g = gimple_build_call (builtin_decl_explicit (start_ix), 6,
+			   device, openmp_target, t1, t2, t3, t4);
+  gimple_set_location (g, gimple_location (entry_stmt));
+  gsi_insert_before (&gsi, g, GSI_SAME_STMT);
+  if (kind != GF_OMP_TARGET_KIND_REGION)
+    {
+      g = gsi_stmt (gsi);
+      gcc_assert (g && gimple_code (g) == GIMPLE_OMP_TARGET);
+      gsi_remove (&gsi, true);
+    }
+  if (kind == GF_OMP_TARGET_KIND_DATA && region->exit)
+    {
+      gsi = gsi_last_bb (region->exit);
+      g = gsi_stmt (gsi);
+      gcc_assert (g && gimple_code (g) == GIMPLE_OMP_RETURN);
+      gsi_remove (&gsi, true);
+    }
+}
+
+
+/* Expand the parallel region tree rooted at REGION.  Expansion
+   proceeds in depth-first order.  Innermost regions are expanded
+   first.  This way, parallel regions that require a new function to
+   be created (e.g., GIMPLE_OMP_PARALLEL) can be expanded without having any
+   internal dependencies in their body.  */
+
+static void
+expand_omp (struct omp_region *region)
+{
+  while (region)
+    {
+      location_t saved_location;
+      gimple inner_stmt = NULL;
+
+      /* First, determine whether this is a combined parallel+workshare
+       	 region.  */
+      if (region->type == GIMPLE_OMP_PARALLEL)
+	determine_parallel_type (region);
+
+      if (region->type == GIMPLE_OMP_FOR
+	  && gimple_omp_for_combined_p (last_stmt (region->entry)))
+	inner_stmt = last_stmt (region->inner->entry);
+
+      if (region->inner)
+	expand_omp (region->inner);
+
+      saved_location = input_location;
+      if (gimple_has_location (last_stmt (region->entry)))
+	input_location = gimple_location (last_stmt (region->entry));
+
+      switch (region->type)
+	{
+	case GIMPLE_OMP_PARALLEL:
+	case GIMPLE_OMP_TASK:
+	  expand_omp_taskreg (region);
+	  break;
+
+	case GIMPLE_OMP_FOR:
+	  expand_omp_for (region, inner_stmt);
+	  break;
 
 	case GIMPLE_OMP_SECTIONS:
 	  expand_omp_sections (region);
@@ -6672,8 +8029,10 @@ expand_omp (struct omp_region *region)
 	  break;
 
 	case GIMPLE_OMP_MASTER:
+	case GIMPLE_OMP_TASKGROUP:
 	case GIMPLE_OMP_ORDERED:
 	case GIMPLE_OMP_CRITICAL:
+	case GIMPLE_OMP_TEAMS:
 	  expand_omp_synch (region);
 	  break;
 
@@ -6681,6 +8040,10 @@ expand_omp (struct omp_region *region)
 	  expand_omp_atomic (region);
 	  break;
 
+	case GIMPLE_OMP_TARGET:
+	  expand_omp_target (region);
+	  break;
+
 	default:
 	  gcc_unreachable ();
 	}
@@ -6745,6 +8108,9 @@ build_omp_regions_1 (basic_block bb, str
 	     GIMPLE_OMP_SECTIONS, and we do nothing for it.  */
 	  ;
 	}
+      else if (code == GIMPLE_OMP_TARGET
+	       && gimple_omp_target_kind (stmt) == GF_OMP_TARGET_KIND_UPDATE)
+	new_omp_region (bb, code, parent);
       else
 	{
 	  /* Otherwise, this directive becomes the parent for a new
@@ -6880,6 +8246,32 @@ make_pass_expand_omp (gcc::context *ctxt
 
 /* Routines to lower OpenMP directives into OMP-GIMPLE.  */
 
+/* If ctx is a worksharing context inside of a cancellable parallel
+   region and it isn't nowait, add lhs to its GIMPLE_OMP_RETURN
+   and conditional branch to parallel's cancel_label to handle
+   cancellation in the implicit barrier.  */
+
+static void
+maybe_add_implicit_barrier_cancel (omp_context *ctx, gimple_seq *body)
+{
+  gimple omp_return = gimple_seq_last_stmt (*body);
+  gcc_assert (gimple_code (omp_return) == GIMPLE_OMP_RETURN);
+  if (gimple_omp_return_nowait_p (omp_return))
+    return;
+  if (ctx->outer
+      && gimple_code (ctx->outer->stmt) == GIMPLE_OMP_PARALLEL
+      && ctx->outer->cancellable)
+    {
+      tree lhs = create_tmp_var (boolean_type_node, NULL);
+      gimple_omp_return_set_lhs (omp_return, lhs);
+      tree fallthru_label = create_artificial_label (UNKNOWN_LOCATION);
+      gimple g = gimple_build_cond (NE_EXPR, lhs, boolean_false_node,
+				    ctx->outer->cancel_label, fallthru_label);
+      gimple_seq_add_stmt (body, g);
+      gimple_seq_add_stmt (body, gimple_build_label (fallthru_label));
+    }
+}
+
 /* Lower the OpenMP sections directive in the current statement in GSI_P.
    CTX is the enclosing OMP context for the current statement.  */
 
@@ -6899,7 +8291,7 @@ lower_omp_sections (gimple_stmt_iterator
   dlist = NULL;
   ilist = NULL;
   lower_rec_input_clauses (gimple_omp_sections_clauses (stmt),
-      			   &ilist, &dlist, ctx);
+      			   &ilist, &dlist, ctx, NULL);
 
   new_body = gimple_omp_body (stmt);
   gimple_omp_set_body (stmt, NULL);
@@ -6959,6 +8351,8 @@ lower_omp_sections (gimple_stmt_iterator
   gimple_seq_add_stmt (&new_body, t);
 
   gimple_seq_add_seq (&new_body, olist);
+  if (ctx->cancellable)
+    gimple_seq_add_stmt (&new_body, gimple_build_label (ctx->cancel_label));
   gimple_seq_add_seq (&new_body, dlist);
 
   new_body = maybe_catch_exception (new_body);
@@ -6967,6 +8361,7 @@ lower_omp_sections (gimple_stmt_iterator
         (!!find_omp_clause (gimple_omp_sections_clauses (stmt),
 			    OMP_CLAUSE_NOWAIT));
   gimple_seq_add_stmt (&new_body, t);
+  maybe_add_implicit_barrier_cancel (ctx, &new_body);
 
   gimple_bind_set_body (new_stmt, new_body);
 }
@@ -7096,7 +8491,7 @@ lower_omp_single (gimple_stmt_iterator *
 {
   tree block;
   gimple t, bind, single_stmt = gsi_stmt (*gsi_p);
-  gimple_seq bind_body, dlist;
+  gimple_seq bind_body, bind_body_tail = NULL, dlist;
   struct gimplify_ctx gctx;
 
   push_gimplify_context (&gctx);
@@ -7107,7 +8502,7 @@ lower_omp_single (gimple_stmt_iterator *
   bind_body = NULL;
   dlist = NULL;
   lower_rec_input_clauses (gimple_omp_single_clauses (single_stmt),
-			   &bind_body, &dlist, ctx);
+			   &bind_body, &dlist, ctx, NULL);
   lower_omp (gimple_omp_body_ptr (single_stmt), ctx);
 
   gimple_seq_add_stmt (&bind_body, single_stmt);
@@ -7126,7 +8521,17 @@ lower_omp_single (gimple_stmt_iterator *
   t = gimple_build_omp_return
         (!!find_omp_clause (gimple_omp_single_clauses (single_stmt),
 			    OMP_CLAUSE_NOWAIT));
-  gimple_seq_add_stmt (&bind_body, t);
+  gimple_seq_add_stmt (&bind_body_tail, t);
+  maybe_add_implicit_barrier_cancel (ctx, &bind_body_tail);
+  if (ctx->record_type)
+    {
+      gimple_stmt_iterator gsi = gsi_start (bind_body_tail);
+      tree clobber = build_constructor (ctx->record_type, NULL);
+      TREE_THIS_VOLATILE (clobber) = 1;
+      gsi_insert_after (&gsi, gimple_build_assign (ctx->sender_decl,
+						   clobber), GSI_SAME_STMT);
+    }
+  gimple_seq_add_seq (&bind_body, bind_body_tail);
   gimple_bind_set_body (bind, bind_body);
 
   pop_gimplify_context (bind);
@@ -7180,6 +8585,33 @@ lower_omp_master (gimple_stmt_iterator *
 }
 
 
+/* Expand code for an OpenMP taskgroup directive.  */
+
+static void
+lower_omp_taskgroup (gimple_stmt_iterator *gsi_p, omp_context *ctx)
+{
+  gimple stmt = gsi_stmt (*gsi_p), bind, x;
+  tree block = make_node (BLOCK);
+
+  bind = gimple_build_bind (NULL, NULL, block);
+  gsi_replace (gsi_p, bind, true);
+  gimple_bind_add_stmt (bind, stmt);
+
+  x = gimple_build_call (builtin_decl_explicit (BUILT_IN_GOMP_TASKGROUP_START),
+			 0);
+  gimple_bind_add_stmt (bind, x);
+
+  lower_omp (gimple_omp_body_ptr (stmt), ctx);
+  gimple_bind_add_seq (bind, gimple_omp_body (stmt));
+  gimple_omp_set_body (stmt, NULL);
+
+  gimple_bind_add_stmt (bind, gimple_build_omp_return (true));
+
+  gimple_bind_append_vars (bind, ctx->block_vars);
+  BLOCK_VARS (block) = ctx->block_vars;
+}
+
+
 /* Expand code for an OpenMP ordered directive.  */
 
 static void
@@ -7372,7 +8804,7 @@ static void
 lower_omp_for (gimple_stmt_iterator *gsi_p, omp_context *ctx)
 {
   tree *rhs_p, block;
-  struct omp_for_data fd;
+  struct omp_for_data fd, *fdp = NULL;
   gimple stmt = gsi_stmt (*gsi_p), new_stmt;
   gimple_seq omp_for_body, body, dlist;
   size_t i;
@@ -7399,10 +8831,50 @@ lower_omp_for (gimple_stmt_iterator *gsi
       gimple_bind_append_vars (new_stmt, vars);
     }
 
+  if (gimple_omp_for_combined_into_p (stmt))
+    {
+      extract_omp_for_data (stmt, &fd, NULL);
+      fdp = &fd;
+
+      /* We need two temporaries with fd.loop.v type (istart/iend)
+	 and then (fd.collapse - 1) temporaries with the same
+	 type for count2 ... countN-1 vars if not constant.  */
+      size_t count = 2;
+      tree type = fd.iter_type;
+      if (fd.collapse > 1
+	  && TREE_CODE (fd.loop.n2) != INTEGER_CST)
+	count += fd.collapse - 1;
+      bool parallel_for = gimple_omp_for_kind (stmt) == GF_OMP_FOR_KIND_FOR;
+      tree outerc = NULL, *pc = gimple_omp_for_clauses_ptr (stmt);
+      tree clauses = *pc;
+      if (parallel_for)
+	outerc
+	  = find_omp_clause (gimple_omp_parallel_clauses (ctx->outer->stmt),
+			     OMP_CLAUSE__LOOPTEMP_);
+      for (i = 0; i < count; i++)
+	{
+	  tree temp;
+	  if (parallel_for)
+	    {
+	      gcc_assert (outerc);
+	      temp = lookup_decl (OMP_CLAUSE_DECL (outerc), ctx->outer);
+	      outerc = find_omp_clause (OMP_CLAUSE_CHAIN (outerc),
+					OMP_CLAUSE__LOOPTEMP_);
+	    }
+	  else
+	    temp = create_tmp_var (type, NULL);
+	  *pc = build_omp_clause (UNKNOWN_LOCATION, OMP_CLAUSE__LOOPTEMP_);
+	  OMP_CLAUSE_DECL (*pc) = temp;
+	  pc = &OMP_CLAUSE_CHAIN (*pc);
+	}
+      *pc = clauses;
+    }
+
   /* The pre-body and input clauses go before the lowered GIMPLE_OMP_FOR.  */
   dlist = NULL;
   body = NULL;
-  lower_rec_input_clauses (gimple_omp_for_clauses (stmt), &body, &dlist, ctx);
+  lower_rec_input_clauses (gimple_omp_for_clauses (stmt), &body, &dlist, ctx,
+			   fdp);
   gimple_seq_add_seq (&body, gimple_omp_for_pre_body (stmt));
 
   lower_omp (gimple_omp_body_ptr (stmt), ctx);
@@ -7442,13 +8914,17 @@ lower_omp_for (gimple_stmt_iterator *gsi
 
   /* After the loop, add exit clauses.  */
   lower_reduction_clauses (gimple_omp_for_clauses (stmt), &body, ctx);
+
+  if (ctx->cancellable)
+    gimple_seq_add_stmt (&body, gimple_build_label (ctx->cancel_label));
+
   gimple_seq_add_seq (&body, dlist);
 
   body = maybe_catch_exception (body);
 
   /* Region exit marker goes at the end of the loop body.  */
   gimple_seq_add_stmt (&body, gimple_build_omp_return (fd.have_nowait));
-
+  maybe_add_implicit_barrier_cancel (ctx, &body);
   pop_gimplify_context (new_stmt);
 
   gimple_bind_append_vars (new_stmt, ctx->block_vars);
@@ -7769,6 +9245,68 @@ create_task_copyfn (gimple task_stmt, om
   pop_cfun ();
 }
 
+static void
+lower_depend_clauses (gimple stmt, gimple_seq *iseq, gimple_seq *oseq)
+{
+  tree c, clauses;
+  gimple g;
+  size_t n_in = 0, n_out = 0, idx = 2, i;
+
+  clauses = find_omp_clause (gimple_omp_task_clauses (stmt),
+			     OMP_CLAUSE_DEPEND);
+  gcc_assert (clauses);
+  for (c = clauses; c; c = OMP_CLAUSE_CHAIN (c))
+    if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_DEPEND)
+      switch (OMP_CLAUSE_DEPEND_KIND (c))
+	{
+	case OMP_CLAUSE_DEPEND_IN:
+	  n_in++;
+	  break;
+	case OMP_CLAUSE_DEPEND_OUT:
+	case OMP_CLAUSE_DEPEND_INOUT:
+	  n_out++;
+	  break;
+	default:
+	  gcc_unreachable ();
+	}
+  tree type = build_array_type_nelts (ptr_type_node, n_in + n_out + 2);
+  tree array = create_tmp_var (type, NULL);
+  tree r = build4 (ARRAY_REF, ptr_type_node, array, size_int (0), NULL_TREE,
+		   NULL_TREE);
+  g = gimple_build_assign (r, build_int_cst (ptr_type_node, n_in + n_out));
+  gimple_seq_add_stmt (iseq, g);
+  r = build4 (ARRAY_REF, ptr_type_node, array, size_int (1), NULL_TREE,
+	      NULL_TREE);
+  g = gimple_build_assign (r, build_int_cst (ptr_type_node, n_out));
+  gimple_seq_add_stmt (iseq, g);
+  for (i = 0; i < 2; i++)
+    {
+      if ((i ? n_in : n_out) == 0)
+	continue;
+      for (c = clauses; c; c = OMP_CLAUSE_CHAIN (c))
+	if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_DEPEND
+	    && ((OMP_CLAUSE_DEPEND_KIND (c) != OMP_CLAUSE_DEPEND_IN) ^ i))
+	  {
+	    tree t = OMP_CLAUSE_DECL (c);
+	    t = fold_convert (ptr_type_node, t);
+	    gimplify_expr (&t, iseq, NULL, is_gimple_val, fb_rvalue);
+	    r = build4 (ARRAY_REF, ptr_type_node, array, size_int (idx++),
+			NULL_TREE, NULL_TREE);
+	    g = gimple_build_assign (r, t);
+	    gimple_seq_add_stmt (iseq, g);
+	  }
+    }
+  tree *p = gimple_omp_task_clauses_ptr (stmt);
+  c = build_omp_clause (UNKNOWN_LOCATION, OMP_CLAUSE_DEPEND);
+  OMP_CLAUSE_DECL (c) = build_fold_addr_expr (array);
+  OMP_CLAUSE_CHAIN (c) = *p;
+  *p = c;
+  tree clobber = build_constructor (type, NULL);
+  TREE_THIS_VOLATILE (clobber) = 1;
+  g = gimple_build_assign (array, clobber);
+  gimple_seq_add_stmt (oseq, g);
+}
+
 /* Lower the OpenMP parallel or task directive in the current statement
    in GSI_P.  CTX holds context information for the directive.  */
 
@@ -7778,9 +9316,9 @@ lower_omp_taskreg (gimple_stmt_iterator
   tree clauses;
   tree child_fn, t;
   gimple stmt = gsi_stmt (*gsi_p);
-  gimple par_bind, bind;
-  gimple_seq par_body, olist, ilist, par_olist, par_ilist, new_body;
-  struct gimplify_ctx gctx;
+  gimple par_bind, bind, dep_bind = NULL;
+  gimple_seq par_body, olist, ilist, par_olist, par_rlist, par_ilist, new_body;
+  struct gimplify_ctx gctx, dep_gctx;
   location_t loc = gimple_location (stmt);
 
   clauses = gimple_omp_taskreg_clauses (stmt);
@@ -7800,6 +9338,16 @@ lower_omp_taskreg (gimple_stmt_iterator
       if (ws_num == 1)
 	gimple_omp_parallel_set_combined_p (stmt, true);
     }
+  gimple_seq dep_ilist = NULL;
+  gimple_seq dep_olist = NULL;
+  if (gimple_code (stmt) == GIMPLE_OMP_TASK
+      && find_omp_clause (clauses, OMP_CLAUSE_DEPEND))
+    {
+      push_gimplify_context (&dep_gctx);
+      dep_bind = gimple_build_bind (NULL, NULL, make_node (BLOCK));
+      lower_depend_clauses (stmt, &dep_ilist, &dep_olist);
+    }
+
   if (ctx->srecord_type)
     create_task_copyfn (stmt, ctx);
 
@@ -7807,10 +9355,11 @@ lower_omp_taskreg (gimple_stmt_iterator
 
   par_olist = NULL;
   par_ilist = NULL;
-  lower_rec_input_clauses (clauses, &par_ilist, &par_olist, ctx);
+  par_rlist = NULL;
+  lower_rec_input_clauses (clauses, &par_ilist, &par_olist, ctx, NULL);
   lower_omp (&par_body, ctx);
   if (gimple_code (stmt) == GIMPLE_OMP_PARALLEL)
-    lower_reduction_clauses (clauses, &par_olist, ctx);
+    lower_reduction_clauses (clauses, &par_rlist, ctx);
 
   /* Declare all the variables created by mapping and the variables
      declared in the scope of the parallel body.  */
@@ -7832,6 +9381,14 @@ lower_omp_taskreg (gimple_stmt_iterator
   lower_send_clauses (clauses, &ilist, &olist, ctx);
   lower_send_shared_vars (&ilist, &olist, ctx);
 
+  if (ctx->record_type)
+    {
+      tree clobber = build_constructor (TREE_TYPE (ctx->sender_decl), NULL);
+      TREE_THIS_VOLATILE (clobber) = 1;
+      gimple_seq_add_stmt (&olist, gimple_build_assign (ctx->sender_decl,
+							clobber));
+    }
+
   /* Once all the expansions are done, sequence all the different
      fragments inside gimple_omp_body.  */
 
@@ -7848,12 +9405,329 @@ lower_omp_taskreg (gimple_stmt_iterator
 
   gimple_seq_add_seq (&new_body, par_ilist);
   gimple_seq_add_seq (&new_body, par_body);
+  gimple_seq_add_seq (&new_body, par_rlist);
+  if (ctx->cancellable)
+    gimple_seq_add_stmt (&new_body, gimple_build_label (ctx->cancel_label));
   gimple_seq_add_seq (&new_body, par_olist);
   new_body = maybe_catch_exception (new_body);
   gimple_seq_add_stmt (&new_body, gimple_build_omp_return (false));
   gimple_omp_set_body (stmt, new_body);
 
   bind = gimple_build_bind (NULL, NULL, gimple_bind_block (par_bind));
+  gsi_replace (gsi_p, dep_bind ? dep_bind : bind, true);
+  gimple_bind_add_seq (bind, ilist);
+  gimple_bind_add_stmt (bind, stmt);
+  gimple_bind_add_seq (bind, olist);
+
+  pop_gimplify_context (NULL);
+
+  if (dep_bind)
+    {
+      gimple_bind_add_seq (dep_bind, dep_ilist);
+      gimple_bind_add_stmt (dep_bind, bind);
+      gimple_bind_add_seq (dep_bind, dep_olist);
+      pop_gimplify_context (dep_bind);
+    }
+}
+
+/* Lower the OpenMP target directive in the current statement
+   in GSI_P.  CTX holds context information for the directive.  */
+
+static void
+lower_omp_target (gimple_stmt_iterator *gsi_p, omp_context *ctx)
+{
+  tree clauses;
+  tree child_fn, t, c;
+  gimple stmt = gsi_stmt (*gsi_p);
+  gimple tgt_bind = NULL, bind;
+  gimple_seq tgt_body = NULL, olist, ilist, new_body;
+  struct gimplify_ctx gctx;
+  location_t loc = gimple_location (stmt);
+  int kind = gimple_omp_target_kind (stmt);
+  unsigned int map_cnt = 0;
+
+  clauses = gimple_omp_target_clauses (stmt);
+  if (kind == GF_OMP_TARGET_KIND_REGION)
+    {
+      tgt_bind = gimple_seq_first_stmt (gimple_omp_body (stmt));
+      tgt_body = gimple_bind_body (tgt_bind);
+    }
+  else if (kind == GF_OMP_TARGET_KIND_DATA)
+    tgt_body = gimple_omp_body (stmt);
+  child_fn = ctx->cb.dst_fn;
+
+  push_gimplify_context (&gctx);
+
+  for (c = clauses; c ; c = OMP_CLAUSE_CHAIN (c))
+    switch (OMP_CLAUSE_CODE (c))
+      {
+	tree var, x;
+
+      default:
+	break;
+      case OMP_CLAUSE_MAP:
+      case OMP_CLAUSE_TO:
+      case OMP_CLAUSE_FROM:
+	var = OMP_CLAUSE_DECL (c);
+	if (!DECL_P (var))
+	  {
+	    if (OMP_CLAUSE_CODE (c) != OMP_CLAUSE_MAP
+		|| !OMP_CLAUSE_MAP_ZERO_BIAS_ARRAY_SECTION (c))
+	      map_cnt++;
+	    continue;
+	  }
+
+	if (DECL_SIZE (var)
+	    && TREE_CODE (DECL_SIZE (var)) != INTEGER_CST)
+	  {
+	    tree var2 = DECL_VALUE_EXPR (var);
+	    gcc_assert (TREE_CODE (var2) == INDIRECT_REF);
+	    var2 = TREE_OPERAND (var2, 0);
+	    gcc_assert (DECL_P (var2));
+	    var = var2;
+	  }
+
+	if (!maybe_lookup_field (var, ctx))
+	  continue;
+
+	if (kind == GF_OMP_TARGET_KIND_REGION)
+	  {
+	    x = build_receiver_ref (var, true, ctx);
+	    tree new_var = lookup_decl (var, ctx);
+	    if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_MAP
+		&& OMP_CLAUSE_MAP_KIND (c) == OMP_CLAUSE_MAP_POINTER
+		&& !OMP_CLAUSE_MAP_ZERO_BIAS_ARRAY_SECTION (c)
+		&& TREE_CODE (TREE_TYPE (var)) == ARRAY_TYPE)
+	      x = build_simple_mem_ref (x);
+	    SET_DECL_VALUE_EXPR (new_var, x);
+	    DECL_HAS_VALUE_EXPR_P (new_var) = 1;
+	  }
+	map_cnt++;
+      }
+
+  if (kind == GF_OMP_TARGET_KIND_REGION)
+    {
+      target_nesting_level++;
+      lower_omp (&tgt_body, ctx);
+      target_nesting_level--;
+    }
+  else if (kind == GF_OMP_TARGET_KIND_DATA)
+    lower_omp (&tgt_body, ctx);
+
+  if (kind == GF_OMP_TARGET_KIND_REGION)
+    {
+      /* Declare all the variables created by mapping and the variables
+	 declared in the scope of the target body.  */
+      record_vars_into (ctx->block_vars, child_fn);
+      record_vars_into (gimple_bind_vars (tgt_bind), child_fn);
+    }
+
+  olist = NULL;
+  ilist = NULL;
+  if (ctx->record_type)
+    {
+      ctx->sender_decl
+	= create_tmp_var (ctx->record_type, ".omp_data_arr");
+      DECL_NAMELESS (ctx->sender_decl) = 1;
+      TREE_ADDRESSABLE (ctx->sender_decl) = 1;
+      t = make_tree_vec (3);
+      TREE_VEC_ELT (t, 0) = ctx->sender_decl;
+      TREE_VEC_ELT (t, 1)
+	= create_tmp_var (build_array_type_nelts (size_type_node, map_cnt),
+			  ".omp_data_sizes");
+      DECL_NAMELESS (TREE_VEC_ELT (t, 1)) = 1;
+      TREE_ADDRESSABLE (TREE_VEC_ELT (t, 1)) = 1;
+      TREE_STATIC (TREE_VEC_ELT (t, 1)) = 1;
+      TREE_VEC_ELT (t, 2)
+	= create_tmp_var (build_array_type_nelts (unsigned_char_type_node,
+						  map_cnt),
+			  ".omp_data_kinds");
+      DECL_NAMELESS (TREE_VEC_ELT (t, 2)) = 1;
+      TREE_ADDRESSABLE (TREE_VEC_ELT (t, 2)) = 1;
+      TREE_STATIC (TREE_VEC_ELT (t, 2)) = 1;
+      gimple_omp_target_set_data_arg (stmt, t);
+
+      vec<constructor_elt, va_gc> *vsize;
+      vec<constructor_elt, va_gc> *vkind;
+      vec_alloc (vsize, map_cnt);
+      vec_alloc (vkind, map_cnt);
+      unsigned int map_idx = 0;
+
+      for (c = clauses; c ; c = OMP_CLAUSE_CHAIN (c))
+	switch (OMP_CLAUSE_CODE (c))
+	  {
+	    tree ovar, nc;
+
+	  default:
+	    break;
+	  case OMP_CLAUSE_MAP:
+	  case OMP_CLAUSE_TO:
+	  case OMP_CLAUSE_FROM:
+	    nc = c;
+	    ovar = OMP_CLAUSE_DECL (c);
+	    if (!DECL_P (ovar))
+	      {
+		if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_MAP
+		    && OMP_CLAUSE_MAP_ZERO_BIAS_ARRAY_SECTION (c))
+		  {
+		    gcc_checking_assert (OMP_CLAUSE_DECL (OMP_CLAUSE_CHAIN (c))
+					 == get_base_address (ovar));
+		    nc = OMP_CLAUSE_CHAIN (c);
+		    ovar = OMP_CLAUSE_DECL (nc);
+		  }
+		else
+		  {
+		    tree x = build_sender_ref (ovar, ctx);
+		    tree v
+		      = build_fold_addr_expr_with_type (ovar, ptr_type_node);
+		    gimplify_assign (x, v, &ilist);
+		    nc = NULL_TREE;
+		  }
+	      }
+	    else
+	      {
+		if (DECL_SIZE (ovar)
+		    && TREE_CODE (DECL_SIZE (ovar)) != INTEGER_CST)
+		  {
+		    tree ovar2 = DECL_VALUE_EXPR (ovar);
+		    gcc_assert (TREE_CODE (ovar2) == INDIRECT_REF);
+		    ovar2 = TREE_OPERAND (ovar2, 0);
+		    gcc_assert (DECL_P (ovar2));
+		    ovar = ovar2;
+		  }
+		if (!maybe_lookup_field (ovar, ctx))
+		  continue;
+	      }
+
+	    if (nc)
+	      {
+		tree var = lookup_decl_in_outer_ctx (ovar, ctx);
+		tree x = build_sender_ref (ovar, ctx);
+		if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_MAP
+		    && OMP_CLAUSE_MAP_KIND (c) == OMP_CLAUSE_MAP_POINTER
+		    && !OMP_CLAUSE_MAP_ZERO_BIAS_ARRAY_SECTION (c)
+		    && TREE_CODE (TREE_TYPE (ovar)) == ARRAY_TYPE)
+		  {
+		    gcc_assert (kind == GF_OMP_TARGET_KIND_REGION);
+		    tree avar
+		      = create_tmp_var (TREE_TYPE (TREE_TYPE (x)), NULL);
+		    mark_addressable (avar);
+		    gimplify_assign (avar, build_fold_addr_expr (var), &ilist);
+		    avar = build_fold_addr_expr (avar);
+		    gimplify_assign (x, avar, &ilist);
+		  }
+		else if (is_gimple_reg (var))
+		  {
+		    gcc_assert (kind == GF_OMP_TARGET_KIND_REGION);
+		    tree avar = create_tmp_var (TREE_TYPE (var), NULL);
+		    mark_addressable (avar);
+		    if (OMP_CLAUSE_MAP_KIND (c) != OMP_CLAUSE_MAP_ALLOC
+			&& OMP_CLAUSE_MAP_KIND (c) != OMP_CLAUSE_MAP_FROM)
+		      gimplify_assign (avar, var, &ilist);
+		    avar = build_fold_addr_expr (avar);
+		    gimplify_assign (x, avar, &ilist);
+		    if ((OMP_CLAUSE_MAP_KIND (c) == OMP_CLAUSE_MAP_FROM
+			 || OMP_CLAUSE_MAP_KIND (c) == OMP_CLAUSE_MAP_TOFROM)
+			&& !TYPE_READONLY (TREE_TYPE (var)))
+		      {
+			x = build_sender_ref (ovar, ctx);
+			x = build_simple_mem_ref (x);
+			gimplify_assign (var, x, &olist);
+		      }
+		  }
+		else
+		  {
+		    var = build_fold_addr_expr (var);
+		    gimplify_assign (x, var, &ilist);
+		  }
+	      }
+	    tree s = OMP_CLAUSE_SIZE (c);
+	    if (s == NULL_TREE)
+	      s = TYPE_SIZE_UNIT (TREE_TYPE (ovar));
+	    s = fold_convert (size_type_node, s);
+	    tree purpose = size_int (map_idx++);
+	    CONSTRUCTOR_APPEND_ELT (vsize, purpose, s);
+	    if (TREE_CODE (s) != INTEGER_CST)
+	      TREE_STATIC (TREE_VEC_ELT (t, 1)) = 0;
+
+	    unsigned char tkind = 0;
+	    switch (OMP_CLAUSE_CODE (c))
+	      {
+	      case OMP_CLAUSE_MAP:
+		tkind = OMP_CLAUSE_MAP_KIND (c);
+		break;
+	      case OMP_CLAUSE_TO:
+		tkind = OMP_CLAUSE_MAP_TO;
+		break;
+	      case OMP_CLAUSE_FROM:
+		tkind = OMP_CLAUSE_MAP_FROM;
+		break;
+	      default:
+		gcc_unreachable ();
+	      }
+	    unsigned int talign = TYPE_ALIGN_UNIT (TREE_TYPE (ovar));
+	    if (DECL_P (ovar) && DECL_ALIGN_UNIT (ovar) > talign)
+	      talign = DECL_ALIGN_UNIT (ovar);
+	    talign = ceil_log2 (talign);
+	    tkind |= talign << 3;
+	    CONSTRUCTOR_APPEND_ELT (vkind, purpose,
+				    build_int_cst (unsigned_char_type_node,
+						   tkind));
+	    if (nc && nc != c)
+	      c = nc;
+	  }
+
+      gcc_assert (map_idx == map_cnt);
+
+      DECL_INITIAL (TREE_VEC_ELT (t, 1))
+	= build_constructor (TREE_TYPE (TREE_VEC_ELT (t, 1)), vsize);
+      DECL_INITIAL (TREE_VEC_ELT (t, 2))
+	= build_constructor (TREE_TYPE (TREE_VEC_ELT (t, 2)), vkind);
+      if (!TREE_STATIC (TREE_VEC_ELT (t, 1)))
+	{
+	  gimple_seq initlist = NULL;
+	  force_gimple_operand (build1 (DECL_EXPR, void_type_node,
+					TREE_VEC_ELT (t, 1)),
+				&initlist, true, NULL_TREE);
+	  gimple_seq_add_seq (&ilist, initlist);
+	}
+
+      tree clobber = build_constructor (ctx->record_type, NULL);
+      TREE_THIS_VOLATILE (clobber) = 1;
+      gimple_seq_add_stmt (&olist, gimple_build_assign (ctx->sender_decl,
+							clobber));
+    }
+
+  /* Once all the expansions are done, sequence all the different
+     fragments inside gimple_omp_body.  */
+
+  new_body = NULL;
+
+  if (ctx->record_type && kind == GF_OMP_TARGET_KIND_REGION)
+    {
+      t = build_fold_addr_expr_loc (loc, ctx->sender_decl);
+      /* fixup_child_record_type might have changed receiver_decl's type.  */
+      t = fold_convert_loc (loc, TREE_TYPE (ctx->receiver_decl), t);
+      gimple_seq_add_stmt (&new_body,
+	  		   gimple_build_assign (ctx->receiver_decl, t));
+    }
+
+  if (kind == GF_OMP_TARGET_KIND_REGION)
+    {
+      gimple_seq_add_seq (&new_body, tgt_body);
+      new_body = maybe_catch_exception (new_body);
+    }
+  else if (kind == GF_OMP_TARGET_KIND_DATA)
+    new_body = tgt_body;
+  if (kind != GF_OMP_TARGET_KIND_UPDATE)
+    {
+      gimple_seq_add_stmt (&new_body, gimple_build_omp_return (false));
+      gimple_omp_set_body (stmt, new_body);
+    }
+
+  bind = gimple_build_bind (NULL, NULL,
+			    tgt_bind ? gimple_bind_block (tgt_bind)
+				     : NULL_TREE);
   gsi_replace (gsi_p, bind, true);
   gimple_bind_add_seq (bind, ilist);
   gimple_bind_add_stmt (bind, stmt);
@@ -7862,6 +9736,72 @@ lower_omp_taskreg (gimple_stmt_iterator
   pop_gimplify_context (NULL);
 }
 
+/* Expand code for an OpenMP teams directive.  */
+
+static void
+lower_omp_teams (gimple_stmt_iterator *gsi_p, omp_context *ctx)
+{
+  gimple teams_stmt = gsi_stmt (*gsi_p);
+  struct gimplify_ctx gctx;
+  push_gimplify_context (&gctx);
+
+  tree block = make_node (BLOCK);
+  gimple bind = gimple_build_bind (NULL, NULL, block);
+  gsi_replace (gsi_p, bind, true);
+  gimple_seq bind_body = NULL;
+  gimple_seq dlist = NULL;
+  gimple_seq olist = NULL;
+
+  tree num_teams = find_omp_clause (gimple_omp_teams_clauses (teams_stmt),
+				    OMP_CLAUSE_NUM_TEAMS);
+  if (num_teams == NULL_TREE)
+    num_teams = build_int_cst (unsigned_type_node, 0);
+  else
+    {
+      num_teams = OMP_CLAUSE_NUM_TEAMS_EXPR (num_teams);
+      num_teams = fold_convert (unsigned_type_node, num_teams);
+      gimplify_expr (&num_teams, &bind_body, NULL, is_gimple_val, fb_rvalue);
+    }
+  tree thread_limit = find_omp_clause (gimple_omp_teams_clauses (teams_stmt),
+				       OMP_CLAUSE_THREAD_LIMIT);
+  if (thread_limit == NULL_TREE)
+    thread_limit = build_int_cst (unsigned_type_node, 0);
+  else
+    {
+      thread_limit = OMP_CLAUSE_THREAD_LIMIT_EXPR (thread_limit);
+      thread_limit = fold_convert (unsigned_type_node, thread_limit);
+      gimplify_expr (&thread_limit, &bind_body, NULL, is_gimple_val,
+		     fb_rvalue);
+    }
+
+  lower_rec_input_clauses (gimple_omp_teams_clauses (teams_stmt),
+			   &bind_body, &dlist, ctx, NULL);
+  lower_omp (gimple_omp_body_ptr (teams_stmt), ctx);
+  lower_reduction_clauses (gimple_omp_teams_clauses (teams_stmt), &olist, ctx);
+  gimple_seq_add_stmt (&bind_body, teams_stmt);
+
+  location_t loc = gimple_location (teams_stmt);
+  tree decl = builtin_decl_explicit (BUILT_IN_GOMP_TEAMS);
+  gimple call = gimple_build_call (decl, 2, num_teams, thread_limit);
+  gimple_set_location (call, loc);
+  gimple_seq_add_stmt (&bind_body, call);
+
+  gimple_seq_add_seq (&bind_body, gimple_omp_body (teams_stmt));
+  gimple_omp_set_body (teams_stmt, NULL);
+  gimple_seq_add_seq (&bind_body, olist);
+  gimple_seq_add_seq (&bind_body, dlist);
+  gimple_seq_add_stmt (&bind_body, gimple_build_omp_return (true));
+  gimple_bind_set_body (bind, bind_body);
+
+  pop_gimplify_context (bind);
+
+  gimple_bind_append_vars (bind, ctx->block_vars);
+  BLOCK_VARS (block) = ctx->block_vars;
+  if (BLOCK_VARS (block))
+    TREE_USED (block) = 1;
+}
+
+
 /* Callback for lower_omp_1.  Return non-NULL if *tp needs to be
    regimplified.  If DATA is non-NULL, lower_omp_1 is outside
    of OpenMP context, but with task_shared_vars set.  */
@@ -7940,16 +9880,23 @@ lower_omp_1 (gimple_stmt_iterator *gsi_p
     case GIMPLE_OMP_PARALLEL:
     case GIMPLE_OMP_TASK:
       ctx = maybe_lookup_ctx (stmt);
+      gcc_assert (ctx);
+      if (ctx->cancellable)
+	ctx->cancel_label = create_artificial_label (UNKNOWN_LOCATION);
       lower_omp_taskreg (gsi_p, ctx);
       break;
     case GIMPLE_OMP_FOR:
       ctx = maybe_lookup_ctx (stmt);
       gcc_assert (ctx);
+      if (ctx->cancellable)
+	ctx->cancel_label = create_artificial_label (UNKNOWN_LOCATION);
       lower_omp_for (gsi_p, ctx);
       break;
     case GIMPLE_OMP_SECTIONS:
       ctx = maybe_lookup_ctx (stmt);
       gcc_assert (ctx);
+      if (ctx->cancellable)
+	ctx->cancel_label = create_artificial_label (UNKNOWN_LOCATION);
       lower_omp_sections (gsi_p, ctx);
       break;
     case GIMPLE_OMP_SINGLE:
@@ -7962,6 +9909,11 @@ lower_omp_1 (gimple_stmt_iterator *gsi_p
       gcc_assert (ctx);
       lower_omp_master (gsi_p, ctx);
       break;
+    case GIMPLE_OMP_TASKGROUP:
+      ctx = maybe_lookup_ctx (stmt);
+      gcc_assert (ctx);
+      lower_omp_taskgroup (gsi_p, ctx);
+      break;
     case GIMPLE_OMP_ORDERED:
       ctx = maybe_lookup_ctx (stmt);
       gcc_assert (ctx);
@@ -7978,6 +9930,66 @@ lower_omp_1 (gimple_stmt_iterator *gsi_p
 			lower_omp_regimplify_p, ctx ? NULL : &wi, NULL))
 	gimple_regimplify_operands (stmt, gsi_p);
       break;
+    case GIMPLE_OMP_TARGET:
+      ctx = maybe_lookup_ctx (stmt);
+      gcc_assert (ctx);
+      lower_omp_target (gsi_p, ctx);
+      break;
+    case GIMPLE_OMP_TEAMS:
+      ctx = maybe_lookup_ctx (stmt);
+      gcc_assert (ctx);
+      lower_omp_teams (gsi_p, ctx);
+      break;
+    case GIMPLE_CALL:
+      tree fndecl;
+      fndecl = gimple_call_fndecl (stmt);
+      if (fndecl
+	  && DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_NORMAL)
+	switch (DECL_FUNCTION_CODE (fndecl))
+	  {
+	  case BUILT_IN_GOMP_BARRIER:
+	    if (ctx == NULL)
+	      break;
+	    /* FALLTHRU */
+	  case BUILT_IN_GOMP_CANCEL:
+	  case BUILT_IN_GOMP_CANCELLATION_POINT:
+	    omp_context *cctx;
+	    cctx = ctx;
+	    if (gimple_code (cctx->stmt) == GIMPLE_OMP_SECTION)
+	      cctx = cctx->outer;
+	    gcc_assert (gimple_call_lhs (stmt) == NULL_TREE);
+	    if (!cctx->cancellable)
+	      {
+		if (DECL_FUNCTION_CODE (fndecl)
+		    == BUILT_IN_GOMP_CANCELLATION_POINT)
+		  {
+		    stmt = gimple_build_nop ();
+		    gsi_replace (gsi_p, stmt, false);
+		  }
+		break;
+	      }
+	    tree lhs;
+	    lhs = create_tmp_var (boolean_type_node, NULL);
+	    if (DECL_FUNCTION_CODE (fndecl) == BUILT_IN_GOMP_BARRIER)
+	      {
+		fndecl = builtin_decl_explicit (BUILT_IN_GOMP_BARRIER_CANCEL);
+		gimple_call_set_fndecl (stmt, fndecl);
+		gimple_call_set_fntype (stmt, TREE_TYPE (fndecl));
+	      }
+	    gimple_call_set_lhs (stmt, lhs);
+	    tree fallthru_label;
+	    fallthru_label = create_artificial_label (UNKNOWN_LOCATION);
+	    gimple g;
+	    g = gimple_build_label (fallthru_label);
+	    gsi_insert_after (gsi_p, g, GSI_SAME_STMT);
+	    g = gimple_build_cond (NE_EXPR, lhs, boolean_false_node,
+				   cctx->cancel_label, fallthru_label);
+	    gsi_insert_after (gsi_p, g, GSI_SAME_STMT);
+	    break;
+	  default:
+	    break;
+	  }
+      /* FALLTHRU */
     default:
       if ((ctx || task_shared_vars)
 	  && walk_gimple_op (stmt, lower_omp_regimplify_p,
@@ -7994,6 +10006,12 @@ lower_omp (gimple_seq *body, omp_context
   gimple_stmt_iterator gsi;
   for (gsi = gsi_start (*body); !gsi_end_p (gsi); gsi_next (&gsi))
     lower_omp_1 (&gsi, ctx);
+  /* Inside target region we haven't called fold_stmt during gimplification,
+     because it can break code by adding decl references that weren't in the
+     source.  Call fold_stmt now.  */
+  if (target_nesting_level)
+    for (gsi = gsi_start (*body); !gsi_end_p (gsi); gsi_next (&gsi))
+      fold_stmt (&gsi);
   input_location = saved_location;
 }
 
@@ -8162,6 +10180,9 @@ diagnose_sb_1 (gimple_stmt_iterator *gsi
     case GIMPLE_OMP_MASTER:
     case GIMPLE_OMP_ORDERED:
     case GIMPLE_OMP_CRITICAL:
+    case GIMPLE_OMP_TARGET:
+    case GIMPLE_OMP_TEAMS:
+    case GIMPLE_OMP_TASKGROUP:
       /* The minimal context here is just the current OMP construct.  */
       inner_context = stmt;
       wi->info = inner_context;
@@ -8217,6 +10238,9 @@ diagnose_sb_2 (gimple_stmt_iterator *gsi
     case GIMPLE_OMP_MASTER:
     case GIMPLE_OMP_ORDERED:
     case GIMPLE_OMP_CRITICAL:
+    case GIMPLE_OMP_TARGET:
+    case GIMPLE_OMP_TEAMS:
+    case GIMPLE_OMP_TASKGROUP:
       wi->info = stmt;
       walk_gimple_seq_mod (gimple_omp_body_ptr (stmt), diagnose_sb_2, NULL, wi);
       wi->info = context;
--- gcc/tree-cfg.c	(.../trunk)	(revision 203241)
+++ gcc/tree-cfg.c	(.../branches/gomp-4_0-branch)	(revision 203287)
@@ -610,7 +610,9 @@ make_edges (void)
 	    case GIMPLE_OMP_TASK:
 	    case GIMPLE_OMP_FOR:
 	    case GIMPLE_OMP_SINGLE:
+	    case GIMPLE_OMP_TEAMS:
 	    case GIMPLE_OMP_MASTER:
+	    case GIMPLE_OMP_TASKGROUP:
 	    case GIMPLE_OMP_ORDERED:
 	    case GIMPLE_OMP_CRITICAL:
 	    case GIMPLE_OMP_SECTION:
@@ -618,6 +620,13 @@ make_edges (void)
 	      fallthru = true;
 	      break;
 
+	    case GIMPLE_OMP_TARGET:
+	      cur_region = new_omp_region (bb, code, cur_region);
+	      fallthru = true;
+	      if (gimple_omp_target_kind (last) == GF_OMP_TARGET_KIND_UPDATE)
+		cur_region = cur_region->outer;
+	      break;
+
 	    case GIMPLE_OMP_SECTIONS:
 	      cur_region = new_omp_region (bb, code, cur_region);
 	      fallthru = true;
--- gcc/tree-core.h	(.../trunk)	(revision 203241)
+++ gcc/tree-core.h	(.../branches/gomp-4_0-branch)	(revision 203287)
@@ -243,9 +243,27 @@ enum omp_clause_code {
   /* OpenMP clause: linear (variable-list[:linear-step]).  */
   OMP_CLAUSE_LINEAR,
 
+  /* OpenMP clause: aligned (variable-list[:alignment]).  */
+  OMP_CLAUSE_ALIGNED,
+
+  /* OpenMP clause: depend ({in,out,inout}:variable-list).  */
+  OMP_CLAUSE_DEPEND,
+
   /* OpenMP clause: uniform (argument-list).  */
   OMP_CLAUSE_UNIFORM,
 
+  /* OpenMP clause: from (variable-list).  */
+  OMP_CLAUSE_FROM,
+
+  /* OpenMP clause: to (variable-list).  */
+  OMP_CLAUSE_TO,
+
+  /* OpenMP clause: map ({alloc:,to:,from:,tofrom:,}variable-list).  */
+  OMP_CLAUSE_MAP,
+
+  /* Internal clause: temporary for combined loops expansion.  */
+  OMP_CLAUSE__LOOPTEMP_,
+
   /* OpenMP clause: if (scalar-expression).  */
   OMP_CLAUSE_IF,
 
@@ -276,9 +294,45 @@ enum omp_clause_code {
   /* OpenMP clause: mergeable.  */
   OMP_CLAUSE_MERGEABLE,
 
+  /* OpenMP clause: device (integer-expression).  */
+  OMP_CLAUSE_DEVICE,
+
+  /* OpenMP clause: dist_schedule (static[:chunk-size]).  */
+  OMP_CLAUSE_DIST_SCHEDULE,
+
+  /* OpenMP clause: inbranch.  */
+  OMP_CLAUSE_INBRANCH,
+
+  /* OpenMP clause: notinbranch.  */
+  OMP_CLAUSE_NOTINBRANCH,
+
+  /* OpenMP clause: num_teams(integer-expression).  */
+  OMP_CLAUSE_NUM_TEAMS,
+
+  /* OpenMP clause: thread_limit(integer-expression).  */
+  OMP_CLAUSE_THREAD_LIMIT,
+
+  /* OpenMP clause: proc_bind ({master,close,spread}).  */
+  OMP_CLAUSE_PROC_BIND,
+
   /* OpenMP clause: safelen (constant-integer-expression).  */
   OMP_CLAUSE_SAFELEN,
 
+  /* OpenMP clause: simdlen (constant-integer-expression).  */
+  OMP_CLAUSE_SIMDLEN,
+
+  /* OpenMP clause: for.  */
+  OMP_CLAUSE_FOR,
+
+  /* OpenMP clause: parallel.  */
+  OMP_CLAUSE_PARALLEL,
+
+  /* OpenMP clause: sections.  */
+  OMP_CLAUSE_SECTIONS,
+
+  /* OpenMP clause: taskgroup.  */
+  OMP_CLAUSE_TASKGROUP,
+
   /* Internally used only clause, holding SIMD uid.  */
   OMP_CLAUSE__SIMDUID_
 };
@@ -784,6 +838,12 @@ struct GTY(()) tree_base {
        OMP_CLAUSE_LINEAR_NO_COPYIN in
 	   OMP_CLAUSE_LINEAR
 
+       OMP_CLAUSE_MAP_ZERO_BIAS_ARRAY_SECTION in
+	   OMP_CLAUSE_MAP
+
+       OMP_CLAUSE_REDUCTION_OMP_ORIG_REF in
+	   OMP_CLAUSE_REDUCTION
+
        TRANSACTION_EXPR_RELAXED in
 	   TRANSACTION_EXPR
 
@@ -801,6 +861,9 @@ struct GTY(()) tree_base {
        OMP_PARALLEL_COMBINED in
            OMP_PARALLEL
 
+       OMP_ATOMIC_SEQ_CST in
+	   OMP_ATOMIC*
+
        OMP_CLAUSE_PRIVATE_OUTER_REF in
 	   OMP_CLAUSE_PRIVATE
 
@@ -1020,6 +1083,35 @@ struct GTY(()) tree_constructor {
   vec<constructor_elt, va_gc> *elts;
 };
 
+enum omp_clause_depend_kind
+{
+  OMP_CLAUSE_DEPEND_IN,
+  OMP_CLAUSE_DEPEND_OUT,
+  OMP_CLAUSE_DEPEND_INOUT
+};
+
+enum omp_clause_map_kind
+{
+  OMP_CLAUSE_MAP_ALLOC,
+  OMP_CLAUSE_MAP_TO,
+  OMP_CLAUSE_MAP_FROM,
+  OMP_CLAUSE_MAP_TOFROM,
+  /* The following kind is an internal only map kind, used for pointer based
+     array sections.  OMP_CLAUSE_SIZE for these is not the pointer size,
+     which is implicitly POINTER_SIZE / BITS_PER_UNIT, but the bias.  */
+  OMP_CLAUSE_MAP_POINTER
+};
+
+enum omp_clause_proc_bind_kind
+{
+  /* Numbers should match omp_proc_bind_t enum in omp.h.  */
+  OMP_CLAUSE_PROC_BIND_FALSE = 0,
+  OMP_CLAUSE_PROC_BIND_TRUE = 1,
+  OMP_CLAUSE_PROC_BIND_MASTER = 2,
+  OMP_CLAUSE_PROC_BIND_CLOSE = 3,
+  OMP_CLAUSE_PROC_BIND_SPREAD = 4
+};
+
 struct GTY(()) tree_exp {
   struct tree_typed typed;
   location_t locus;
@@ -1077,9 +1169,12 @@ struct GTY(()) tree_omp_clause {
   location_t locus;
   enum omp_clause_code code;
   union omp_clause_subcode {
-    enum omp_clause_default_kind  default_kind;
-    enum omp_clause_schedule_kind schedule_kind;
-    enum tree_code                reduction_code;
+    enum omp_clause_default_kind   default_kind;
+    enum omp_clause_schedule_kind  schedule_kind;
+    enum omp_clause_depend_kind    depend_kind;
+    enum omp_clause_map_kind       map_kind;
+    enum omp_clause_proc_bind_kind proc_bind_kind;
+    enum tree_code                 reduction_code;
   } GTY ((skip)) subcode;
 
   /* The gimplification of OMP_CLAUSE_REDUCTION_{INIT,MERGE} for omp-low's
--- gcc/tree-inline.c	(.../trunk)	(revision 203241)
+++ gcc/tree-inline.c	(.../branches/gomp-4_0-branch)	(revision 203287)
@@ -1345,6 +1345,11 @@ remap_gimple_stmt (gimple stmt, copy_bod
 	  copy = gimple_build_omp_master (s1);
 	  break;
 
+	case GIMPLE_OMP_TASKGROUP:
+	  s1 = remap_gimple_seq (gimple_omp_body (stmt), id);
+	  copy = gimple_build_omp_taskgroup (s1);
+	  break;
+
 	case GIMPLE_OMP_ORDERED:
 	  s1 = remap_gimple_seq (gimple_omp_body (stmt), id);
 	  copy = gimple_build_omp_ordered (s1);
@@ -1367,6 +1372,19 @@ remap_gimple_stmt (gimple stmt, copy_bod
 	           (s1, gimple_omp_single_clauses (stmt));
 	  break;
 
+	case GIMPLE_OMP_TARGET:
+	  s1 = remap_gimple_seq (gimple_omp_body (stmt), id);
+	  copy = gimple_build_omp_target
+		   (s1, gimple_omp_target_kind (stmt),
+		    gimple_omp_target_clauses (stmt));
+	  break;
+
+	case GIMPLE_OMP_TEAMS:
+	  s1 = remap_gimple_seq (gimple_omp_body (stmt), id);
+	  copy = gimple_build_omp_teams
+		   (s1, gimple_omp_teams_clauses (stmt));
+	  break;
+
 	case GIMPLE_OMP_CRITICAL:
 	  s1 = remap_gimple_seq (gimple_omp_body (stmt), id);
 	  copy
@@ -3828,10 +3846,13 @@ estimate_num_insns (gimple stmt, eni_wei
     case GIMPLE_OMP_TASK:
     case GIMPLE_OMP_CRITICAL:
     case GIMPLE_OMP_MASTER:
+    case GIMPLE_OMP_TASKGROUP:
     case GIMPLE_OMP_ORDERED:
     case GIMPLE_OMP_SECTION:
     case GIMPLE_OMP_SECTIONS:
     case GIMPLE_OMP_SINGLE:
+    case GIMPLE_OMP_TARGET:
+    case GIMPLE_OMP_TEAMS:
       return (weights->omp_cost
               + estimate_num_insns_seq (gimple_omp_body (stmt), weights));
 
--- gcc/tree-nested.c	(.../trunk)	(revision 203241)
+++ gcc/tree-nested.c	(.../branches/gomp-4_0-branch)	(revision 203287)
@@ -1291,8 +1291,25 @@ convert_nonlocal_reference_stmt (gimple_
       info->suppress_expansion = save_suppress;
       break;
 
+    case GIMPLE_OMP_TARGET:
+      save_suppress = info->suppress_expansion;
+      convert_nonlocal_omp_clauses (gimple_omp_target_clauses_ptr (stmt), wi);
+      walk_body (convert_nonlocal_reference_stmt, convert_nonlocal_reference_op,
+		 info, gimple_omp_body_ptr (stmt));
+      info->suppress_expansion = save_suppress;
+      break;
+
+    case GIMPLE_OMP_TEAMS:
+      save_suppress = info->suppress_expansion;
+      convert_nonlocal_omp_clauses (gimple_omp_teams_clauses_ptr (stmt), wi);
+      walk_body (convert_nonlocal_reference_stmt, convert_nonlocal_reference_op,
+		 info, gimple_omp_body_ptr (stmt));
+      info->suppress_expansion = save_suppress;
+      break;
+
     case GIMPLE_OMP_SECTION:
     case GIMPLE_OMP_MASTER:
+    case GIMPLE_OMP_TASKGROUP:
     case GIMPLE_OMP_ORDERED:
       walk_body (convert_nonlocal_reference_stmt, convert_nonlocal_reference_op,
 	         info, gimple_omp_body_ptr (stmt));
@@ -1714,8 +1731,25 @@ convert_local_reference_stmt (gimple_stm
       info->suppress_expansion = save_suppress;
       break;
 
+    case GIMPLE_OMP_TARGET:
+      save_suppress = info->suppress_expansion;
+      convert_local_omp_clauses (gimple_omp_target_clauses_ptr (stmt), wi);
+      walk_body (convert_local_reference_stmt, convert_local_reference_op,
+		 info, gimple_omp_body_ptr (stmt));
+      info->suppress_expansion = save_suppress;
+      break;
+
+    case GIMPLE_OMP_TEAMS:
+      save_suppress = info->suppress_expansion;
+      convert_local_omp_clauses (gimple_omp_teams_clauses_ptr (stmt), wi);
+      walk_body (convert_local_reference_stmt, convert_local_reference_op,
+		 info, gimple_omp_body_ptr (stmt));
+      info->suppress_expansion = save_suppress;
+      break;
+
     case GIMPLE_OMP_SECTION:
     case GIMPLE_OMP_MASTER:
+    case GIMPLE_OMP_TASKGROUP:
     case GIMPLE_OMP_ORDERED:
       walk_body (convert_local_reference_stmt, convert_local_reference_op,
 		 info, gimple_omp_body_ptr (stmt));
@@ -2071,7 +2105,10 @@ convert_gimple_call (gimple_stmt_iterato
     case GIMPLE_OMP_SECTIONS:
     case GIMPLE_OMP_SECTION:
     case GIMPLE_OMP_SINGLE:
+    case GIMPLE_OMP_TARGET:
+    case GIMPLE_OMP_TEAMS:
     case GIMPLE_OMP_MASTER:
+    case GIMPLE_OMP_TASKGROUP:
     case GIMPLE_OMP_ORDERED:
     case GIMPLE_OMP_CRITICAL:
       walk_body (convert_gimple_call, NULL, info, gimple_omp_body_ptr (stmt));
--- gcc/tree-pretty-print.c	(.../trunk)	(revision 203241)
+++ gcc/tree-pretty-print.c	(.../branches/gomp-4_0-branch)	(revision 203287)
@@ -319,6 +319,9 @@ dump_omp_clause (pretty_printer *buffer,
     case OMP_CLAUSE_UNIFORM:
       name = "uniform";
       goto print_remap;
+    case OMP_CLAUSE__LOOPTEMP_:
+      name = "_looptemp_";
+      goto print_remap;
   print_remap:
       pp_string (buffer, name);
       pp_left_paren (buffer);
@@ -329,24 +332,28 @@ dump_omp_clause (pretty_printer *buffer,
 
     case OMP_CLAUSE_REDUCTION:
       pp_string (buffer, "reduction(");
-      pp_string (buffer, op_symbol_code (OMP_CLAUSE_REDUCTION_CODE (clause)));
-      pp_colon (buffer);
+      if (OMP_CLAUSE_REDUCTION_CODE (clause) != ERROR_MARK)
+	{
+	  pp_string (buffer,
+		     op_symbol_code (OMP_CLAUSE_REDUCTION_CODE (clause)));
+	  pp_colon (buffer);
+	}
       dump_generic_node (buffer, OMP_CLAUSE_DECL (clause),
-	  spc, flags, false);
+			 spc, flags, false);
       pp_right_paren (buffer);
       break;
 
     case OMP_CLAUSE_IF:
       pp_string (buffer, "if(");
       dump_generic_node (buffer, OMP_CLAUSE_IF_EXPR (clause),
-	  spc, flags, false);
+			 spc, flags, false);
       pp_right_paren (buffer);
       break;
 
     case OMP_CLAUSE_NUM_THREADS:
       pp_string (buffer, "num_threads(");
       dump_generic_node (buffer, OMP_CLAUSE_NUM_THREADS_EXPR (clause),
-	  spc, flags, false);
+			 spc, flags, false);
       pp_right_paren (buffer);
       break;
 
@@ -385,30 +392,29 @@ dump_omp_clause (pretty_printer *buffer,
       pp_string (buffer, "schedule(");
       switch (OMP_CLAUSE_SCHEDULE_KIND (clause))
 	{
-      case OMP_CLAUSE_SCHEDULE_STATIC:
-	pp_string (buffer, "static");
-	break;
-      case OMP_CLAUSE_SCHEDULE_DYNAMIC:
-	pp_string (buffer, "dynamic");
-	break;
-      case OMP_CLAUSE_SCHEDULE_GUIDED:
-	pp_string (buffer, "guided");
-	break;
-      case OMP_CLAUSE_SCHEDULE_RUNTIME:
-	pp_string (buffer, "runtime");
-	break;
-      case OMP_CLAUSE_SCHEDULE_AUTO:
-	pp_string (buffer, "auto");
-	break;
-      default:
-	gcc_unreachable ();
+	case OMP_CLAUSE_SCHEDULE_STATIC:
+	  pp_string (buffer, "static");
+	  break;
+	case OMP_CLAUSE_SCHEDULE_DYNAMIC:
+	  pp_string (buffer, "dynamic");
+	  break;
+	case OMP_CLAUSE_SCHEDULE_GUIDED:
+	  pp_string (buffer, "guided");
+	  break;
+	case OMP_CLAUSE_SCHEDULE_RUNTIME:
+	  pp_string (buffer, "runtime");
+	  break;
+	case OMP_CLAUSE_SCHEDULE_AUTO:
+	  pp_string (buffer, "auto");
+	  break;
+	default:
+	  gcc_unreachable ();
 	}
       if (OMP_CLAUSE_SCHEDULE_CHUNK_EXPR (clause))
 	{
 	  pp_comma (buffer);
-	  dump_generic_node (buffer,
-	      OMP_CLAUSE_SCHEDULE_CHUNK_EXPR (clause),
-	      spc, flags, false);
+	  dump_generic_node (buffer, OMP_CLAUSE_SCHEDULE_CHUNK_EXPR (clause),
+			     spc, flags, false);
 	}
       pp_right_paren (buffer);
       break;
@@ -419,8 +425,7 @@ dump_omp_clause (pretty_printer *buffer,
 
     case OMP_CLAUSE_COLLAPSE:
       pp_string (buffer, "collapse(");
-      dump_generic_node (buffer,
-			 OMP_CLAUSE_COLLAPSE_EXPR (clause),
+      dump_generic_node (buffer, OMP_CLAUSE_COLLAPSE_EXPR (clause),
 			 spc, flags, false);
       pp_right_paren (buffer);
       break;
@@ -428,7 +433,7 @@ dump_omp_clause (pretty_printer *buffer,
     case OMP_CLAUSE_FINAL:
       pp_string (buffer, "final(");
       dump_generic_node (buffer, OMP_CLAUSE_FINAL_EXPR (clause),
-	  spc, flags, false);
+			 spc, flags, false);
       pp_right_paren (buffer);
       break;
 
@@ -440,24 +445,187 @@ dump_omp_clause (pretty_printer *buffer,
       pp_string (buffer, "linear(");
       dump_generic_node (buffer, OMP_CLAUSE_DECL (clause),
 			 spc, flags, false);
-      pp_character (buffer, ':');
+      pp_colon (buffer);
       dump_generic_node (buffer, OMP_CLAUSE_LINEAR_STEP (clause),
 			 spc, flags, false);
-      pp_character (buffer, ')');
+      pp_right_paren (buffer);
+      break;
+
+    case OMP_CLAUSE_ALIGNED:
+      pp_string (buffer, "aligned(");
+      dump_generic_node (buffer, OMP_CLAUSE_DECL (clause),
+			 spc, flags, false);
+      if (OMP_CLAUSE_ALIGNED_ALIGNMENT (clause))
+	{
+	  pp_colon (buffer);
+	  dump_generic_node (buffer, OMP_CLAUSE_ALIGNED_ALIGNMENT (clause),
+			     spc, flags, false);
+	}
+      pp_right_paren (buffer);
+      break;
+
+    case OMP_CLAUSE_DEPEND:
+      pp_string (buffer, "depend(");
+      switch (OMP_CLAUSE_DEPEND_KIND (clause))
+	{
+	case OMP_CLAUSE_DEPEND_IN:
+	  pp_string (buffer, "in");
+	  break;
+	case OMP_CLAUSE_DEPEND_OUT:
+	  pp_string (buffer, "out");
+	  break;
+	case OMP_CLAUSE_DEPEND_INOUT:
+	  pp_string (buffer, "inout");
+	  break;
+	default:
+	  gcc_unreachable ();
+	}
+      pp_colon (buffer);
+      dump_generic_node (buffer, OMP_CLAUSE_DECL (clause),
+			 spc, flags, false);
+      pp_right_paren (buffer);
+      break;
+
+    case OMP_CLAUSE_MAP:
+      pp_string (buffer, "map(");
+      switch (OMP_CLAUSE_MAP_KIND (clause))
+	{
+	case OMP_CLAUSE_MAP_ALLOC:
+	case OMP_CLAUSE_MAP_POINTER:
+	  pp_string (buffer, "alloc");
+	  break;
+	case OMP_CLAUSE_MAP_TO:
+	  pp_string (buffer, "to");
+	  break;
+	case OMP_CLAUSE_MAP_FROM:
+	  pp_string (buffer, "from");
+	  break;
+	case OMP_CLAUSE_MAP_TOFROM:
+	  pp_string (buffer, "tofrom");
+	  break;
+	default:
+	  gcc_unreachable ();
+	}
+      pp_colon (buffer);
+      dump_generic_node (buffer, OMP_CLAUSE_DECL (clause),
+			 spc, flags, false);
+     print_clause_size:
+      if (OMP_CLAUSE_SIZE (clause))
+	{
+	  if (OMP_CLAUSE_CODE (clause) == OMP_CLAUSE_MAP
+	      && OMP_CLAUSE_MAP_KIND (clause) == OMP_CLAUSE_MAP_POINTER)
+	    pp_string (buffer, " [pointer assign, bias: ");
+	  else
+	    pp_string (buffer, " [len: ");
+	  dump_generic_node (buffer, OMP_CLAUSE_SIZE (clause),
+			     spc, flags, false);
+	  pp_right_bracket (buffer);
+	}
+      pp_right_paren (buffer);
+      break;
+
+    case OMP_CLAUSE_FROM:
+      pp_string (buffer, "from(");
+      dump_generic_node (buffer, OMP_CLAUSE_DECL (clause),
+			 spc, flags, false);
+      goto print_clause_size;
+
+    case OMP_CLAUSE_TO:
+      pp_string (buffer, "to(");
+      dump_generic_node (buffer, OMP_CLAUSE_DECL (clause),
+			 spc, flags, false);
+      goto print_clause_size;
+
+    case OMP_CLAUSE_NUM_TEAMS:
+      pp_string (buffer, "num_teams(");
+      dump_generic_node (buffer, OMP_CLAUSE_NUM_TEAMS_EXPR (clause),
+			 spc, flags, false);
+      pp_right_paren (buffer);
+      break;
+
+    case OMP_CLAUSE_THREAD_LIMIT:
+      pp_string (buffer, "thread_limit(");
+      dump_generic_node (buffer, OMP_CLAUSE_THREAD_LIMIT_EXPR (clause),
+			 spc, flags, false);
+      pp_right_paren (buffer);
+      break;
+
+    case OMP_CLAUSE_DEVICE:
+      pp_string (buffer, "device(");
+      dump_generic_node (buffer, OMP_CLAUSE_DEVICE_ID (clause),
+			 spc, flags, false);
+      pp_right_paren (buffer);
+      break;
+
+    case OMP_CLAUSE_DIST_SCHEDULE:
+      pp_string (buffer, "dist_schedule(static");
+      if (OMP_CLAUSE_DIST_SCHEDULE_CHUNK_EXPR (clause))
+	{
+	  pp_comma (buffer);
+	  dump_generic_node (buffer,
+			     OMP_CLAUSE_DIST_SCHEDULE_CHUNK_EXPR (clause),
+			     spc, flags, false);
+	}
+      pp_right_paren (buffer);
+      break;
+
+    case OMP_CLAUSE_PROC_BIND:
+      pp_string (buffer, "proc_bind(");
+      switch (OMP_CLAUSE_PROC_BIND_KIND (clause))
+	{
+	case OMP_CLAUSE_PROC_BIND_MASTER:
+	  pp_string (buffer, "master");
+	  break;
+	case OMP_CLAUSE_PROC_BIND_CLOSE:
+	  pp_string (buffer, "close");
+	  break;
+	case OMP_CLAUSE_PROC_BIND_SPREAD:
+	  pp_string (buffer, "spread");
+	  break;
+	default:
+	  gcc_unreachable ();
+	}
+      pp_right_paren (buffer);
       break;
 
     case OMP_CLAUSE_SAFELEN:
       pp_string (buffer, "safelen(");
       dump_generic_node (buffer, OMP_CLAUSE_SAFELEN_EXPR (clause),
 			 spc, flags, false);
-      pp_character (buffer, ')');
+      pp_right_paren (buffer);
+      break;
+
+    case OMP_CLAUSE_SIMDLEN:
+      pp_string (buffer, "simdlen(");
+      dump_generic_node (buffer, OMP_CLAUSE_SIMDLEN_EXPR (clause),
+			 spc, flags, false);
+      pp_right_paren (buffer);
       break;
 
     case OMP_CLAUSE__SIMDUID_:
       pp_string (buffer, "_simduid_(");
       dump_generic_node (buffer, OMP_CLAUSE__SIMDUID__DECL (clause),
 			 spc, flags, false);
-      pp_character (buffer, ')');
+      pp_right_paren (buffer);
+      break;
+
+    case OMP_CLAUSE_INBRANCH:
+      pp_string (buffer, "inbranch");
+      break;
+    case OMP_CLAUSE_NOTINBRANCH:
+      pp_string (buffer, "notinbranch");
+      break;
+    case OMP_CLAUSE_FOR:
+      pp_string (buffer, "for");
+      break;
+    case OMP_CLAUSE_PARALLEL:
+      pp_string (buffer, "parallel");
+      break;
+    case OMP_CLAUSE_SECTIONS:
+      pp_string (buffer, "sections");
+      break;
+    case OMP_CLAUSE_TASKGROUP:
+      pp_string (buffer, "taskgroup");
       break;
 
     default:
@@ -2192,6 +2360,31 @@ dump_generic_node (pretty_printer *buffe
       pp_string (buffer, "#pragma omp simd");
       goto dump_omp_loop;
 
+    case OMP_DISTRIBUTE:
+      pp_string (buffer, "#pragma omp distribute");
+      goto dump_omp_loop;
+
+    case OMP_TEAMS:
+      pp_string (buffer, "#pragma omp teams");
+      dump_omp_clauses (buffer, OMP_TEAMS_CLAUSES (node), spc, flags);
+      goto dump_omp_body;
+
+    case OMP_TARGET_DATA:
+      pp_string (buffer, "#pragma omp target data");
+      dump_omp_clauses (buffer, OMP_TARGET_DATA_CLAUSES (node), spc, flags);
+      goto dump_omp_body;
+
+    case OMP_TARGET:
+      pp_string (buffer, "#pragma omp target");
+      dump_omp_clauses (buffer, OMP_TARGET_CLAUSES (node), spc, flags);
+      goto dump_omp_body;
+
+    case OMP_TARGET_UPDATE:
+      pp_string (buffer, "#pragma omp target update");
+      dump_omp_clauses (buffer, OMP_TARGET_UPDATE_CLAUSES (node), spc, flags);
+      is_expr = false;
+      break;
+
     dump_omp_loop:
       dump_omp_clauses (buffer, OMP_FOR_CLAUSES (node), spc, flags);
 
@@ -2208,21 +2401,27 @@ dump_generic_node (pretty_printer *buffe
 	      dump_generic_node (buffer, OMP_FOR_PRE_BODY (node),
 		  spc, flags, false);
 	    }
-	  spc -= 2;
-	  for (i = 0; i < TREE_VEC_LENGTH (OMP_FOR_INIT (node)); i++)
+	  if (OMP_FOR_INIT (node))
 	    {
-	      spc += 2;
-	      newline_and_indent (buffer, spc);
-	      pp_string (buffer, "for (");
-	      dump_generic_node (buffer, TREE_VEC_ELT (OMP_FOR_INIT (node), i),
-				 spc, flags, false);
-	      pp_string (buffer, "; ");
-	      dump_generic_node (buffer, TREE_VEC_ELT (OMP_FOR_COND (node), i),
-				 spc, flags, false);
-	      pp_string (buffer, "; ");
-	      dump_generic_node (buffer, TREE_VEC_ELT (OMP_FOR_INCR (node), i),
-				 spc, flags, false);
-	      pp_right_paren (buffer);
+	      spc -= 2;
+	      for (i = 0; i < TREE_VEC_LENGTH (OMP_FOR_INIT (node)); i++)
+		{
+		  spc += 2;
+		  newline_and_indent (buffer, spc);
+		  pp_string (buffer, "for (");
+		  dump_generic_node (buffer,
+				     TREE_VEC_ELT (OMP_FOR_INIT (node), i),
+				     spc, flags, false);
+		  pp_string (buffer, "; ");
+		  dump_generic_node (buffer,
+				     TREE_VEC_ELT (OMP_FOR_COND (node), i),
+				     spc, flags, false);
+		  pp_string (buffer, "; ");
+		  dump_generic_node (buffer,
+				     TREE_VEC_ELT (OMP_FOR_INCR (node), i),
+				     spc, flags, false);
+		  pp_right_paren (buffer);
+		}
 	    }
 	  if (OMP_FOR_BODY (node))
 	    {
@@ -2234,7 +2433,8 @@ dump_generic_node (pretty_printer *buffe
 	      newline_and_indent (buffer, spc + 2);
 	      pp_right_brace (buffer);
 	    }
-	  spc -= 2 * TREE_VEC_LENGTH (OMP_FOR_INIT (node)) - 2;
+	  if (OMP_FOR_INIT (node))
+	    spc -= 2 * TREE_VEC_LENGTH (OMP_FOR_INIT (node)) - 2;
 	  if (OMP_FOR_PRE_BODY (node))
 	    {
 	      spc -= 4;
@@ -2258,6 +2458,10 @@ dump_generic_node (pretty_printer *buffe
       pp_string (buffer, "#pragma omp master");
       goto dump_omp_body;
 
+    case OMP_TASKGROUP:
+      pp_string (buffer, "#pragma omp taskgroup");
+      goto dump_omp_body;
+
     case OMP_ORDERED:
       pp_string (buffer, "#pragma omp ordered");
       goto dump_omp_body;
@@ -2276,6 +2480,8 @@ dump_generic_node (pretty_printer *buffe
 
     case OMP_ATOMIC:
       pp_string (buffer, "#pragma omp atomic");
+      if (OMP_ATOMIC_SEQ_CST (node))
+	pp_string (buffer, " seq_cst");
       newline_and_indent (buffer, spc + 2);
       dump_generic_node (buffer, TREE_OPERAND (node, 0), spc, flags, false);
       pp_space (buffer);
@@ -2286,6 +2492,8 @@ dump_generic_node (pretty_printer *buffe
 
     case OMP_ATOMIC_READ:
       pp_string (buffer, "#pragma omp atomic read");
+      if (OMP_ATOMIC_SEQ_CST (node))
+	pp_string (buffer, " seq_cst");
       newline_and_indent (buffer, spc + 2);
       dump_generic_node (buffer, TREE_OPERAND (node, 0), spc, flags, false);
       pp_space (buffer);
@@ -2294,6 +2502,8 @@ dump_generic_node (pretty_printer *buffe
     case OMP_ATOMIC_CAPTURE_OLD:
     case OMP_ATOMIC_CAPTURE_NEW:
       pp_string (buffer, "#pragma omp atomic capture");
+      if (OMP_ATOMIC_SEQ_CST (node))
+	pp_string (buffer, " seq_cst");
       newline_and_indent (buffer, spc + 2);
       dump_generic_node (buffer, TREE_OPERAND (node, 0), spc, flags, false);
       pp_space (buffer);
--- gcc/tree-ssa-alias.c	(.../trunk)	(revision 203241)
+++ gcc/tree-ssa-alias.c	(.../branches/gomp-4_0-branch)	(revision 203287)
@@ -1513,16 +1513,19 @@ ref_maybe_used_by_call_p_1 (gimple call,
 	case BUILT_IN_GOMP_ATOMIC_START:
 	case BUILT_IN_GOMP_ATOMIC_END:
 	case BUILT_IN_GOMP_BARRIER:
+	case BUILT_IN_GOMP_BARRIER_CANCEL:
 	case BUILT_IN_GOMP_TASKWAIT:
+	case BUILT_IN_GOMP_TASKGROUP_END:
 	case BUILT_IN_GOMP_CRITICAL_START:
 	case BUILT_IN_GOMP_CRITICAL_END:
 	case BUILT_IN_GOMP_CRITICAL_NAME_START:
 	case BUILT_IN_GOMP_CRITICAL_NAME_END:
 	case BUILT_IN_GOMP_LOOP_END:
+	case BUILT_IN_GOMP_LOOP_END_CANCEL:
 	case BUILT_IN_GOMP_ORDERED_START:
 	case BUILT_IN_GOMP_ORDERED_END:
-	case BUILT_IN_GOMP_PARALLEL_END:
 	case BUILT_IN_GOMP_SECTIONS_END:
+	case BUILT_IN_GOMP_SECTIONS_END_CANCEL:
 	case BUILT_IN_GOMP_SINGLE_COPY_START:
 	case BUILT_IN_GOMP_SINGLE_COPY_END:
 	  return true;
@@ -1857,16 +1860,19 @@ call_may_clobber_ref_p_1 (gimple call, a
 	case BUILT_IN_GOMP_ATOMIC_START:
 	case BUILT_IN_GOMP_ATOMIC_END:
 	case BUILT_IN_GOMP_BARRIER:
+	case BUILT_IN_GOMP_BARRIER_CANCEL:
 	case BUILT_IN_GOMP_TASKWAIT:
+	case BUILT_IN_GOMP_TASKGROUP_END:
 	case BUILT_IN_GOMP_CRITICAL_START:
 	case BUILT_IN_GOMP_CRITICAL_END:
 	case BUILT_IN_GOMP_CRITICAL_NAME_START:
 	case BUILT_IN_GOMP_CRITICAL_NAME_END:
 	case BUILT_IN_GOMP_LOOP_END:
+	case BUILT_IN_GOMP_LOOP_END_CANCEL:
 	case BUILT_IN_GOMP_ORDERED_START:
 	case BUILT_IN_GOMP_ORDERED_END:
-	case BUILT_IN_GOMP_PARALLEL_END:
 	case BUILT_IN_GOMP_SECTIONS_END:
+	case BUILT_IN_GOMP_SECTIONS_END_CANCEL:
 	case BUILT_IN_GOMP_SINGLE_COPY_START:
 	case BUILT_IN_GOMP_SINGLE_COPY_END:
 	  return true;
--- gcc/tree-vectorizer.c	(.../trunk)	(revision 203241)
+++ gcc/tree-vectorizer.c	(.../branches/gomp-4_0-branch)	(revision 203287)
@@ -111,7 +111,8 @@ simduid_to_vf::equal (const value_type *
         D.1737[_7] = stuff;
 
 
-   This hash maps from the simduid.0 to OMP simd array (D.1737[]).  */
+   This hash maps from the OMP simd array (D.1737[]) to DECL_UID of
+   simduid.0.  */
 
 struct simd_array_to_simduid : typed_free_remove<simd_array_to_simduid>
 {
--- gcc/tree.c	(.../trunk)	(revision 203241)
+++ gcc/tree.c	(.../branches/gomp-4_0-branch)	(revision 203287)
@@ -237,7 +237,13 @@ unsigned const char omp_clause_num_ops[]
   1, /* OMP_CLAUSE_COPYIN  */
   1, /* OMP_CLAUSE_COPYPRIVATE  */
   2, /* OMP_CLAUSE_LINEAR  */
+  2, /* OMP_CLAUSE_ALIGNED  */
+  1, /* OMP_CLAUSE_DEPEND  */
   1, /* OMP_CLAUSE_UNIFORM  */
+  2, /* OMP_CLAUSE_FROM  */
+  2, /* OMP_CLAUSE_TO  */
+  2, /* OMP_CLAUSE_MAP  */
+  1, /* OMP_CLAUSE__LOOPTEMP_  */
   1, /* OMP_CLAUSE_IF  */
   1, /* OMP_CLAUSE_NUM_THREADS  */
   1, /* OMP_CLAUSE_SCHEDULE  */
@@ -248,7 +254,19 @@ unsigned const char omp_clause_num_ops[]
   0, /* OMP_CLAUSE_UNTIED   */
   1, /* OMP_CLAUSE_FINAL  */
   0, /* OMP_CLAUSE_MERGEABLE  */
+  1, /* OMP_CLAUSE_DEVICE  */
+  1, /* OMP_CLAUSE_DIST_SCHEDULE  */
+  0, /* OMP_CLAUSE_INBRANCH  */
+  0, /* OMP_CLAUSE_NOTINBRANCH  */
+  1, /* OMP_CLAUSE_NUM_TEAMS  */
+  1, /* OMP_CLAUSE_THREAD_LIMIT  */
+  0, /* OMP_CLAUSE_PROC_BIND  */
   1, /* OMP_CLAUSE_SAFELEN  */
+  1, /* OMP_CLAUSE_SIMDLEN  */
+  0, /* OMP_CLAUSE_FOR  */
+  0, /* OMP_CLAUSE_PARALLEL  */
+  0, /* OMP_CLAUSE_SECTIONS  */
+  0, /* OMP_CLAUSE_TASKGROUP  */
   1, /* OMP_CLAUSE__SIMDUID_  */
 };
 
@@ -263,7 +281,13 @@ const char * const omp_clause_code_name[
   "copyin",
   "copyprivate",
   "linear",
+  "aligned",
+  "depend",
   "uniform",
+  "from",
+  "to",
+  "map",
+  "_looptemp_",
   "if",
   "num_threads",
   "schedule",
@@ -274,7 +298,19 @@ const char * const omp_clause_code_name[
   "untied",
   "final",
   "mergeable",
+  "device",
+  "dist_schedule",
+  "inbranch",
+  "notinbranch",
+  "num_teams",
+  "thread_limit",
+  "proc_bind",
   "safelen",
+  "simdlen",
+  "for",
+  "parallel",
+  "sections",
+  "taskgroup",
   "_simduid_"
 };
 
@@ -4560,6 +4596,77 @@ build_type_attribute_qual_variant (tree
   return ttype;
 }
 
+/* Check if "omp declare simd" attribute arguments, CLAUSES1 and CLAUSES2, are
+   the same.  */
+
+static bool
+omp_declare_simd_clauses_equal (tree clauses1, tree clauses2)
+{
+  tree cl1, cl2;
+  for (cl1 = clauses1, cl2 = clauses2;
+       cl1 && cl2;
+       cl1 = OMP_CLAUSE_CHAIN (cl1), cl2 = OMP_CLAUSE_CHAIN (cl2))
+    {
+      if (OMP_CLAUSE_CODE (cl1) != OMP_CLAUSE_CODE (cl2))
+	return false;
+      if (OMP_CLAUSE_CODE (cl1) != OMP_CLAUSE_SIMDLEN)
+	{
+	  if (simple_cst_equal (OMP_CLAUSE_DECL (cl1),
+				OMP_CLAUSE_DECL (cl2)) != 1)
+	    return false;
+	}
+      switch (OMP_CLAUSE_CODE (cl1))
+	{
+	case OMP_CLAUSE_ALIGNED:
+	  if (simple_cst_equal (OMP_CLAUSE_ALIGNED_ALIGNMENT (cl1),
+				OMP_CLAUSE_ALIGNED_ALIGNMENT (cl2)) != 1)
+	    return false;
+	  break;
+	case OMP_CLAUSE_LINEAR:
+	  if (simple_cst_equal (OMP_CLAUSE_LINEAR_STEP (cl1),
+				OMP_CLAUSE_LINEAR_STEP (cl2)) != 1)
+	    return false;
+	  break;
+	case OMP_CLAUSE_SIMDLEN:
+	  if (simple_cst_equal (OMP_CLAUSE_SIMDLEN_EXPR (cl1),
+				OMP_CLAUSE_SIMDLEN_EXPR (cl2)) != 1)
+	    return false;
+	default:
+	  break;
+	}
+    }
+  return true;
+}
+
+/* Remove duplicate "omp declare simd" attributes.  */
+
+void
+omp_remove_redundant_declare_simd_attrs (tree fndecl)
+{
+  tree attr, end_attr = NULL_TREE, last_attr = NULL_TREE;
+  for (attr = lookup_attribute ("omp declare simd", DECL_ATTRIBUTES (fndecl));
+       attr;
+       attr = lookup_attribute ("omp declare simd", TREE_CHAIN (attr)))
+    {
+      tree *pc;
+      for (pc = &TREE_CHAIN (attr); *pc && *pc != end_attr; )
+	{
+	  if (is_attribute_p ("omp declare simd", TREE_PURPOSE (*pc)))
+	    {
+	      last_attr = TREE_CHAIN (*pc);
+	      if (omp_declare_simd_clauses_equal (TREE_VALUE (*pc),
+						  TREE_VALUE (attr)))
+		{
+		  *pc = TREE_CHAIN (*pc);
+		  continue;
+		}
+	    }
+	  pc = &TREE_CHAIN (*pc);
+	}
+      end_attr = last_attr;
+    }
+}
+
 /* Compare two attributes for their value identity.  Return true if the
    attribute values are known to be equal; otherwise return false.
 */
@@ -4577,6 +4684,13 @@ attribute_value_equal (const_tree attr1,
     return (simple_cst_list_equal (TREE_VALUE (attr1),
 				   TREE_VALUE (attr2)) == 1);
 
+  if (flag_openmp
+      && TREE_VALUE (attr1) && TREE_VALUE (attr2)
+      && TREE_CODE (TREE_VALUE (attr1)) == OMP_CLAUSE
+      && TREE_CODE (TREE_VALUE (attr2)) == OMP_CLAUSE)
+    return omp_declare_simd_clauses_equal (TREE_VALUE (attr1),
+					   TREE_VALUE (attr2));
+
   return (simple_cst_equal (TREE_VALUE (attr1), TREE_VALUE (attr2)) == 1);
 }
 
@@ -11047,7 +11161,14 @@ walk_tree_1 (tree *tp, walk_tree_fn func
 	case OMP_CLAUSE_NUM_THREADS:
 	case OMP_CLAUSE_SCHEDULE:
 	case OMP_CLAUSE_UNIFORM:
+	case OMP_CLAUSE_DEPEND:
+	case OMP_CLAUSE_NUM_TEAMS:
+	case OMP_CLAUSE_THREAD_LIMIT:
+	case OMP_CLAUSE_DEVICE:
+	case OMP_CLAUSE_DIST_SCHEDULE:
 	case OMP_CLAUSE_SAFELEN:
+	case OMP_CLAUSE_SIMDLEN:
+	case OMP_CLAUSE__LOOPTEMP_:
 	case OMP_CLAUSE__SIMDUID_:
 	  WALK_SUBTREE (OMP_CLAUSE_OPERAND (*tp, 0));
 	  /* FALLTHRU */
@@ -11057,6 +11178,13 @@ walk_tree_1 (tree *tp, walk_tree_fn func
 	case OMP_CLAUSE_DEFAULT:
 	case OMP_CLAUSE_UNTIED:
 	case OMP_CLAUSE_MERGEABLE:
+	case OMP_CLAUSE_PROC_BIND:
+	case OMP_CLAUSE_INBRANCH:
+	case OMP_CLAUSE_NOTINBRANCH:
+	case OMP_CLAUSE_FOR:
+	case OMP_CLAUSE_PARALLEL:
+	case OMP_CLAUSE_SECTIONS:
+	case OMP_CLAUSE_TASKGROUP:
 	  WALK_SUBTREE_TAIL (OMP_CLAUSE_CHAIN (*tp));
 
 	case OMP_CLAUSE_LASTPRIVATE:
@@ -11072,7 +11200,11 @@ walk_tree_1 (tree *tp, walk_tree_fn func
 	    WALK_SUBTREE_TAIL (OMP_CLAUSE_CHAIN (*tp));
 	  }
 
+	case OMP_CLAUSE_ALIGNED:
 	case OMP_CLAUSE_LINEAR:
+	case OMP_CLAUSE_FROM:
+	case OMP_CLAUSE_TO:
+	case OMP_CLAUSE_MAP:
 	  WALK_SUBTREE (OMP_CLAUSE_DECL (*tp));
 	  WALK_SUBTREE (OMP_CLAUSE_OPERAND (*tp, 1));
 	  WALK_SUBTREE_TAIL (OMP_CLAUSE_CHAIN (*tp));
--- gcc/tree.def	(.../trunk)	(revision 203241)
+++ gcc/tree.def	(.../branches/gomp-4_0-branch)	(revision 203287)
@@ -1034,6 +1034,25 @@ DEFTREECODE (OMP_FOR, "omp_for", tcc_sta
    Operands like for OMP_FOR.  */
 DEFTREECODE (OMP_SIMD, "omp_simd", tcc_statement, 6)
 
+/* OpenMP - #pragma omp distribute [clause1 ... clauseN]
+   Operands like for OMP_FOR.  */
+DEFTREECODE (OMP_DISTRIBUTE, "omp_distribute", tcc_statement, 6)
+
+/* OpenMP - #pragma omp teams [clause1 ... clauseN]
+   Operand 0: OMP_TEAMS_BODY: Teams body.
+   Operand 1: OMP_TEAMS_CLAUSES: List of clauses.  */
+DEFTREECODE (OMP_TEAMS, "omp_teams", tcc_statement, 2)
+
+/* OpenMP - #pragma omp target data [clause1 ... clauseN]
+   Operand 0: OMP_TARGET_DATA_BODY: Target data construct body.
+   Operand 1: OMP_TARGET_DATA_CLAUSES: List of clauses.  */
+DEFTREECODE (OMP_TARGET_DATA, "omp_target_data", tcc_statement, 2)
+
+/* OpenMP - #pragma omp target [clause1 ... clauseN]
+   Operand 0: OMP_TARGET_BODY: Target construct body.
+   Operand 1: OMP_TARGET_CLAUSES: List of clauses.  */
+DEFTREECODE (OMP_TARGET, "omp_target", tcc_statement, 2)
+
 /* OpenMP - #pragma omp sections [clause1 ... clauseN]
    Operand 0: OMP_SECTIONS_BODY: Sections body.
    Operand 1: OMP_SECTIONS_CLAUSES: List of clauses.  */
@@ -1052,6 +1071,10 @@ DEFTREECODE (OMP_SECTION, "omp_section",
    Operand 0: OMP_MASTER_BODY: Master section body.  */
 DEFTREECODE (OMP_MASTER, "omp_master", tcc_statement, 1)
 
+/* OpenMP - #pragma omp taskgroup
+   Operand 0: OMP_TASKGROUP_BODY: Taskgroup body.  */
+DEFTREECODE (OMP_TASKGROUP, "omp_taskgroup", tcc_statement, 1)
+
 /* OpenMP - #pragma omp ordered
    Operand 0: OMP_ORDERED_BODY: Master section body.  */
 DEFTREECODE (OMP_ORDERED, "omp_ordered", tcc_statement, 1)
@@ -1061,6 +1084,13 @@ DEFTREECODE (OMP_ORDERED, "omp_ordered",
    Operand 1: OMP_CRITICAL_NAME: Identifier for critical section.  */
 DEFTREECODE (OMP_CRITICAL, "omp_critical", tcc_statement, 2)
 
+/* OpenMP - #pragma omp target update [clause1 ... clauseN]
+   Operand 0: OMP_TARGET_UPDATE_CLAUSES: List of clauses.  */
+DEFTREECODE (OMP_TARGET_UPDATE, "omp_target_update", tcc_statement, 1)
+
+/* OMP_ATOMIC through OMP_ATOMIC_CAPTURE_NEW must be consecutive,
+   or OMP_ATOMIC_SEQ_CST needs adjusting.  */
+
 /* OpenMP - #pragma omp atomic
    Operand 0: The address at which the atomic operation is to be performed.
 	This address should be stabilized with save_expr.
--- gcc/tree.h	(.../trunk)	(revision 203241)
+++ gcc/tree.h	(.../branches/gomp-4_0-branch)	(revision 203287)
@@ -1167,12 +1167,13 @@ extern void protected_set_expr_location
 #define OMP_TASKREG_BODY(NODE)    TREE_OPERAND (OMP_TASKREG_CHECK (NODE), 0)
 #define OMP_TASKREG_CLAUSES(NODE) TREE_OPERAND (OMP_TASKREG_CHECK (NODE), 1)
 
-#define OMP_FOR_BODY(NODE)	   TREE_OPERAND (OMP_FOR_CHECK (NODE), 0)
-#define OMP_FOR_CLAUSES(NODE)	   TREE_OPERAND (OMP_FOR_CHECK (NODE), 1)
-#define OMP_FOR_INIT(NODE)	   TREE_OPERAND (OMP_FOR_CHECK (NODE), 2)
-#define OMP_FOR_COND(NODE)	   TREE_OPERAND (OMP_FOR_CHECK (NODE), 3)
-#define OMP_FOR_INCR(NODE)	   TREE_OPERAND (OMP_FOR_CHECK (NODE), 4)
-#define OMP_FOR_PRE_BODY(NODE)	   TREE_OPERAND (OMP_FOR_CHECK (NODE), 5)
+#define OMP_LOOP_CHECK(NODE) TREE_RANGE_CHECK (NODE, OMP_FOR, OMP_DISTRIBUTE)
+#define OMP_FOR_BODY(NODE)	   TREE_OPERAND (OMP_LOOP_CHECK (NODE), 0)
+#define OMP_FOR_CLAUSES(NODE)	   TREE_OPERAND (OMP_LOOP_CHECK (NODE), 1)
+#define OMP_FOR_INIT(NODE)	   TREE_OPERAND (OMP_LOOP_CHECK (NODE), 2)
+#define OMP_FOR_COND(NODE)	   TREE_OPERAND (OMP_LOOP_CHECK (NODE), 3)
+#define OMP_FOR_INCR(NODE)	   TREE_OPERAND (OMP_LOOP_CHECK (NODE), 4)
+#define OMP_FOR_PRE_BODY(NODE)	   TREE_OPERAND (OMP_LOOP_CHECK (NODE), 5)
 
 #define OMP_SECTIONS_BODY(NODE)    TREE_OPERAND (OMP_SECTIONS_CHECK (NODE), 0)
 #define OMP_SECTIONS_CLAUSES(NODE) TREE_OPERAND (OMP_SECTIONS_CHECK (NODE), 1)
@@ -1184,16 +1185,37 @@ extern void protected_set_expr_location
 
 #define OMP_MASTER_BODY(NODE)	   TREE_OPERAND (OMP_MASTER_CHECK (NODE), 0)
 
+#define OMP_TASKGROUP_BODY(NODE)   TREE_OPERAND (OMP_TASKGROUP_CHECK (NODE), 0)
+
 #define OMP_ORDERED_BODY(NODE)	   TREE_OPERAND (OMP_ORDERED_CHECK (NODE), 0)
 
 #define OMP_CRITICAL_BODY(NODE)    TREE_OPERAND (OMP_CRITICAL_CHECK (NODE), 0)
 #define OMP_CRITICAL_NAME(NODE)    TREE_OPERAND (OMP_CRITICAL_CHECK (NODE), 1)
 
+#define OMP_TEAMS_BODY(NODE)	   TREE_OPERAND (OMP_TEAMS_CHECK (NODE), 0)
+#define OMP_TEAMS_CLAUSES(NODE)	   TREE_OPERAND (OMP_TEAMS_CHECK (NODE), 1)
+
+#define OMP_TARGET_DATA_BODY(NODE) \
+  TREE_OPERAND (OMP_TARGET_DATA_CHECK (NODE), 0)
+#define OMP_TARGET_DATA_CLAUSES(NODE)\
+  TREE_OPERAND (OMP_TARGET_DATA_CHECK (NODE), 1)
+
+#define OMP_TARGET_BODY(NODE)	   TREE_OPERAND (OMP_TARGET_CHECK (NODE), 0)
+#define OMP_TARGET_CLAUSES(NODE)   TREE_OPERAND (OMP_TARGET_CHECK (NODE), 1)
+
+#define OMP_TARGET_UPDATE_CLAUSES(NODE)\
+  TREE_OPERAND (OMP_TARGET_UPDATE_CHECK (NODE), 0)
+
+#define OMP_CLAUSE_SIZE(NODE)						\
+  OMP_CLAUSE_OPERAND (OMP_CLAUSE_RANGE_CHECK (OMP_CLAUSE_CHECK (NODE),	\
+					      OMP_CLAUSE_FROM,		\
+					      OMP_CLAUSE_MAP), 1)
+
 #define OMP_CLAUSE_CHAIN(NODE)     TREE_CHAIN (OMP_CLAUSE_CHECK (NODE))
 #define OMP_CLAUSE_DECL(NODE)      					\
   OMP_CLAUSE_OPERAND (OMP_CLAUSE_RANGE_CHECK (OMP_CLAUSE_CHECK (NODE),	\
 					      OMP_CLAUSE_PRIVATE,	\
-	                                      OMP_CLAUSE_UNIFORM), 0)
+					      OMP_CLAUSE__LOOPTEMP_), 0)
 #define OMP_CLAUSE_HAS_LOCATION(NODE) \
   (LOCATION_LOCUS ((OMP_CLAUSE_CHECK (NODE))->omp_clause.locus)		\
   != UNKNOWN_LOCATION)
@@ -1209,6 +1231,12 @@ extern void protected_set_expr_location
 #define OMP_PARALLEL_COMBINED(NODE) \
   (OMP_PARALLEL_CHECK (NODE)->base.private_flag)
 
+/* True if OMP_ATOMIC* is supposed to be sequentially consistent
+   as opposed to relaxed.  */
+#define OMP_ATOMIC_SEQ_CST(NODE) \
+  (TREE_RANGE_CHECK (NODE, OMP_ATOMIC, \
+		     OMP_ATOMIC_CAPTURE_NEW)->base.private_flag)
+
 /* True on a PRIVATE clause if its decl is kept around for debugging
    information only and its DECL_VALUE_EXPR is supposed to point
    to what it has been remapped to.  */
@@ -1240,6 +1268,21 @@ extern void protected_set_expr_location
 #define OMP_CLAUSE_SCHEDULE_CHUNK_EXPR(NODE) \
   OMP_CLAUSE_OPERAND (OMP_CLAUSE_SUBCODE_CHECK (NODE, OMP_CLAUSE_SCHEDULE), 0)
 
+#define OMP_CLAUSE_DEPEND_KIND(NODE) \
+  (OMP_CLAUSE_SUBCODE_CHECK (NODE, OMP_CLAUSE_DEPEND)->omp_clause.subcode.depend_kind)
+
+#define OMP_CLAUSE_MAP_KIND(NODE) \
+  (OMP_CLAUSE_SUBCODE_CHECK (NODE, OMP_CLAUSE_MAP)->omp_clause.subcode.map_kind)
+
+/* Nonzero if this map clause is for array (rather than pointer) based array
+   section with zero bias.  Both the non-decl OMP_CLAUSE_MAP and
+   correspoidng OMP_CLAUSE_MAP_POINTER clause are marked with this flag.  */
+#define OMP_CLAUSE_MAP_ZERO_BIAS_ARRAY_SECTION(NODE) \
+  (OMP_CLAUSE_SUBCODE_CHECK (NODE, OMP_CLAUSE_MAP)->base.public_flag)
+
+#define OMP_CLAUSE_PROC_BIND_KIND(NODE) \
+  (OMP_CLAUSE_SUBCODE_CHECK (NODE, OMP_CLAUSE_PROC_BIND)->omp_clause.subcode.proc_bind_kind)
+
 #define OMP_CLAUSE_COLLAPSE_EXPR(NODE) \
   OMP_CLAUSE_OPERAND (OMP_CLAUSE_SUBCODE_CHECK (NODE, OMP_CLAUSE_COLLAPSE), 0)
 #define OMP_CLAUSE_COLLAPSE_ITERVAR(NODE) \
@@ -1260,6 +1303,11 @@ extern void protected_set_expr_location
 #define OMP_CLAUSE_REDUCTION_PLACEHOLDER(NODE) \
   OMP_CLAUSE_OPERAND (OMP_CLAUSE_SUBCODE_CHECK (NODE, OMP_CLAUSE_REDUCTION), 3)
 
+/* True if a REDUCTION clause may reference the original list item (omp_orig)
+   in its OMP_CLAUSE_REDUCTION_{,GIMPLE_}INIT.  */
+#define OMP_CLAUSE_REDUCTION_OMP_ORIG_REF(NODE) \
+  (OMP_CLAUSE_SUBCODE_CHECK (NODE, OMP_CLAUSE_REDUCTION)->base.public_flag)
+
 /* True if a LINEAR clause doesn't need copy in.  True for iterator vars which
    are always initialized inside of the loop construct, false otherwise.  */
 #define OMP_CLAUSE_LINEAR_NO_COPYIN(NODE) \
@@ -1273,9 +1321,29 @@ extern void protected_set_expr_location
 #define OMP_CLAUSE_LINEAR_STEP(NODE) \
   OMP_CLAUSE_OPERAND (OMP_CLAUSE_SUBCODE_CHECK (NODE, OMP_CLAUSE_LINEAR), 1)
 
+#define OMP_CLAUSE_ALIGNED_ALIGNMENT(NODE) \
+  OMP_CLAUSE_OPERAND (OMP_CLAUSE_SUBCODE_CHECK (NODE, OMP_CLAUSE_ALIGNED), 1)
+
+#define OMP_CLAUSE_NUM_TEAMS_EXPR(NODE) \
+  OMP_CLAUSE_OPERAND (OMP_CLAUSE_SUBCODE_CHECK (NODE, OMP_CLAUSE_NUM_TEAMS), 0)
+
+#define OMP_CLAUSE_THREAD_LIMIT_EXPR(NODE) \
+  OMP_CLAUSE_OPERAND (OMP_CLAUSE_SUBCODE_CHECK (NODE, \
+						OMP_CLAUSE_THREAD_LIMIT), 0)
+
+#define OMP_CLAUSE_DEVICE_ID(NODE) \
+  OMP_CLAUSE_OPERAND (OMP_CLAUSE_SUBCODE_CHECK (NODE, OMP_CLAUSE_DEVICE), 0)
+
+#define OMP_CLAUSE_DIST_SCHEDULE_CHUNK_EXPR(NODE) \
+  OMP_CLAUSE_OPERAND (OMP_CLAUSE_SUBCODE_CHECK (NODE, \
+						OMP_CLAUSE_DIST_SCHEDULE), 0)
+
 #define OMP_CLAUSE_SAFELEN_EXPR(NODE) \
   OMP_CLAUSE_OPERAND (OMP_CLAUSE_SUBCODE_CHECK (NODE, OMP_CLAUSE_SAFELEN), 0)
 
+#define OMP_CLAUSE_SIMDLEN_EXPR(NODE) \
+  OMP_CLAUSE_OPERAND (OMP_CLAUSE_SUBCODE_CHECK (NODE, OMP_CLAUSE_SIMDLEN), 0)
+
 #define OMP_CLAUSE__SIMDUID__DECL(NODE) \
   OMP_CLAUSE_OPERAND (OMP_CLAUSE_SUBCODE_CHECK (NODE, OMP_CLAUSE__SIMDUID_), 0)
 
@@ -3624,6 +3692,9 @@ extern tree build_type_attribute_variant
 extern tree build_decl_attribute_variant (tree, tree);
 extern tree build_type_attribute_qual_variant (tree, tree, int);
 
+/* Remove redundant "omp declare simd" attributes from fndecl.  */
+extern void omp_remove_redundant_declare_simd_attrs (tree);
+
 /* Return 0 if the attributes for two types are incompatible, 1 if they
    are compatible, and 2 if they are nearly compatible (which causes a
    warning to be generated).  */

	Jakub



More information about the Gcc-patches mailing list