insn-notes.def $(INPUT_H) $(REAL_H) statistics.h $(VEC_H) \
$(FIXED_VALUE_H) alias.h $(HASHTAB_H)
FIXED_VALUE_H = fixed-value.h $(MACHMODE_H) double-int.h
-RTL_H = $(RTL_BASE_H) $(FLAGS_H) genrtl.h
+RTL_H = $(RTL_BASE_H) $(FLAGS_H) genrtl.h wide-int.h
- RTL_ERROR_H = rtl-error.h $(RTL_H) $(DIAGNOSTIC_CORE_H)
READ_MD_H = $(OBSTACK_H) $(HASHTAB_H) read-md.h
PARAMS_H = params.h params.def
BUILTINS_DEF = builtins.def sync-builtins.def omp-builtins.def \
EXPR_H = expr.h insn-config.h $(FUNCTION_H) $(RTL_H) $(FLAGS_H) $(TREE_H) $(MACHMODE_H) $(EMIT_RTL_H)
OPTABS_H = optabs.h insn-codes.h insn-opinit.h
REGS_H = regs.h $(MACHMODE_H) hard-reg-set.h
- SCHED_INT_H = sched-int.h $(INSN_ATTR_H) $(BASIC_BLOCK_H) $(RTL_H) $(DF_H) \
- $(REGSET_H)
- SEL_SCHED_IR_H = sel-sched-ir.h $(INSN_ATTR_H) $(BASIC_BLOCK_H) $(RTL_H) \
- $(GGC_H) $(BITMAP_H) $(SCHED_INT_H) $(CFGLOOP_H) $(REGSET_H)
- SEL_SCHED_DUMP_H = sel-sched-dump.h $(SEL_SCHED_IR_H)
-CFGLOOP_H = cfgloop.h $(BASIC_BLOCK_H) double-int.h \
+CFGLOOP_H = cfgloop.h $(BASIC_BLOCK_H) double-int.h wide-int.h \
$(BITMAP_H) sbitmap.h
IPA_UTILS_H = ipa-utils.h $(TREE_H) $(CGRAPH_H)
IPA_REFERENCE_H = ipa-reference.h $(BITMAP_H) $(TREE_H)
INSN_ATTR_H = insn-attr.h insn-attr-common.h $(INSN_ADDR_H)
INSN_ADDR_H = $(srcdir)/insn-addr.h
C_COMMON_H = c-family/c-common.h c-family/c-common.def $(TREE_H) \
- $(SPLAY_TREE_H) $(CPPLIB_H) $(GGC_H) $(DIAGNOSTIC_CORE_H)
+ $(SPLAY_TREE_H) $(CPPLIB_H) $(GGC_H) $(DIAGNOSTIC_CORE_H) wide-int.h
C_PRAGMA_H = c-family/c-pragma.h $(CPPLIB_H)
- C_TREE_H = c-tree.h $(C_COMMON_H) $(DIAGNOSTIC_H)
+ C_TREE_H = c/c-tree.h $(C_COMMON_H) $(DIAGNOSTIC_H)
SYSTEM_H = system.h hwint.h $(srcdir)/../include/libiberty.h \
$(srcdir)/../include/safe-ctype.h $(srcdir)/../include/filenames.h
PREDICT_H = predict.h predict.def
TREE_FLOW_H = tree-flow.h tree-flow-inline.h tree-ssa-operands.h \
$(BITMAP_H) sbitmap.h $(BASIC_BLOCK_H) $(GIMPLE_H) \
$(HASHTAB_H) $(CGRAPH_H) $(IPA_REFERENCE_H) \
- tree-ssa-alias.h
+ tree-ssa-alias.h wide-int.h
TREE_SSA_H = tree-ssa.h $(TREE_FLOW_H)
- TREE_HASHER_H = tree-hasher.h $(HASH_TABLE_H) $(TREE_FLOW_H)
- TREE_SSA_LIVE_H = tree-ssa-live.h $(PARTITION_H)
- SSAEXPAND_H = ssaexpand.h $(TREE_SSA_LIVE_H)
PRETTY_PRINT_H = pretty-print.h $(INPUT_H) $(OBSTACK_H)
TREE_PRETTY_PRINT_H = tree-pretty-print.h $(PRETTY_PRINT_H)
GIMPLE_PRETTY_PRINT_H = gimple-pretty-print.h $(TREE_PRETTY_PRINT_H)
DIAGNOSTIC_CORE_H = diagnostic-core.h $(INPUT_H) bversion.h diagnostic.def
DIAGNOSTIC_H = diagnostic.h $(DIAGNOSTIC_CORE_H) $(PRETTY_PRINT_H)
- DWARF2OUT_H = dwarf2out.h $(DWARF2_H) wide-int.h
C_PRETTY_PRINT_H = c-family/c-pretty-print.h $(PRETTY_PRINT_H) \
$(C_COMMON_H) $(TREE_H)
- SCEV_H = tree-scalar-evolution.h $(GGC_H) tree-chrec.h $(PARAMS_H)
- OMEGA_H = omega.h $(PARAMS_H)
- TREE_DATA_REF_H = tree-data-ref.h $(OMEGA_H) graphds.h $(SCEV_H)
TREE_INLINE_H = tree-inline.h
-REAL_H = real.h $(MACHMODE_H)
+REAL_H = real.h $(MACHMODE_H) signop.h
- IRA_INT_H = ira.h ira-int.h $(CFGLOOP_H) alloc-pool.h
- LRA_INT_H = lra.h $(BITMAP_H) $(RECOG_H) $(INSN_ATTR_H) insn-codes.h \
- insn-config.h $(REGS_H) lra-int.h
- DBGCNT_H = dbgcnt.h dbgcnt.def
LTO_STREAMER_H = lto-streamer.h $(LINKER_PLUGIN_API_H) $(TARGET_H) \
$(CGRAPH_H) $(VEC_H) $(HASH_TABLE_H) $(TREE_H) $(GIMPLE_H) \
$(GCOV_IO_H) $(DIAGNOSTIC_H) alloc-pool.h pointer-set.h
else
pos = compute_related_constant (curpos, last_pos);
- if (!pos && TREE_CODE (curpos) == MULT_EXPR
+ if (!pos
+ && TREE_CODE (curpos) == MULT_EXPR
- && host_integerp (TREE_OPERAND (curpos, 1), 1))
+ && tree_fits_uhwi_p (TREE_OPERAND (curpos, 1)))
{
tree offset = TREE_OPERAND (curpos, 0);
- align = tree_low_cst (TREE_OPERAND (curpos, 1), 1);
+ align = tree_to_uhwi (TREE_OPERAND (curpos, 1));
-
- /* An offset which is a bitwise AND with a mask increases the
- alignment according to the number of trailing zeros. */
- offset = remove_conversions (offset, true);
- if (TREE_CODE (offset) == BIT_AND_EXPR
- && TREE_CODE (TREE_OPERAND (offset, 1)) == INTEGER_CST)
- {
- unsigned HOST_WIDE_INT mask
- = tree_to_hwi (TREE_OPERAND (offset, 1));
- unsigned int i;
-
- for (i = 0; i < HOST_BITS_PER_WIDE_INT; i++)
- {
- if (mask & 1)
- break;
- mask >>= 1;
- align *= 2;
- }
- }
-
- pos = compute_related_constant (curpos,
- round_up (last_pos, align));
+ align = scale_by_factor_of (offset, align);
+ last_pos = round_up (last_pos, align);
+ pos = compute_related_constant (curpos, last_pos);
}
- else if (!pos && TREE_CODE (curpos) == PLUS_EXPR
- && TREE_CODE (TREE_OPERAND (curpos, 1)) == INTEGER_CST
+ else if (!pos
+ && TREE_CODE (curpos) == PLUS_EXPR
- && host_integerp (TREE_OPERAND (curpos, 1), 1)
++ && tree_fits_uhwi_p (TREE_OPERAND (curpos, 1))
&& TREE_CODE (TREE_OPERAND (curpos, 0)) == MULT_EXPR
- && tree_fits_uhwi_p (TREE_OPERAND
- (TREE_OPERAND (curpos, 0), 1)))
- && host_integerp
- (TREE_OPERAND (TREE_OPERAND (curpos, 0), 1), 1))
++ && tree_fits_uhwi_p
++ (TREE_OPERAND (TREE_OPERAND (curpos, 0), 1)))
{
- = tree_low_cst (TREE_OPERAND (curpos, 1), 1);
+ tree offset = TREE_OPERAND (TREE_OPERAND (curpos, 0), 0);
+ unsigned HOST_WIDE_INT addend
++ = tree_to_uhwi (TREE_OPERAND (curpos, 1));
align
- = tree_to_uhwi
- (TREE_OPERAND (TREE_OPERAND (curpos, 0), 1));
- pos = compute_related_constant (curpos,
- round_up (last_pos, align));
- = tree_low_cst (TREE_OPERAND (TREE_OPERAND (curpos, 0), 1), 1);
++ = tree_to_uhwi (TREE_OPERAND (TREE_OPERAND (curpos, 0), 1));
+ align = scale_by_factor_of (offset, align);
+ align = MIN (align, addend & -addend);
+ last_pos = round_up (last_pos, align);
+ pos = compute_related_constant (curpos, last_pos);
}
- else if (potential_alignment_gap (prev_old_field, old_field,
- pos))
+ else if (potential_alignment_gap (prev_old_field, old_field, pos))
{
align = TYPE_ALIGN (field_type);
- pos = compute_related_constant (curpos,
- round_up (last_pos, align));
+ last_pos = round_up (last_pos, align);
+ pos = compute_related_constant (curpos, last_pos);
}
/* If we can't compute a position, set it to zero.
return false;
}
- unsigned HOST_WIDE_INT mask = TREE_INT_CST_LOW (TREE_OPERAND (expr, 1));
+ /* Return VALUE scaled by the biggest power-of-2 factor of EXPR. */
+
+ static unsigned int
+ scale_by_factor_of (tree expr, unsigned int value)
+ {
+ expr = remove_conversions (expr, true);
+
+ /* An expression which is a bitwise AND with a mask has a power-of-2 factor
+ corresponding to the number of trailing zeros of the mask. */
+ if (TREE_CODE (expr) == BIT_AND_EXPR
+ && TREE_CODE (TREE_OPERAND (expr, 1)) == INTEGER_CST)
+ {
++ unsigned HOST_WIDE_INT mask = tree_to_hwi (TREE_OPERAND (expr, 1));
+ unsigned int i = 0;
+
+ while ((mask & 1) == 0 && i < HOST_BITS_PER_WIDE_INT)
+ {
+ mask >>= 1;
+ value *= 2;
+ i++;
+ }
+ }
+
+ return value;
+ }
+
/* Given two consecutive field decls PREV_FIELD and CURR_FIELD, return true
unless we can prove these 2 fields are laid out in such a way that no gap
exist between the end of PREV_FIELD and the beginning of CURR_FIELD. OFFSET
}
}
- int c = tree_low_cst (OMP_CLAUSE_DECL (a), 0);
- int d = tree_low_cst (OMP_CLAUSE_DECL (b), 0);
+
+ /* 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 idx = tree_low_cst (OMP_CLAUSE_DECL (c), 0), i;
++ int c = tree_to_shwi (OMP_CLAUSE_DECL (a));
++ int d = tree_to_shwi (OMP_CLAUSE_DECL (b));
+ 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_to_shwi (OMP_CLAUSE_DECL (c)), 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
-mv c/*$(objext) stageprofile/c
c.stagefeedback: stagefeedback-start
-mv c/*$(objext) stagefeedback/c
-
- #\f
- # .o: .h dependencies.
- # C language specific files.
- C_TREE_H = c/c-tree.h $(C_COMMON_H) $(DIAGNOSTIC_H)
- c/c-aux-info.o : c/c-aux-info.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) \
- $(C_TREE_H) $(TREE_H) $(FLAGS_H)
-
- c/c-convert.o : c/c-convert.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) \
- $(TREE_H) $(C_TREE_H) $(FLAGS_H) $(C_COMMON_H) convert.h \
- langhooks.h $(TARGET_H)
-
- c/c-decl.o : c/c-decl.c c/c-lang.h $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) \
- $(TREE_H) $(C_TREE_H) $(GGC_H) $(TARGET_H) $(FLAGS_H) $(FUNCTION_H) \
- output.h debug.h toplev.h intl.h $(TM_P_H) $(TREE_INLINE_H) \
- $(TIMEVAR_H) $(OPTS_H) $(C_PRAGMA_H) gt-c-c-decl.h $(CGRAPH_H) \
- $(HASH_TABLE_H) $(LANGHOOKS_DEF_H) \
- dumpfile.h $(C_COMMON_H) $(CPPLIB_H) $(DIAGNOSTIC_CORE_H) \
- $(INPUT_H) langhooks.h pointer-set.h tree-iterator.h \
- $(PLUGIN_H) c-family/c-ada-spec.h c-family/c-objc.h
-
- c/c-errors.o: c/c-errors.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(TREE_H) \
- $(C_TREE_H) $(FLAGS_H) $(DIAGNOSTIC_H) $(TM_P_H)
-
- c/c-lang.o : c/c-lang.c c/c-objc-common.h \
- $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(TREE_H) \
- $(C_TREE_H) $(DIAGNOSTIC_CORE_H) \
- langhooks.h $(LANGHOOKS_DEF_H) $(C_COMMON_H) gtype-c.h \
- $(C_PRAGMA_H) $(TREE_INLINE_H)
-
- c/c-objc-common.o : c/c-objc-common.c c/c-objc-common.h \
- $(CONFIG_H) $(SYSTEM_H) coretypes.h \
- $(TREE_H) $(C_TREE_H) $(FLAGS_H) $(DIAGNOSTIC_H) \
- langhooks.h $(GGC_H) $(C_PRETTY_PRINT_H) intl.h \
- $(TREE_PRETTY_PRINT_H)
-
- c/c-parser.o : c/c-parser.c $(CONFIG_H) $(SYSTEM_H) coretypes.h \
- $(TM_H) $(TREE_H) $(C_TREE_H) $(C_COMMON_H) $(C_PRAGMA_H) $(CPPLIB_H) \
- $(GGC_H) $(TIMEVAR_H) $(INPUT_H) $(FLAGS_H) \
- gt-c-c-parser.h langhooks.h \
- $(VEC_H) $(TARGET_H) $(CGRAPH_H) $(PLUGIN_H) \
- c-family/c-objc.h
-
- c/c-typeck.o : c/c-typeck.c c/c-lang.h $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) \
- $(TREE_H) $(C_TREE_H) $(TARGET_H) $(FLAGS_H) intl.h \
- langhooks.h tree-iterator.h $(BITMAP_H) $(GIMPLE_H) \
- c-family/c-objc.h c-family/c-common.h wide-int.h
-
- c/c-array-notation.o: c/c-array-notation.c c/c-lang.h $(CONFIG_H) \
- $(SYSTEM_H) coretypes.h $(TREE_H) $(C_TREE_H) $(TARGET_H) \
- intl.h output.h $(EXPR_H) langhooks.h tree-iterator.h $(BITMAP_H) \
- $(GIMPLE_H) c-family/c-objc.h
--
}
if (num == error_mark_node)
return list;
+ mark_exp_read (num);
+ num = c_fully_fold (num, false, NULL);
if (!INTEGRAL_TYPE_P (TREE_TYPE (num))
- || !host_integerp (num, 0)
- || (n = tree_low_cst (num, 0)) <= 0
+ || !tree_fits_shwi_p (num)
+ || (n = tree_to_shwi (num)) <= 0
|| (int) n != n)
{
error_at (loc,
if (c_parser_next_token_is (parser, CPP_NAME))
{
const char *p = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value);
-
- if (!strcmp (p, "read"))
- code = OMP_ATOMIC_READ;
- else if (!strcmp (p, "write"))
- code = NOP_EXPR;
- else if (!strcmp (p, "update"))
- code = OMP_ATOMIC;
- else if (!strcmp (p, "capture"))
- code = OMP_ATOMIC_CAPTURE_NEW;
+ if (strcmp ("in", p) == 0)
+ kind = OMP_CLAUSE_DEPEND_IN;
+ else if (strcmp ("inout", p) == 0)
+ kind = OMP_CLAUSE_DEPEND_INOUT;
+ else if (strcmp ("out", p) == 0)
+ kind = OMP_CLAUSE_DEPEND_OUT;
else
- p = NULL;
- if (p)
- c_parser_consume_token (parser);
+ goto invalid_kind;
}
- c_parser_skip_to_pragma_eol (parser);
+ else
+ goto invalid_kind;
- switch (code)
+ c_parser_consume_token (parser);
+ if (!c_parser_require (parser, CPP_COLON, "expected %<:%>"))
+ goto resync_fail;
+
+ nl = c_parser_omp_variable_list (parser, clause_loc,
+ OMP_CLAUSE_DEPEND, list);
+
+ for (c = nl; c != list; c = OMP_CLAUSE_CHAIN (c))
+ OMP_CLAUSE_DEPEND_KIND (c) = kind;
+
+ c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>");
+ return nl;
+
+ invalid_kind:
+ c_parser_error (parser, "invalid depend kind");
+ resync_fail:
+ c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>");
+ return list;
+ }
+
+ /* OpenMP 4.0:
+ map ( map-kind: variable-list )
+ map ( variable-list )
+
+ map-kind:
+ alloc | to | from | tofrom */
+
+ static tree
+ c_parser_omp_clause_map (c_parser *parser, tree list)
+ {
+ location_t clause_loc = c_parser_peek_token (parser)->location;
+ enum omp_clause_map_kind kind = OMP_CLAUSE_MAP_TOFROM;
+ tree nl, c;
+
+ if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>"))
+ return list;
+
+ if (c_parser_next_token_is (parser, CPP_NAME)
+ && c_parser_peek_2nd_token (parser)->type == CPP_COLON)
{
- case OMP_ATOMIC_READ:
- case NOP_EXPR: /* atomic write */
- v = c_parser_unary_expression (parser).value;
- v = c_fully_fold (v, false, NULL);
- if (v == error_mark_node)
- goto saw_error;
- loc = c_parser_peek_token (parser)->location;
- if (!c_parser_require (parser, CPP_EQ, "expected %<=%>"))
- goto saw_error;
- if (code == NOP_EXPR)
- lhs = c_parser_expression (parser).value;
- else
- lhs = c_parser_unary_expression (parser).value;
- lhs = c_fully_fold (lhs, false, NULL);
- if (lhs == error_mark_node)
- goto saw_error;
- if (code == NOP_EXPR)
- {
- /* atomic write is represented by OMP_ATOMIC with NOP_EXPR
- opcode. */
- code = OMP_ATOMIC;
- rhs = lhs;
- lhs = v;
- v = NULL_TREE;
- }
- goto done;
- case OMP_ATOMIC_CAPTURE_NEW:
- if (c_parser_next_token_is (parser, CPP_OPEN_BRACE))
- {
- c_parser_consume_token (parser);
- structured_block = true;
- }
+ const char *p = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value);
+ if (strcmp ("alloc", p) == 0)
+ kind = OMP_CLAUSE_MAP_ALLOC;
+ else if (strcmp ("to", p) == 0)
+ kind = OMP_CLAUSE_MAP_TO;
+ else if (strcmp ("from", p) == 0)
+ kind = OMP_CLAUSE_MAP_FROM;
+ else if (strcmp ("tofrom", p) == 0)
+ kind = OMP_CLAUSE_MAP_TOFROM;
else
{
- v = c_parser_unary_expression (parser).value;
- v = c_fully_fold (v, false, NULL);
- if (v == error_mark_node)
- goto saw_error;
- if (!c_parser_require (parser, CPP_EQ, "expected %<=%>"))
- goto saw_error;
+ c_parser_error (parser, "invalid map kind");
+ c_parser_skip_until_found (parser, CPP_CLOSE_PAREN,
+ "expected %<)%>");
+ return list;
}
- break;
- default:
- break;
+ c_parser_consume_token (parser);
+ c_parser_consume_token (parser);
}
- /* For structured_block case we don't know yet whether
- old or new x should be captured. */
- restart:
- lhs = c_parser_unary_expression (parser).value;
- lhs = c_fully_fold (lhs, false, NULL);
- orig_lhs = lhs;
- switch (TREE_CODE (lhs))
+ nl = c_parser_omp_variable_list (parser, clause_loc, OMP_CLAUSE_MAP, list);
+
+ for (c = nl; c != list; c = OMP_CLAUSE_CHAIN (c))
+ OMP_CLAUSE_MAP_KIND (c) = kind;
+
+ c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>");
+ return nl;
+ }
+
+ /* OpenMP 4.0:
+ device ( expression ) */
+
+ static tree
+ c_parser_omp_clause_device (c_parser *parser, tree list)
+ {
+ location_t clause_loc = c_parser_peek_token (parser)->location;
+ if (c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>"))
{
- case ERROR_MARK:
- saw_error:
- c_parser_skip_to_end_of_block_or_statement (parser);
- if (structured_block)
+ tree c, t = c_parser_expr_no_commas (parser, NULL).value;
+ mark_exp_read (t);
+ t = c_fully_fold (t, false, NULL);
+
+ c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>");
+
+ if (!INTEGRAL_TYPE_P (TREE_TYPE (t)))
{
- if (c_parser_next_token_is (parser, CPP_CLOSE_BRACE))
- c_parser_consume_token (parser);
- else if (code == OMP_ATOMIC_CAPTURE_NEW)
- {
- c_parser_skip_to_end_of_block_or_statement (parser);
- if (c_parser_next_token_is (parser, CPP_CLOSE_BRACE))
- c_parser_consume_token (parser);
- }
+ c_parser_error (parser, "expected integer expression");
+ return list;
}
- return;
- case POSTINCREMENT_EXPR:
- if (code == OMP_ATOMIC_CAPTURE_NEW && !structured_block)
- code = OMP_ATOMIC_CAPTURE_OLD;
- /* FALLTHROUGH */
- case PREINCREMENT_EXPR:
- lhs = TREE_OPERAND (lhs, 0);
- opcode = PLUS_EXPR;
- rhs = integer_one_node;
- break;
+ check_no_duplicate_clause (list, OMP_CLAUSE_DEVICE, "device");
- case POSTDECREMENT_EXPR:
- if (code == OMP_ATOMIC_CAPTURE_NEW && !structured_block)
- code = OMP_ATOMIC_CAPTURE_OLD;
- /* FALLTHROUGH */
- case PREDECREMENT_EXPR:
- lhs = TREE_OPERAND (lhs, 0);
- opcode = MINUS_EXPR;
- rhs = integer_one_node;
- break;
+ c = build_omp_clause (clause_loc, OMP_CLAUSE_DEVICE);
+ OMP_CLAUSE_DEVICE_ID (c) = t;
+ OMP_CLAUSE_CHAIN (c) = list;
+ list = c;
+ }
- case COMPOUND_EXPR:
- if (TREE_CODE (TREE_OPERAND (lhs, 0)) == SAVE_EXPR
- && TREE_CODE (TREE_OPERAND (lhs, 1)) == COMPOUND_EXPR
- && TREE_CODE (TREE_OPERAND (TREE_OPERAND (lhs, 1), 0)) == MODIFY_EXPR
- && TREE_OPERAND (TREE_OPERAND (lhs, 1), 1) == TREE_OPERAND (lhs, 0)
- && TREE_CODE (TREE_TYPE (TREE_OPERAND (TREE_OPERAND
- (TREE_OPERAND (lhs, 1), 0), 0)))
- == BOOLEAN_TYPE)
- /* Undo effects of boolean_increment for post {in,de}crement. */
- lhs = TREE_OPERAND (TREE_OPERAND (lhs, 1), 0);
- /* FALLTHRU */
- case MODIFY_EXPR:
- if (TREE_CODE (lhs) == MODIFY_EXPR
- && TREE_CODE (TREE_TYPE (TREE_OPERAND (lhs, 0))) == BOOLEAN_TYPE)
- {
- /* Undo effects of boolean_increment. */
- if (integer_onep (TREE_OPERAND (lhs, 1)))
- {
- /* This is pre or post increment. */
- rhs = TREE_OPERAND (lhs, 1);
- lhs = TREE_OPERAND (lhs, 0);
- opcode = NOP_EXPR;
- if (code == OMP_ATOMIC_CAPTURE_NEW
- && !structured_block
- && TREE_CODE (orig_lhs) == COMPOUND_EXPR)
- code = OMP_ATOMIC_CAPTURE_OLD;
- break;
- }
- if (TREE_CODE (TREE_OPERAND (lhs, 1)) == TRUTH_NOT_EXPR
- && TREE_OPERAND (lhs, 0)
- == TREE_OPERAND (TREE_OPERAND (lhs, 1), 0))
- {
- /* This is pre or post decrement. */
- rhs = TREE_OPERAND (lhs, 1);
- lhs = TREE_OPERAND (lhs, 0);
- opcode = NOP_EXPR;
- if (code == OMP_ATOMIC_CAPTURE_NEW
- && !structured_block
- && TREE_CODE (orig_lhs) == COMPOUND_EXPR)
- code = OMP_ATOMIC_CAPTURE_OLD;
- break;
- }
- }
- /* FALLTHRU */
- default:
- switch (c_parser_peek_token (parser)->type)
- {
- case CPP_MULT_EQ:
- opcode = MULT_EXPR;
- break;
- case CPP_DIV_EQ:
- opcode = TRUNC_DIV_EXPR;
- break;
- case CPP_PLUS_EQ:
- opcode = PLUS_EXPR;
- break;
- case CPP_MINUS_EQ:
- opcode = MINUS_EXPR;
- break;
- case CPP_LSHIFT_EQ:
- opcode = LSHIFT_EXPR;
- break;
- case CPP_RSHIFT_EQ:
- opcode = RSHIFT_EXPR;
- break;
- case CPP_AND_EQ:
- opcode = BIT_AND_EXPR;
- break;
- case CPP_OR_EQ:
- opcode = BIT_IOR_EXPR;
- break;
- case CPP_XOR_EQ:
- opcode = BIT_XOR_EXPR;
- break;
- case CPP_EQ:
- if (structured_block || code == OMP_ATOMIC)
- {
- location_t aloc = c_parser_peek_token (parser)->location;
- location_t rhs_loc;
- enum c_parser_prec oprec = PREC_NONE;
+ return list;
+ }
- c_parser_consume_token (parser);
- rhs1 = c_parser_unary_expression (parser).value;
- rhs1 = c_fully_fold (rhs1, false, NULL);
- if (rhs1 == error_mark_node)
- goto saw_error;
- switch (c_parser_peek_token (parser)->type)
- {
- case CPP_SEMICOLON:
- if (code == OMP_ATOMIC_CAPTURE_NEW)
- {
- code = OMP_ATOMIC_CAPTURE_OLD;
- v = lhs;
- lhs = NULL_TREE;
- lhs1 = rhs1;
- rhs1 = NULL_TREE;
- c_parser_consume_token (parser);
- goto restart;
- }
- c_parser_error (parser,
- "invalid form of %<#pragma omp atomic%>");
- goto saw_error;
- case CPP_MULT:
- opcode = MULT_EXPR;
- oprec = PREC_MULT;
- break;
- case CPP_DIV:
- opcode = TRUNC_DIV_EXPR;
- oprec = PREC_MULT;
- break;
- case CPP_PLUS:
- opcode = PLUS_EXPR;
- oprec = PREC_ADD;
- break;
- case CPP_MINUS:
- opcode = MINUS_EXPR;
- oprec = PREC_ADD;
- break;
- case CPP_LSHIFT:
- opcode = LSHIFT_EXPR;
- oprec = PREC_SHIFT;
- break;
- case CPP_RSHIFT:
- opcode = RSHIFT_EXPR;
- oprec = PREC_SHIFT;
- break;
- case CPP_AND:
- opcode = BIT_AND_EXPR;
- oprec = PREC_BITAND;
- break;
- case CPP_OR:
- opcode = BIT_IOR_EXPR;
- oprec = PREC_BITOR;
- break;
- case CPP_XOR:
- opcode = BIT_XOR_EXPR;
- oprec = PREC_BITXOR;
- break;
- default:
- c_parser_error (parser,
- "invalid operator for %<#pragma omp atomic%>");
- goto saw_error;
- }
- loc = aloc;
- c_parser_consume_token (parser);
- rhs_loc = c_parser_peek_token (parser)->location;
- if (commutative_tree_code (opcode))
- oprec = (enum c_parser_prec) (oprec - 1);
- rhs_expr = c_parser_binary_expression (parser, NULL, oprec);
- rhs_expr = default_function_array_read_conversion (rhs_loc,
- rhs_expr);
- rhs = rhs_expr.value;
- rhs = c_fully_fold (rhs, false, NULL);
- goto stmt_done;
- }
- /* FALLTHROUGH */
- default:
- c_parser_error (parser,
- "invalid operator for %<#pragma omp atomic%>");
- goto saw_error;
- }
+ /* OpenMP 4.0:
+ dist_schedule ( static )
+ dist_schedule ( static , expression ) */
- /* Arrange to pass the location of the assignment operator to
- c_finish_omp_atomic. */
- loc = c_parser_peek_token (parser)->location;
- c_parser_consume_token (parser);
- {
- location_t rhs_loc = c_parser_peek_token (parser)->location;
- rhs_expr = c_parser_expression (parser);
- rhs_expr = default_function_array_read_conversion (rhs_loc, rhs_expr);
- }
- rhs = rhs_expr.value;
- rhs = c_fully_fold (rhs, false, NULL);
- break;
- }
- stmt_done:
- if (structured_block && code == OMP_ATOMIC_CAPTURE_NEW)
- {
- if (!c_parser_require (parser, CPP_SEMICOLON, "expected %<;%>"))
- goto saw_error;
- v = c_parser_unary_expression (parser).value;
- v = c_fully_fold (v, false, NULL);
- if (v == error_mark_node)
- goto saw_error;
- if (!c_parser_require (parser, CPP_EQ, "expected %<=%>"))
- goto saw_error;
- lhs1 = c_parser_unary_expression (parser).value;
- lhs1 = c_fully_fold (lhs1, false, NULL);
- if (lhs1 == error_mark_node)
- goto saw_error;
- }
- if (structured_block)
+ static tree
+ c_parser_omp_clause_dist_schedule (c_parser *parser, tree list)
+ {
+ tree c, t = NULL_TREE;
+ location_t loc = c_parser_peek_token (parser)->location;
+
+ if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>"))
+ return list;
+
+ if (!c_parser_next_token_is_keyword (parser, RID_STATIC))
{
- c_parser_skip_until_found (parser, CPP_SEMICOLON, "expected %<;%>");
- c_parser_require (parser, CPP_CLOSE_BRACE, "expected %<}%>");
+ c_parser_error (parser, "invalid dist_schedule kind");
+ c_parser_skip_until_found (parser, CPP_CLOSE_PAREN,
+ "expected %<)%>");
+ return list;
}
- done:
- stmt = c_finish_omp_atomic (loc, code, opcode, lhs, rhs, v, lhs1, rhs1);
- if (stmt != error_mark_node)
- add_stmt (stmt);
-
- if (!structured_block)
- c_parser_skip_until_found (parser, CPP_SEMICOLON, "expected %<;%>");
- }
+ c_parser_consume_token (parser);
+ if (c_parser_next_token_is (parser, CPP_COMMA))
+ {
+ c_parser_consume_token (parser);
- /* OpenMP 2.5:
- # pragma omp barrier new-line
- */
+ t = c_parser_expr_no_commas (parser, NULL).value;
+ mark_exp_read (t);
+ t = c_fully_fold (t, false, NULL);
+ c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>");
+ }
+ else
+ c_parser_skip_until_found (parser, CPP_CLOSE_PAREN,
+ "expected %<,%> or %<)%>");
- static void
- c_parser_omp_barrier (c_parser *parser)
- {
- location_t loc = c_parser_peek_token (parser)->location;
- c_parser_consume_pragma (parser);
- c_parser_skip_to_pragma_eol (parser);
+ check_no_duplicate_clause (list, OMP_CLAUSE_SCHEDULE, "schedule");
+ if (t == error_mark_node)
+ return list;
- c_finish_omp_barrier (loc);
+ c = build_omp_clause (loc, OMP_CLAUSE_DIST_SCHEDULE);
+ OMP_CLAUSE_DIST_SCHEDULE_CHUNK_EXPR (c) = t;
+ OMP_CLAUSE_CHAIN (c) = list;
+ return c;
}
- /* OpenMP 2.5:
- # pragma omp critical [(name)] new-line
- structured-block
+ /* OpenMP 4.0:
+ proc_bind ( proc-bind-kind )
- LOC is the location of the #pragma itself. */
+ proc-bind-kind:
+ master | close | spread */
static tree
- c_parser_omp_critical (location_t loc, c_parser *parser)
+ c_parser_omp_clause_proc_bind (c_parser *parser, tree list)
{
- tree stmt, name = NULL;
+ location_t clause_loc = c_parser_peek_token (parser)->location;
+ enum omp_clause_proc_bind_kind kind;
+ tree c;
- if (c_parser_next_token_is (parser, CPP_OPEN_PAREN))
+ if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>"))
+ return list;
+
+ if (c_parser_next_token_is (parser, CPP_NAME))
{
- c_parser_consume_token (parser);
- if (c_parser_next_token_is (parser, CPP_NAME))
- {
- name = c_parser_peek_token (parser)->value;
- c_parser_consume_token (parser);
- c_parser_require (parser, CPP_CLOSE_PAREN, "expected %<)%>");
- }
+ const char *p = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value);
+ if (strcmp ("master", p) == 0)
+ kind = OMP_CLAUSE_PROC_BIND_MASTER;
+ else if (strcmp ("close", p) == 0)
+ kind = OMP_CLAUSE_PROC_BIND_CLOSE;
+ else if (strcmp ("spread", p) == 0)
+ kind = OMP_CLAUSE_PROC_BIND_SPREAD;
else
- c_parser_error (parser, "expected identifier");
+ goto invalid_kind;
}
- else if (c_parser_next_token_is_not (parser, CPP_PRAGMA_EOL))
- c_parser_error (parser, "expected %<(%> or end of line");
- c_parser_skip_to_pragma_eol (parser);
+ else
+ goto invalid_kind;
- stmt = c_parser_omp_structured_block (parser);
- return c_finish_omp_critical (loc, stmt, name);
- }
+ c_parser_consume_token (parser);
+ c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>");
+ c = build_omp_clause (clause_loc, OMP_CLAUSE_PROC_BIND);
+ OMP_CLAUSE_PROC_BIND_KIND (c) = kind;
+ OMP_CLAUSE_CHAIN (c) = list;
+ return c;
- /* OpenMP 2.5:
- # pragma omp flush flush-vars[opt] new-line
+ invalid_kind:
+ c_parser_error (parser, "invalid proc_bind kind");
+ c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>");
+ return list;
+ }
- flush-vars:
- ( variable-list ) */
+ /* OpenMP 4.0:
+ to ( variable-list ) */
- static void
- c_parser_omp_flush (c_parser *parser)
+ static tree
+ c_parser_omp_clause_to (c_parser *parser, tree list)
{
- location_t loc = c_parser_peek_token (parser)->location;
- c_parser_consume_pragma (parser);
- if (c_parser_next_token_is (parser, CPP_OPEN_PAREN))
- c_parser_omp_var_list_parens (parser, OMP_CLAUSE_ERROR, NULL);
- else if (c_parser_next_token_is_not (parser, CPP_PRAGMA_EOL))
- c_parser_error (parser, "expected %<(%> or end of line");
- c_parser_skip_to_pragma_eol (parser);
-
- c_finish_omp_flush (loc);
+ return c_parser_omp_var_list_parens (parser, OMP_CLAUSE_TO, list);
}
- /* Parse the restricted form of the for statement allowed by OpenMP.
- The real trick here is to determine the loop control variable early
- so that we can push a new decl if necessary to make it private.
- LOC is the location of the OMP in "#pragma omp". */
+ /* OpenMP 4.0:
+ from ( variable-list ) */
static tree
- c_parser_omp_for_loop (location_t loc,
- c_parser *parser, tree clauses, tree *par_clauses)
+ c_parser_omp_clause_from (c_parser *parser, tree list)
{
- tree decl, cond, incr, save_break, save_cont, body, init, stmt, cl;
- tree declv, condv, incrv, initv, ret = NULL;
- bool fail = false, open_brace_parsed = false;
- int i, collapse = 1, nbraces = 0;
- location_t for_loc;
- vec<tree, va_gc> *for_block = make_tree_vector ();
-
- for (cl = clauses; cl; cl = OMP_CLAUSE_CHAIN (cl))
- if (OMP_CLAUSE_CODE (cl) == OMP_CLAUSE_COLLAPSE)
- collapse = tree_to_shwi (OMP_CLAUSE_COLLAPSE_EXPR (cl));
+ return c_parser_omp_var_list_parens (parser, OMP_CLAUSE_FROM, list);
+ }
- gcc_assert (collapse >= 1);
+ /* OpenMP 4.0:
+ uniform ( variable-list ) */
- declv = make_tree_vec (collapse);
- initv = make_tree_vec (collapse);
- condv = make_tree_vec (collapse);
- incrv = make_tree_vec (collapse);
+ static tree
+ c_parser_omp_clause_uniform (c_parser *parser, tree list)
+ {
+ /* The clauses location. */
+ location_t loc = c_parser_peek_token (parser)->location;
- if (!c_parser_next_token_is_keyword (parser, RID_FOR))
+ if (c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>"))
{
- c_parser_error (parser, "for statement expected");
- return NULL;
+ list = c_parser_omp_variable_list (parser, loc, OMP_CLAUSE_UNIFORM,
+ list);
+ c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>");
}
- for_loc = c_parser_peek_token (parser)->location;
- c_parser_consume_token (parser);
+ return list;
+ }
- for (i = 0; i < collapse; i++)
- {
- int bracecount = 0;
+ /* Parse all OpenMP clauses. The set clauses allowed by the directive
+ is a bitmask in MASK. Return the list of clauses found; the result
+ of clause default goes in *pdefault. */
- if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>"))
- goto pop_scopes;
+ static tree
+ c_parser_omp_all_clauses (c_parser *parser, omp_clause_mask mask,
+ const char *where, bool finish_p = true)
+ {
+ tree clauses = NULL;
+ bool first = true;
- /* Parse the initialization declaration or expression. */
- if (c_parser_next_tokens_start_declaration (parser))
+ while (c_parser_next_token_is_not (parser, CPP_PRAGMA_EOL))
+ {
+ location_t here;
+ pragma_omp_clause c_kind;
+ const char *c_name;
+ tree prev = clauses;
+
+ if (!first && c_parser_next_token_is (parser, CPP_COMMA))
+ c_parser_consume_token (parser);
+
+ here = c_parser_peek_token (parser)->location;
+ c_kind = c_parser_omp_clause_name (parser);
+
+ switch (c_kind)
{
- if (i > 0)
- vec_safe_push (for_block, c_begin_compound_stmt (true));
- c_parser_declaration_or_fndef (parser, true, true, true, true, true, NULL);
- decl = check_for_loop_decls (for_loc, flag_isoc99);
- if (decl == NULL)
- goto error_init;
- if (DECL_INITIAL (decl) == error_mark_node)
- decl = error_mark_node;
- init = decl;
+ case PRAGMA_OMP_CLAUSE_COLLAPSE:
+ clauses = c_parser_omp_clause_collapse (parser, clauses);
+ c_name = "collapse";
+ break;
+ case PRAGMA_OMP_CLAUSE_COPYIN:
+ clauses = c_parser_omp_clause_copyin (parser, clauses);
+ c_name = "copyin";
+ break;
+ case PRAGMA_OMP_CLAUSE_COPYPRIVATE:
+ clauses = c_parser_omp_clause_copyprivate (parser, clauses);
+ c_name = "copyprivate";
+ break;
+ case PRAGMA_OMP_CLAUSE_DEFAULT:
+ clauses = c_parser_omp_clause_default (parser, clauses);
+ c_name = "default";
+ break;
+ case PRAGMA_OMP_CLAUSE_FIRSTPRIVATE:
+ clauses = c_parser_omp_clause_firstprivate (parser, clauses);
+ c_name = "firstprivate";
+ break;
+ case PRAGMA_OMP_CLAUSE_FINAL:
+ clauses = c_parser_omp_clause_final (parser, clauses);
+ c_name = "final";
+ break;
+ case PRAGMA_OMP_CLAUSE_IF:
+ clauses = c_parser_omp_clause_if (parser, clauses);
+ c_name = "if";
+ break;
+ case PRAGMA_OMP_CLAUSE_LASTPRIVATE:
+ clauses = c_parser_omp_clause_lastprivate (parser, clauses);
+ c_name = "lastprivate";
+ break;
+ case PRAGMA_OMP_CLAUSE_MERGEABLE:
+ clauses = c_parser_omp_clause_mergeable (parser, clauses);
+ c_name = "mergeable";
+ break;
+ case PRAGMA_OMP_CLAUSE_NOWAIT:
+ clauses = c_parser_omp_clause_nowait (parser, clauses);
+ c_name = "nowait";
+ break;
+ case PRAGMA_OMP_CLAUSE_NUM_THREADS:
+ clauses = c_parser_omp_clause_num_threads (parser, clauses);
+ c_name = "num_threads";
+ break;
+ case PRAGMA_OMP_CLAUSE_ORDERED:
+ clauses = c_parser_omp_clause_ordered (parser, clauses);
+ c_name = "ordered";
+ break;
+ case PRAGMA_OMP_CLAUSE_PRIVATE:
+ clauses = c_parser_omp_clause_private (parser, clauses);
+ c_name = "private";
+ break;
+ case PRAGMA_OMP_CLAUSE_REDUCTION:
+ clauses = c_parser_omp_clause_reduction (parser, clauses);
+ c_name = "reduction";
+ break;
+ case PRAGMA_OMP_CLAUSE_SCHEDULE:
+ clauses = c_parser_omp_clause_schedule (parser, clauses);
+ c_name = "schedule";
+ break;
+ case PRAGMA_OMP_CLAUSE_SHARED:
+ clauses = c_parser_omp_clause_shared (parser, clauses);
+ c_name = "shared";
+ break;
+ case PRAGMA_OMP_CLAUSE_UNTIED:
+ clauses = c_parser_omp_clause_untied (parser, clauses);
+ c_name = "untied";
+ break;
+ case PRAGMA_OMP_CLAUSE_INBRANCH:
+ clauses = c_parser_omp_clause_branch (parser, OMP_CLAUSE_INBRANCH,
+ clauses);
+ c_name = "inbranch";
+ break;
+ case PRAGMA_OMP_CLAUSE_NOTINBRANCH:
+ clauses = c_parser_omp_clause_branch (parser, OMP_CLAUSE_NOTINBRANCH,
+ clauses);
+ c_name = "notinbranch";
+ break;
+ case PRAGMA_OMP_CLAUSE_PARALLEL:
+ clauses
+ = c_parser_omp_clause_cancelkind (parser, OMP_CLAUSE_PARALLEL,
+ clauses);
+ c_name = "parallel";
+ if (!first)
+ {
+ clause_not_first:
+ error_at (here, "%qs must be the first clause of %qs",
+ c_name, where);
+ clauses = prev;
+ }
+ break;
+ case PRAGMA_OMP_CLAUSE_FOR:
+ clauses
+ = c_parser_omp_clause_cancelkind (parser, OMP_CLAUSE_FOR,
+ clauses);
+ c_name = "for";
+ if (!first)
+ goto clause_not_first;
+ break;
+ case PRAGMA_OMP_CLAUSE_SECTIONS:
+ clauses
+ = c_parser_omp_clause_cancelkind (parser, OMP_CLAUSE_SECTIONS,
+ clauses);
+ c_name = "sections";
+ if (!first)
+ goto clause_not_first;
+ break;
+ case PRAGMA_OMP_CLAUSE_TASKGROUP:
+ clauses
+ = c_parser_omp_clause_cancelkind (parser, OMP_CLAUSE_TASKGROUP,
+ clauses);
+ c_name = "taskgroup";
+ if (!first)
+ goto clause_not_first;
+ break;
+ case PRAGMA_OMP_CLAUSE_TO:
+ clauses = c_parser_omp_clause_to (parser, clauses);
+ c_name = "to";
+ break;
+ case PRAGMA_OMP_CLAUSE_FROM:
+ clauses = c_parser_omp_clause_from (parser, clauses);
+ c_name = "from";
+ break;
+ case PRAGMA_OMP_CLAUSE_UNIFORM:
+ clauses = c_parser_omp_clause_uniform (parser, clauses);
+ c_name = "uniform";
+ break;
+ case PRAGMA_OMP_CLAUSE_NUM_TEAMS:
+ clauses = c_parser_omp_clause_num_teams (parser, clauses);
+ c_name = "num_teams";
+ break;
+ case PRAGMA_OMP_CLAUSE_THREAD_LIMIT:
+ clauses = c_parser_omp_clause_thread_limit (parser, clauses);
+ c_name = "thread_limit";
+ break;
+ case PRAGMA_OMP_CLAUSE_ALIGNED:
+ clauses = c_parser_omp_clause_aligned (parser, clauses);
+ c_name = "aligned";
+ break;
+ case PRAGMA_OMP_CLAUSE_LINEAR:
+ clauses = c_parser_omp_clause_linear (parser, clauses);
+ c_name = "linear";
+ break;
+ case PRAGMA_OMP_CLAUSE_DEPEND:
+ clauses = c_parser_omp_clause_depend (parser, clauses);
+ c_name = "depend";
+ break;
+ case PRAGMA_OMP_CLAUSE_MAP:
+ clauses = c_parser_omp_clause_map (parser, clauses);
+ c_name = "map";
+ break;
+ case PRAGMA_OMP_CLAUSE_DEVICE:
+ clauses = c_parser_omp_clause_device (parser, clauses);
+ c_name = "device";
+ break;
+ case PRAGMA_OMP_CLAUSE_DIST_SCHEDULE:
+ clauses = c_parser_omp_clause_dist_schedule (parser, clauses);
+ c_name = "dist_schedule";
+ break;
+ case PRAGMA_OMP_CLAUSE_PROC_BIND:
+ clauses = c_parser_omp_clause_proc_bind (parser, clauses);
+ c_name = "proc_bind";
+ break;
+ case PRAGMA_OMP_CLAUSE_SAFELEN:
+ clauses = c_parser_omp_clause_safelen (parser, clauses);
+ c_name = "safelen";
+ break;
+ case PRAGMA_OMP_CLAUSE_SIMDLEN:
+ clauses = c_parser_omp_clause_simdlen (parser, clauses);
+ c_name = "simdlen";
+ break;
+ default:
+ c_parser_error (parser, "expected %<#pragma omp%> clause");
+ goto saw_error;
}
- else if (c_parser_next_token_is (parser, CPP_NAME)
- && c_parser_peek_2nd_token (parser)->type == CPP_EQ)
+
+ first = false;
+
+ if (((mask >> c_kind) & 1) == 0 && !parser->error)
{
- struct c_expr decl_exp;
- struct c_expr init_exp;
- location_t init_loc;
+ /* Remove the invalid clause(s) from the list to avoid
+ confusing the rest of the compiler. */
+ clauses = prev;
+ error_at (here, "%qs is not valid for %qs", c_name, where);
+ }
+ }
- decl_exp = c_parser_postfix_expression (parser);
- decl = decl_exp.value;
+ saw_error:
+ c_parser_skip_to_pragma_eol (parser);
- c_parser_require (parser, CPP_EQ, "expected %<=%>");
+ if (finish_p)
+ return c_finish_omp_clauses (clauses);
- init_loc = c_parser_peek_token (parser)->location;
- init_exp = c_parser_expr_no_commas (parser, NULL);
- init_exp = default_function_array_read_conversion (init_loc,
- init_exp);
- init = build_modify_expr (init_loc, decl, decl_exp.original_type,
- NOP_EXPR, init_loc, init_exp.value,
- init_exp.original_type);
- init = c_process_expr_stmt (init_loc, init);
+ return clauses;
+ }
- c_parser_skip_until_found (parser, CPP_SEMICOLON, "expected %<;%>");
- }
+ /* OpenMP 2.5:
+ structured-block:
+ statement
+
+ In practice, we're also interested in adding the statement to an
+ outer node. So it is convenient if we work around the fact that
+ c_parser_statement calls add_stmt. */
+
+ static tree
+ c_parser_omp_structured_block (c_parser *parser)
+ {
+ tree stmt = push_stmt_list ();
+ c_parser_statement (parser);
+ return pop_stmt_list (stmt);
+ }
+
+ /* OpenMP 2.5:
+ # pragma omp atomic new-line
+ expression-stmt
+
+ expression-stmt:
+ x binop= expr | x++ | ++x | x-- | --x
+ binop:
+ +, *, -, /, &, ^, |, <<, >>
+
+ where x is an lvalue expression with scalar type.
+
+ OpenMP 3.1:
+ # pragma omp atomic new-line
+ update-stmt
+
+ # pragma omp atomic read new-line
+ read-stmt
+
+ # pragma omp atomic write new-line
+ write-stmt
+
+ # pragma omp atomic update new-line
+ update-stmt
+
+ # pragma omp atomic capture new-line
+ capture-stmt
+
+ # pragma omp atomic capture new-line
+ capture-block
+
+ read-stmt:
+ v = x
+ write-stmt:
+ x = expr
+ update-stmt:
+ expression-stmt | x = x binop expr
+ capture-stmt:
+ v = expression-stmt
+ capture-block:
+ { v = x; update-stmt; } | { update-stmt; v = x; }
+
+ OpenMP 4.0:
+ update-stmt:
+ expression-stmt | x = x binop expr | x = expr binop x
+ capture-stmt:
+ v = update-stmt
+ capture-block:
+ { v = x; update-stmt; } | { update-stmt; v = x; } | { v = x; x = expr; }
+
+ where x and v are lvalue expressions with scalar type.
+
+ LOC is the location of the #pragma token. */
+
+ static void
+ c_parser_omp_atomic (location_t loc, c_parser *parser)
+ {
+ tree lhs = NULL_TREE, rhs = NULL_TREE, v = NULL_TREE;
+ tree lhs1 = NULL_TREE, rhs1 = NULL_TREE;
+ tree stmt, orig_lhs, unfolded_lhs = NULL_TREE, unfolded_lhs1 = NULL_TREE;
+ enum tree_code code = OMP_ATOMIC, opcode = NOP_EXPR;
+ struct c_expr expr;
+ location_t eloc;
+ bool structured_block = false;
+ bool swapped = false;
+ bool seq_cst = false;
+
+ if (c_parser_next_token_is (parser, CPP_NAME))
+ {
+ const char *p = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value);
+
+ if (!strcmp (p, "read"))
+ code = OMP_ATOMIC_READ;
+ else if (!strcmp (p, "write"))
+ code = NOP_EXPR;
+ else if (!strcmp (p, "update"))
+ code = OMP_ATOMIC;
+ else if (!strcmp (p, "capture"))
+ code = OMP_ATOMIC_CAPTURE_NEW;
else
+ p = NULL;
+ if (p)
+ c_parser_consume_token (parser);
+ }
+ if (c_parser_next_token_is (parser, CPP_NAME))
+ {
+ const char *p = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value);
+ if (!strcmp (p, "seq_cst"))
{
- error_init:
- c_parser_error (parser,
- "expected iteration declaration or initialization");
- c_parser_skip_until_found (parser, CPP_CLOSE_PAREN,
- "expected %<)%>");
- fail = true;
- goto parse_next;
+ seq_cst = true;
+ c_parser_consume_token (parser);
}
- collapse = tree_low_cst (OMP_CLAUSE_COLLAPSE_EXPR (cl), 0);
+ }
+ c_parser_skip_to_pragma_eol (parser);
+
+ switch (code)
+ {
+ case OMP_ATOMIC_READ:
+ case NOP_EXPR: /* atomic write */
+ v = c_parser_unary_expression (parser).value;
+ v = c_fully_fold (v, false, NULL);
+ if (v == error_mark_node)
+ goto saw_error;
+ loc = c_parser_peek_token (parser)->location;
+ if (!c_parser_require (parser, CPP_EQ, "expected %<=%>"))
+ goto saw_error;
+ if (code == NOP_EXPR)
+ lhs = c_parser_expression (parser).value;
+ else
+ lhs = c_parser_unary_expression (parser).value;
+ lhs = c_fully_fold (lhs, false, NULL);
+ if (lhs == error_mark_node)
+ goto saw_error;
+ if (code == NOP_EXPR)
+ {
+ /* atomic write is represented by OMP_ATOMIC with NOP_EXPR
+ opcode. */
+ code = OMP_ATOMIC;
+ rhs = lhs;
+ lhs = v;
+ v = NULL_TREE;
+ }
+ goto done;
+ case OMP_ATOMIC_CAPTURE_NEW:
+ if (c_parser_next_token_is (parser, CPP_OPEN_BRACE))
+ {
+ c_parser_consume_token (parser);
+ structured_block = true;
+ }
+ else
+ {
+ v = c_parser_unary_expression (parser).value;
+ v = c_fully_fold (v, false, NULL);
+ if (v == error_mark_node)
+ goto saw_error;
+ if (!c_parser_require (parser, CPP_EQ, "expected %<=%>"))
+ goto saw_error;
+ }
+ break;
+ default:
+ break;
+ }
+
+ /* For structured_block case we don't know yet whether
+ old or new x should be captured. */
+ restart:
+ eloc = c_parser_peek_token (parser)->location;
+ expr = c_parser_unary_expression (parser);
+ lhs = expr.value;
+ expr = default_function_array_conversion (eloc, expr);
+ unfolded_lhs = expr.value;
+ lhs = c_fully_fold (lhs, false, NULL);
+ orig_lhs = lhs;
+ switch (TREE_CODE (lhs))
+ {
+ case ERROR_MARK:
+ saw_error:
+ c_parser_skip_to_end_of_block_or_statement (parser);
+ if (structured_block)
+ {
+ if (c_parser_next_token_is (parser, CPP_CLOSE_BRACE))
+ c_parser_consume_token (parser);
+ else if (code == OMP_ATOMIC_CAPTURE_NEW)
+ {
+ c_parser_skip_to_end_of_block_or_statement (parser);
+ if (c_parser_next_token_is (parser, CPP_CLOSE_BRACE))
+ c_parser_consume_token (parser);
+ }
+ }
+ return;
+
+ case POSTINCREMENT_EXPR:
+ if (code == OMP_ATOMIC_CAPTURE_NEW && !structured_block)
+ code = OMP_ATOMIC_CAPTURE_OLD;
+ /* FALLTHROUGH */
+ case PREINCREMENT_EXPR:
+ lhs = TREE_OPERAND (lhs, 0);
+ unfolded_lhs = NULL_TREE;
+ opcode = PLUS_EXPR;
+ rhs = integer_one_node;
+ break;
+
+ case POSTDECREMENT_EXPR:
+ if (code == OMP_ATOMIC_CAPTURE_NEW && !structured_block)
+ code = OMP_ATOMIC_CAPTURE_OLD;
+ /* FALLTHROUGH */
+ case PREDECREMENT_EXPR:
+ lhs = TREE_OPERAND (lhs, 0);
+ unfolded_lhs = NULL_TREE;
+ opcode = MINUS_EXPR;
+ rhs = integer_one_node;
+ break;
+
+ case COMPOUND_EXPR:
+ if (TREE_CODE (TREE_OPERAND (lhs, 0)) == SAVE_EXPR
+ && TREE_CODE (TREE_OPERAND (lhs, 1)) == COMPOUND_EXPR
+ && TREE_CODE (TREE_OPERAND (TREE_OPERAND (lhs, 1), 0)) == MODIFY_EXPR
+ && TREE_OPERAND (TREE_OPERAND (lhs, 1), 1) == TREE_OPERAND (lhs, 0)
+ && TREE_CODE (TREE_TYPE (TREE_OPERAND (TREE_OPERAND
+ (TREE_OPERAND (lhs, 1), 0), 0)))
+ == BOOLEAN_TYPE)
+ /* Undo effects of boolean_increment for post {in,de}crement. */
+ lhs = TREE_OPERAND (TREE_OPERAND (lhs, 1), 0);
+ /* FALLTHRU */
+ case MODIFY_EXPR:
+ if (TREE_CODE (lhs) == MODIFY_EXPR
+ && TREE_CODE (TREE_TYPE (TREE_OPERAND (lhs, 0))) == BOOLEAN_TYPE)
+ {
+ /* Undo effects of boolean_increment. */
+ if (integer_onep (TREE_OPERAND (lhs, 1)))
+ {
+ /* This is pre or post increment. */
+ rhs = TREE_OPERAND (lhs, 1);
+ lhs = TREE_OPERAND (lhs, 0);
+ unfolded_lhs = NULL_TREE;
+ opcode = NOP_EXPR;
+ if (code == OMP_ATOMIC_CAPTURE_NEW
+ && !structured_block
+ && TREE_CODE (orig_lhs) == COMPOUND_EXPR)
+ code = OMP_ATOMIC_CAPTURE_OLD;
+ break;
+ }
+ if (TREE_CODE (TREE_OPERAND (lhs, 1)) == TRUTH_NOT_EXPR
+ && TREE_OPERAND (lhs, 0)
+ == TREE_OPERAND (TREE_OPERAND (lhs, 1), 0))
+ {
+ /* This is pre or post decrement. */
+ rhs = TREE_OPERAND (lhs, 1);
+ lhs = TREE_OPERAND (lhs, 0);
+ unfolded_lhs = NULL_TREE;
+ opcode = NOP_EXPR;
+ if (code == OMP_ATOMIC_CAPTURE_NEW
+ && !structured_block
+ && TREE_CODE (orig_lhs) == COMPOUND_EXPR)
+ code = OMP_ATOMIC_CAPTURE_OLD;
+ break;
+ }
+ }
+ /* FALLTHRU */
+ default:
+ switch (c_parser_peek_token (parser)->type)
+ {
+ case CPP_MULT_EQ:
+ opcode = MULT_EXPR;
+ break;
+ case CPP_DIV_EQ:
+ opcode = TRUNC_DIV_EXPR;
+ break;
+ case CPP_PLUS_EQ:
+ opcode = PLUS_EXPR;
+ break;
+ case CPP_MINUS_EQ:
+ opcode = MINUS_EXPR;
+ break;
+ case CPP_LSHIFT_EQ:
+ opcode = LSHIFT_EXPR;
+ break;
+ case CPP_RSHIFT_EQ:
+ opcode = RSHIFT_EXPR;
+ break;
+ case CPP_AND_EQ:
+ opcode = BIT_AND_EXPR;
+ break;
+ case CPP_OR_EQ:
+ opcode = BIT_IOR_EXPR;
+ break;
+ case CPP_XOR_EQ:
+ opcode = BIT_XOR_EXPR;
+ break;
+ case CPP_EQ:
+ c_parser_consume_token (parser);
+ eloc = c_parser_peek_token (parser)->location;
+ expr = c_parser_expr_no_commas (parser, NULL, unfolded_lhs);
+ rhs1 = expr.value;
+ switch (TREE_CODE (rhs1))
+ {
+ case MULT_EXPR:
+ case TRUNC_DIV_EXPR:
+ case PLUS_EXPR:
+ case MINUS_EXPR:
+ case LSHIFT_EXPR:
+ case RSHIFT_EXPR:
+ case BIT_AND_EXPR:
+ case BIT_IOR_EXPR:
+ case BIT_XOR_EXPR:
+ if (c_tree_equal (TREE_OPERAND (rhs1, 0), unfolded_lhs))
+ {
+ opcode = TREE_CODE (rhs1);
+ rhs = c_fully_fold (TREE_OPERAND (rhs1, 1), false, NULL);
+ rhs1 = c_fully_fold (TREE_OPERAND (rhs1, 0), false, NULL);
+ goto stmt_done;
+ }
+ if (c_tree_equal (TREE_OPERAND (rhs1, 1), unfolded_lhs))
+ {
+ opcode = TREE_CODE (rhs1);
+ rhs = c_fully_fold (TREE_OPERAND (rhs1, 0), false, NULL);
+ rhs1 = c_fully_fold (TREE_OPERAND (rhs1, 1), false, NULL);
+ swapped = !commutative_tree_code (opcode);
+ goto stmt_done;
+ }
+ break;
+ case ERROR_MARK:
+ goto saw_error;
+ default:
+ break;
+ }
+ if (c_parser_peek_token (parser)->type == CPP_SEMICOLON)
+ {
+ if (structured_block && code == OMP_ATOMIC_CAPTURE_NEW)
+ {
+ code = OMP_ATOMIC_CAPTURE_OLD;
+ v = lhs;
+ lhs = NULL_TREE;
+ expr = default_function_array_read_conversion (eloc, expr);
+ unfolded_lhs1 = expr.value;
+ lhs1 = c_fully_fold (unfolded_lhs1, false, NULL);
+ rhs1 = NULL_TREE;
+ c_parser_consume_token (parser);
+ goto restart;
+ }
+ if (structured_block)
+ {
+ opcode = NOP_EXPR;
+ expr = default_function_array_read_conversion (eloc, expr);
+ rhs = c_fully_fold (expr.value, false, NULL);
+ rhs1 = NULL_TREE;
+ goto stmt_done;
+ }
+ }
+ c_parser_error (parser, "invalid form of %<#pragma omp atomic%>");
+ goto saw_error;
+ default:
+ c_parser_error (parser,
+ "invalid operator for %<#pragma omp atomic%>");
+ goto saw_error;
+ }
+
+ /* Arrange to pass the location of the assignment operator to
+ c_finish_omp_atomic. */
+ loc = c_parser_peek_token (parser)->location;
+ c_parser_consume_token (parser);
+ eloc = c_parser_peek_token (parser)->location;
+ expr = c_parser_expression (parser);
+ expr = default_function_array_read_conversion (eloc, expr);
+ rhs = expr.value;
+ rhs = c_fully_fold (rhs, false, NULL);
+ break;
+ }
+ stmt_done:
+ if (structured_block && code == OMP_ATOMIC_CAPTURE_NEW)
+ {
+ if (!c_parser_require (parser, CPP_SEMICOLON, "expected %<;%>"))
+ goto saw_error;
+ v = c_parser_unary_expression (parser).value;
+ v = c_fully_fold (v, false, NULL);
+ if (v == error_mark_node)
+ goto saw_error;
+ if (!c_parser_require (parser, CPP_EQ, "expected %<=%>"))
+ goto saw_error;
+ eloc = c_parser_peek_token (parser)->location;
+ expr = c_parser_unary_expression (parser);
+ lhs1 = expr.value;
+ expr = default_function_array_read_conversion (eloc, expr);
+ unfolded_lhs1 = expr.value;
+ lhs1 = c_fully_fold (lhs1, false, NULL);
+ if (lhs1 == error_mark_node)
+ goto saw_error;
+ }
+ if (structured_block)
+ {
+ c_parser_skip_until_found (parser, CPP_SEMICOLON, "expected %<;%>");
+ c_parser_require (parser, CPP_CLOSE_BRACE, "expected %<}%>");
+ }
+ done:
+ if (unfolded_lhs && unfolded_lhs1
+ && !c_tree_equal (unfolded_lhs, unfolded_lhs1))
+ {
+ error ("%<#pragma omp atomic capture%> uses two different "
+ "expressions for memory");
+ stmt = error_mark_node;
+ }
+ else
+ stmt = c_finish_omp_atomic (loc, code, opcode, lhs, rhs, v, lhs1, rhs1,
+ swapped, seq_cst);
+ if (stmt != error_mark_node)
+ add_stmt (stmt);
+
+ if (!structured_block)
+ c_parser_skip_until_found (parser, CPP_SEMICOLON, "expected %<;%>");
+ }
+
+
+ /* OpenMP 2.5:
+ # pragma omp barrier new-line
+ */
+
+ static void
+ c_parser_omp_barrier (c_parser *parser)
+ {
+ location_t loc = c_parser_peek_token (parser)->location;
+ c_parser_consume_pragma (parser);
+ c_parser_skip_to_pragma_eol (parser);
+
+ c_finish_omp_barrier (loc);
+ }
+
+ /* OpenMP 2.5:
+ # pragma omp critical [(name)] new-line
+ structured-block
+
+ LOC is the location of the #pragma itself. */
+
+ static tree
+ c_parser_omp_critical (location_t loc, c_parser *parser)
+ {
+ tree stmt, name = NULL;
+
+ if (c_parser_next_token_is (parser, CPP_OPEN_PAREN))
+ {
+ c_parser_consume_token (parser);
+ if (c_parser_next_token_is (parser, CPP_NAME))
+ {
+ name = c_parser_peek_token (parser)->value;
+ c_parser_consume_token (parser);
+ c_parser_require (parser, CPP_CLOSE_PAREN, "expected %<)%>");
+ }
+ else
+ c_parser_error (parser, "expected identifier");
+ }
+ else if (c_parser_next_token_is_not (parser, CPP_PRAGMA_EOL))
+ c_parser_error (parser, "expected %<(%> or end of line");
+ c_parser_skip_to_pragma_eol (parser);
+
+ stmt = c_parser_omp_structured_block (parser);
+ return c_finish_omp_critical (loc, stmt, name);
+ }
+
+ /* OpenMP 2.5:
+ # pragma omp flush flush-vars[opt] new-line
+
+ flush-vars:
+ ( variable-list ) */
+
+ static void
+ c_parser_omp_flush (c_parser *parser)
+ {
+ location_t loc = c_parser_peek_token (parser)->location;
+ c_parser_consume_pragma (parser);
+ if (c_parser_next_token_is (parser, CPP_OPEN_PAREN))
+ c_parser_omp_var_list_parens (parser, OMP_CLAUSE_ERROR, NULL);
+ else if (c_parser_next_token_is_not (parser, CPP_PRAGMA_EOL))
+ c_parser_error (parser, "expected %<(%> or end of line");
+ c_parser_skip_to_pragma_eol (parser);
+
+ c_finish_omp_flush (loc);
+ }
+
+ /* Parse the restricted form of the for statement allowed by OpenMP.
+ The real trick here is to determine the loop control variable early
+ so that we can push a new decl if necessary to make it private.
+ LOC is the location of the OMP in "#pragma omp". */
+
+ static tree
+ c_parser_omp_for_loop (location_t loc, c_parser *parser, enum tree_code code,
+ tree clauses, tree *cclauses)
+ {
+ tree decl, cond, incr, save_break, save_cont, body, init, stmt, cl;
+ tree declv, condv, incrv, initv, ret = NULL;
+ bool fail = false, open_brace_parsed = false;
+ int i, collapse = 1, nbraces = 0;
+ location_t for_loc;
+ vec<tree, va_gc> *for_block = make_tree_vector ();
+
+ for (cl = clauses; cl; cl = OMP_CLAUSE_CHAIN (cl))
+ if (OMP_CLAUSE_CODE (cl) == OMP_CLAUSE_COLLAPSE)
++ collapse = tree_to_shwi (OMP_CLAUSE_COLLAPSE_EXPR (cl));
+
+ gcc_assert (collapse >= 1);
+
+ declv = make_tree_vec (collapse);
+ initv = make_tree_vec (collapse);
+ condv = make_tree_vec (collapse);
+ incrv = make_tree_vec (collapse);
+
+ if (!c_parser_next_token_is_keyword (parser, RID_FOR))
+ {
+ c_parser_error (parser, "for statement expected");
+ return NULL;
+ }
+ for_loc = c_parser_peek_token (parser)->location;
+ c_parser_consume_token (parser);
+
+ for (i = 0; i < collapse; i++)
+ {
+ int bracecount = 0;
+
+ if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>"))
+ goto pop_scopes;
+
+ /* Parse the initialization declaration or expression. */
+ if (c_parser_next_tokens_start_declaration (parser))
+ {
+ if (i > 0)
+ vec_safe_push (for_block, c_begin_compound_stmt (true));
+ c_parser_declaration_or_fndef (parser, true, true, true, true, true,
+ NULL, vNULL);
+ decl = check_for_loop_decls (for_loc, flag_isoc99);
+ if (decl == NULL)
+ goto error_init;
+ if (DECL_INITIAL (decl) == error_mark_node)
+ decl = error_mark_node;
+ init = decl;
+ }
+ else if (c_parser_next_token_is (parser, CPP_NAME)
+ && c_parser_peek_2nd_token (parser)->type == CPP_EQ)
+ {
+ struct c_expr decl_exp;
+ struct c_expr init_exp;
+ location_t init_loc;
+
+ decl_exp = c_parser_postfix_expression (parser);
+ decl = decl_exp.value;
+
+ c_parser_require (parser, CPP_EQ, "expected %<=%>");
+
+ init_loc = c_parser_peek_token (parser)->location;
+ init_exp = c_parser_expr_no_commas (parser, NULL);
+ init_exp = default_function_array_read_conversion (init_loc,
+ init_exp);
+ init = build_modify_expr (init_loc, decl, decl_exp.original_type,
+ NOP_EXPR, init_loc, init_exp.value,
+ init_exp.original_type);
+ init = c_process_expr_stmt (init_loc, init);
+
+ c_parser_skip_until_found (parser, CPP_SEMICOLON, "expected %<;%>");
+ }
+ else
+ {
+ error_init:
+ c_parser_error (parser,
+ "expected iteration declaration or initialization");
+ c_parser_skip_until_found (parser, CPP_CLOSE_PAREN,
+ "expected %<)%>");
+ fail = true;
+ goto parse_next;
+ }
+
+ /* Parse the loop condition. */
+ cond = NULL_TREE;
+ if (c_parser_next_token_is_not (parser, CPP_SEMICOLON))
+ {
+ location_t cond_loc = c_parser_peek_token (parser)->location;
+ struct c_expr cond_expr
+ = c_parser_binary_expression (parser, NULL, NULL_TREE);
+
+ cond = cond_expr.value;
+ cond = c_objc_common_truthvalue_conversion (cond_loc, cond);
+ cond = c_fully_fold (cond, false, NULL);
+ switch (cond_expr.original_code)
+ {
+ case GT_EXPR:
+ case GE_EXPR:
+ case LT_EXPR:
+ case LE_EXPR:
+ break;
+ default:
+ /* Can't be cond = error_mark_node, because we want to preserve
+ the location until c_finish_omp_for. */
+ cond = build1 (NOP_EXPR, boolean_type_node, error_mark_node);
+ break;
+ }
+ protected_set_expr_location (cond, cond_loc);
+ }
+ c_parser_skip_until_found (parser, CPP_SEMICOLON, "expected %<;%>");
+
+ /* Parse the increment expression. */
+ incr = NULL_TREE;
+ if (c_parser_next_token_is_not (parser, CPP_CLOSE_PAREN))
+ {
+ location_t incr_loc = c_parser_peek_token (parser)->location;
+
+ incr = c_process_expr_stmt (incr_loc,
+ c_parser_expression (parser).value);
+ }
+ c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>");
+
+ if (decl == NULL || decl == error_mark_node || init == error_mark_node)
+ fail = true;
+ else
+ {
+ TREE_VEC_ELT (declv, i) = decl;
+ TREE_VEC_ELT (initv, i) = init;
+ TREE_VEC_ELT (condv, i) = cond;
+ TREE_VEC_ELT (incrv, i) = incr;
+ }
+
+ parse_next:
+ if (i == collapse - 1)
+ break;
+
+ /* FIXME: OpenMP 3.0 draft isn't very clear on what exactly is allowed
+ in between the collapsed for loops to be still considered perfectly
+ nested. Hopefully the final version clarifies this.
+ For now handle (multiple) {'s and empty statements. */
+ do
+ {
+ if (c_parser_next_token_is_keyword (parser, RID_FOR))
+ {
+ c_parser_consume_token (parser);
+ break;
+ }
+ else if (c_parser_next_token_is (parser, CPP_OPEN_BRACE))
+ {
+ c_parser_consume_token (parser);
+ bracecount++;
+ }
+ else if (bracecount
+ && c_parser_next_token_is (parser, CPP_SEMICOLON))
+ c_parser_consume_token (parser);
+ else
+ {
+ c_parser_error (parser, "not enough perfectly nested loops");
+ if (bracecount)
+ {
+ open_brace_parsed = true;
+ bracecount--;
+ }
+ fail = true;
+ collapse = 0;
+ break;
+ }
+ }
+ while (1);
+
+ nbraces += bracecount;
+ }
+
+ save_break = c_break_label;
+ c_break_label = size_one_node;
+ save_cont = c_cont_label;
+ c_cont_label = NULL_TREE;
+ body = push_stmt_list ();
+
+ if (open_brace_parsed)
+ {
+ location_t here = c_parser_peek_token (parser)->location;
+ stmt = c_begin_compound_stmt (true);
+ c_parser_compound_statement_nostart (parser);
+ add_stmt (c_end_compound_stmt (here, stmt, true));
+ }
+ else
+ add_stmt (c_parser_c99_block_statement (parser));
+ if (c_cont_label)
+ {
+ tree t = build1 (LABEL_EXPR, void_type_node, c_cont_label);
+ SET_EXPR_LOCATION (t, loc);
+ add_stmt (t);
+ }
+
+ body = pop_stmt_list (body);
+ c_break_label = save_break;
+ c_cont_label = save_cont;
+
+ while (nbraces)
+ {
+ if (c_parser_next_token_is (parser, CPP_CLOSE_BRACE))
+ {
+ c_parser_consume_token (parser);
+ nbraces--;
+ }
+ else if (c_parser_next_token_is (parser, CPP_SEMICOLON))
+ c_parser_consume_token (parser);
+ else
+ {
+ c_parser_error (parser, "collapsed loops not perfectly nested");
+ while (nbraces)
+ {
+ location_t here = c_parser_peek_token (parser)->location;
+ stmt = c_begin_compound_stmt (true);
+ add_stmt (body);
+ c_parser_compound_statement_nostart (parser);
+ body = c_end_compound_stmt (here, stmt, true);
+ nbraces--;
+ }
+ goto pop_scopes;
+ }
+ }
+
+ /* Only bother calling c_finish_omp_for if we haven't already generated
+ an error from the initialization parsing. */
+ if (!fail)
+ {
+ stmt = c_finish_omp_for (loc, code, declv, initv, condv,
+ incrv, body, NULL);
+ if (stmt)
+ {
+ if (cclauses != NULL
+ && cclauses[C_OMP_CLAUSE_SPLIT_PARALLEL] != NULL)
+ {
+ tree *c;
+ for (c = &cclauses[C_OMP_CLAUSE_SPLIT_PARALLEL]; *c ; )
+ if (OMP_CLAUSE_CODE (*c) != OMP_CLAUSE_FIRSTPRIVATE
+ && OMP_CLAUSE_CODE (*c) != OMP_CLAUSE_LASTPRIVATE)
+ c = &OMP_CLAUSE_CHAIN (*c);
+ else
+ {
+ for (i = 0; i < collapse; i++)
+ if (TREE_VEC_ELT (declv, i) == OMP_CLAUSE_DECL (*c))
+ break;
+ if (i == collapse)
+ c = &OMP_CLAUSE_CHAIN (*c);
+ else if (OMP_CLAUSE_CODE (*c) == OMP_CLAUSE_FIRSTPRIVATE)
+ {
+ error_at (loc,
+ "iteration variable %qD should not be firstprivate",
+ OMP_CLAUSE_DECL (*c));
+ *c = OMP_CLAUSE_CHAIN (*c);
+ }
+ else
+ {
+ /* Copy lastprivate (decl) clause to OMP_FOR_CLAUSES,
+ change it to shared (decl) in
+ OMP_PARALLEL_CLAUSES. */
+ tree l = build_omp_clause (OMP_CLAUSE_LOCATION (*c),
+ OMP_CLAUSE_LASTPRIVATE);
+ OMP_CLAUSE_DECL (l) = OMP_CLAUSE_DECL (*c);
+ OMP_CLAUSE_CHAIN (l) = clauses;
+ clauses = l;
+ OMP_CLAUSE_SET_CODE (*c, OMP_CLAUSE_SHARED);
+ }
+ }
+ }
+ OMP_FOR_CLAUSES (stmt) = clauses;
+ }
+ ret = stmt;
+ }
+ pop_scopes:
+ while (!for_block->is_empty ())
+ {
+ /* FIXME diagnostics: LOC below should be the actual location of
+ this particular for block. We need to build a list of
+ locations to go along with FOR_BLOCK. */
+ stmt = c_end_compound_stmt (loc, for_block->pop (), true);
+ add_stmt (stmt);
+ }
+ release_tree_vector (for_block);
+ return ret;
+ }
+
+ /* Helper function for OpenMP parsing, split clauses and call
+ finish_omp_clauses on each of the set of clauses afterwards. */
+
+ static void
+ omp_split_clauses (location_t loc, enum tree_code code,
+ omp_clause_mask mask, tree clauses, tree *cclauses)
+ {
+ int i;
+ c_omp_split_clauses (loc, code, mask, clauses, cclauses);
+ for (i = 0; i < C_OMP_CLAUSE_SPLIT_COUNT; i++)
+ if (cclauses[i])
+ cclauses[i] = c_finish_omp_clauses (cclauses[i]);
+ }
+
+ /* OpenMP 4.0:
+ #pragma omp simd simd-clause[optseq] new-line
+ for-loop
+
+ LOC is the location of the #pragma token.
+ */
+
+ #define OMP_SIMD_CLAUSE_MASK \
+ ( (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_SAFELEN) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_LINEAR) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_ALIGNED) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_PRIVATE) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_LASTPRIVATE) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_REDUCTION) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_COLLAPSE))
+
+ static tree
+ c_parser_omp_simd (location_t loc, c_parser *parser,
+ char *p_name, omp_clause_mask mask, tree *cclauses)
+ {
+ tree block, clauses, ret;
+
+ strcat (p_name, " simd");
+ mask |= OMP_SIMD_CLAUSE_MASK;
+ mask &= ~(OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_ORDERED);
+
+ clauses = c_parser_omp_all_clauses (parser, mask, p_name, cclauses == NULL);
+ if (cclauses)
+ {
+ omp_split_clauses (loc, OMP_SIMD, mask, clauses, cclauses);
+ clauses = cclauses[C_OMP_CLAUSE_SPLIT_SIMD];
+ }
+
+ block = c_begin_compound_stmt (true);
+ ret = c_parser_omp_for_loop (loc, parser, OMP_SIMD, clauses, cclauses);
+ block = c_end_compound_stmt (loc, block, true);
+ add_stmt (block);
+
+ return ret;
+ }
+
+ /* OpenMP 2.5:
+ #pragma omp for for-clause[optseq] new-line
+ for-loop
+
+ OpenMP 4.0:
+ #pragma omp for simd for-simd-clause[optseq] new-line
+ for-loop
+
+ LOC is the location of the #pragma token.
+ */
+
+ #define OMP_FOR_CLAUSE_MASK \
+ ( (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_PRIVATE) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_FIRSTPRIVATE) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_LASTPRIVATE) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_REDUCTION) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_ORDERED) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_SCHEDULE) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_COLLAPSE) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_NOWAIT))
+
+ static tree
+ c_parser_omp_for (location_t loc, c_parser *parser,
+ char *p_name, omp_clause_mask mask, tree *cclauses)
+ {
+ tree block, clauses, ret;
+
+ strcat (p_name, " for");
+ mask |= OMP_FOR_CLAUSE_MASK;
+ if (cclauses)
+ mask &= ~(OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_NOWAIT);
+
+ if (c_parser_next_token_is (parser, CPP_NAME))
+ {
+ const char *p = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value);
+
+ if (strcmp (p, "simd") == 0)
+ {
+ tree cclauses_buf[C_OMP_CLAUSE_SPLIT_COUNT];
+ if (cclauses == NULL)
+ cclauses = cclauses_buf;
+
+ c_parser_consume_token (parser);
+ block = c_begin_compound_stmt (true);
+ ret = c_parser_omp_simd (loc, parser, p_name, mask, cclauses);
+ block = c_end_compound_stmt (loc, block, true);
+ if (ret == NULL_TREE)
+ return ret;
+ ret = make_node (OMP_FOR);
+ TREE_TYPE (ret) = void_type_node;
+ OMP_FOR_BODY (ret) = block;
+ OMP_FOR_CLAUSES (ret) = cclauses[C_OMP_CLAUSE_SPLIT_FOR];
+ SET_EXPR_LOCATION (ret, loc);
+ add_stmt (ret);
+ return ret;
+ }
+ }
+
+ clauses = c_parser_omp_all_clauses (parser, mask, p_name, cclauses == NULL);
+ if (cclauses)
+ {
+ omp_split_clauses (loc, OMP_FOR, mask, clauses, cclauses);
+ clauses = cclauses[C_OMP_CLAUSE_SPLIT_FOR];
+ }
+
+ block = c_begin_compound_stmt (true);
+ ret = c_parser_omp_for_loop (loc, parser, OMP_FOR, clauses, cclauses);
+ block = c_end_compound_stmt (loc, block, true);
+ add_stmt (block);
+
+ return ret;
+ }
+
+ /* OpenMP 2.5:
+ # pragma omp master new-line
+ structured-block
+
+ LOC is the location of the #pragma token.
+ */
+
+ static tree
+ c_parser_omp_master (location_t loc, c_parser *parser)
+ {
+ c_parser_skip_to_pragma_eol (parser);
+ return c_finish_omp_master (loc, c_parser_omp_structured_block (parser));
+ }
+
+ /* OpenMP 2.5:
+ # pragma omp ordered new-line
+ structured-block
+
+ LOC is the location of the #pragma itself.
+ */
+
+ static tree
+ c_parser_omp_ordered (location_t loc, c_parser *parser)
+ {
+ c_parser_skip_to_pragma_eol (parser);
+ return c_finish_omp_ordered (loc, c_parser_omp_structured_block (parser));
+ }
+
+ /* OpenMP 2.5:
+
+ section-scope:
+ { section-sequence }
+
+ section-sequence:
+ section-directive[opt] structured-block
+ section-sequence section-directive structured-block
+
+ SECTIONS_LOC is the location of the #pragma omp sections. */
+
+ static tree
+ c_parser_omp_sections_scope (location_t sections_loc, c_parser *parser)
+ {
+ tree stmt, substmt;
+ bool error_suppress = false;
+ location_t loc;
+
+ loc = c_parser_peek_token (parser)->location;
+ if (!c_parser_require (parser, CPP_OPEN_BRACE, "expected %<{%>"))
+ {
+ /* Avoid skipping until the end of the block. */
+ parser->error = false;
+ return NULL_TREE;
+ }
+
+ stmt = push_stmt_list ();
+
+ if (c_parser_peek_token (parser)->pragma_kind != PRAGMA_OMP_SECTION)
+ {
+ substmt = c_parser_omp_structured_block (parser);
+ substmt = build1 (OMP_SECTION, void_type_node, substmt);
+ SET_EXPR_LOCATION (substmt, loc);
+ add_stmt (substmt);
+ }
+
+ while (1)
+ {
+ if (c_parser_next_token_is (parser, CPP_CLOSE_BRACE))
+ break;
+ if (c_parser_next_token_is (parser, CPP_EOF))
+ break;
+
+ loc = c_parser_peek_token (parser)->location;
+ if (c_parser_peek_token (parser)->pragma_kind == PRAGMA_OMP_SECTION)
+ {
+ c_parser_consume_pragma (parser);
+ c_parser_skip_to_pragma_eol (parser);
+ error_suppress = false;
+ }
+ else if (!error_suppress)
+ {
+ error_at (loc, "expected %<#pragma omp section%> or %<}%>");
+ error_suppress = true;
+ }
+
+ substmt = c_parser_omp_structured_block (parser);
+ substmt = build1 (OMP_SECTION, void_type_node, substmt);
+ SET_EXPR_LOCATION (substmt, loc);
+ add_stmt (substmt);
+ }
+ c_parser_skip_until_found (parser, CPP_CLOSE_BRACE,
+ "expected %<#pragma omp section%> or %<}%>");
+
+ substmt = pop_stmt_list (stmt);
+
+ stmt = make_node (OMP_SECTIONS);
+ SET_EXPR_LOCATION (stmt, sections_loc);
+ TREE_TYPE (stmt) = void_type_node;
+ OMP_SECTIONS_BODY (stmt) = substmt;
+
+ return add_stmt (stmt);
+ }
+
+ /* OpenMP 2.5:
+ # pragma omp sections sections-clause[optseq] newline
+ sections-scope
+
+ LOC is the location of the #pragma token.
+ */
- /* Parse the loop condition. */
- cond = NULL_TREE;
- if (c_parser_next_token_is_not (parser, CPP_SEMICOLON))
- {
- location_t cond_loc = c_parser_peek_token (parser)->location;
- struct c_expr cond_expr = c_parser_binary_expression (parser, NULL,
- PREC_NONE);
+ #define OMP_SECTIONS_CLAUSE_MASK \
+ ( (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_PRIVATE) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_FIRSTPRIVATE) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_LASTPRIVATE) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_REDUCTION) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_NOWAIT))
- cond = cond_expr.value;
- cond = c_objc_common_truthvalue_conversion (cond_loc, cond);
- cond = c_fully_fold (cond, false, NULL);
- switch (cond_expr.original_code)
- {
- case GT_EXPR:
- case GE_EXPR:
- case LT_EXPR:
- case LE_EXPR:
- break;
- default:
- /* Can't be cond = error_mark_node, because we want to preserve
- the location until c_finish_omp_for. */
- cond = build1 (NOP_EXPR, boolean_type_node, error_mark_node);
- break;
- }
- protected_set_expr_location (cond, cond_loc);
- }
- c_parser_skip_until_found (parser, CPP_SEMICOLON, "expected %<;%>");
+ static tree
+ c_parser_omp_sections (location_t loc, c_parser *parser,
+ char *p_name, omp_clause_mask mask, tree *cclauses)
+ {
+ tree block, clauses, ret;
- /* Parse the increment expression. */
- incr = NULL_TREE;
- if (c_parser_next_token_is_not (parser, CPP_CLOSE_PAREN))
- {
- location_t incr_loc = c_parser_peek_token (parser)->location;
+ strcat (p_name, " sections");
+ mask |= OMP_SECTIONS_CLAUSE_MASK;
+ if (cclauses)
+ mask &= ~(OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_NOWAIT);
- incr = c_process_expr_stmt (incr_loc,
- c_parser_expression (parser).value);
- }
- c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>");
+ clauses = c_parser_omp_all_clauses (parser, mask, p_name, cclauses == NULL);
+ if (cclauses)
+ {
+ omp_split_clauses (loc, OMP_SECTIONS, mask, clauses, cclauses);
+ clauses = cclauses[C_OMP_CLAUSE_SPLIT_SECTIONS];
+ }
- if (decl == NULL || decl == error_mark_node || init == error_mark_node)
- fail = true;
- else
- {
- TREE_VEC_ELT (declv, i) = decl;
- TREE_VEC_ELT (initv, i) = init;
- TREE_VEC_ELT (condv, i) = cond;
- TREE_VEC_ELT (incrv, i) = incr;
- }
+ block = c_begin_compound_stmt (true);
+ ret = c_parser_omp_sections_scope (loc, parser);
+ if (ret)
+ OMP_SECTIONS_CLAUSES (ret) = clauses;
+ block = c_end_compound_stmt (loc, block, true);
+ add_stmt (block);
- parse_next:
- if (i == collapse - 1)
- break;
+ return ret;
+ }
- /* FIXME: OpenMP 3.0 draft isn't very clear on what exactly is allowed
- in between the collapsed for loops to be still considered perfectly
- nested. Hopefully the final version clarifies this.
- For now handle (multiple) {'s and empty statements. */
- do
- {
- if (c_parser_next_token_is_keyword (parser, RID_FOR))
- {
- c_parser_consume_token (parser);
- break;
- }
- else if (c_parser_next_token_is (parser, CPP_OPEN_BRACE))
- {
- c_parser_consume_token (parser);
- bracecount++;
- }
- else if (bracecount
- && c_parser_next_token_is (parser, CPP_SEMICOLON))
- c_parser_consume_token (parser);
- else
- {
- c_parser_error (parser, "not enough perfectly nested loops");
- if (bracecount)
- {
- open_brace_parsed = true;
- bracecount--;
- }
- fail = true;
- collapse = 0;
- break;
- }
- }
- while (1);
+ /* OpenMP 2.5:
+ # pragma parallel parallel-clause new-line
+ # pragma parallel for parallel-for-clause new-line
+ # pragma parallel sections parallel-sections-clause new-line
- nbraces += bracecount;
- }
+ LOC is the location of the #pragma token.
+ */
- save_break = c_break_label;
- c_break_label = size_one_node;
- save_cont = c_cont_label;
- c_cont_label = NULL_TREE;
- body = push_stmt_list ();
+ #define OMP_PARALLEL_CLAUSE_MASK \
+ ( (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_IF) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_PRIVATE) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_FIRSTPRIVATE) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_DEFAULT) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_SHARED) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_COPYIN) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_REDUCTION) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_NUM_THREADS) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_PROC_BIND))
- if (open_brace_parsed)
+ static tree
+ c_parser_omp_parallel (location_t loc, c_parser *parser,
+ char *p_name, omp_clause_mask mask, tree *cclauses)
+ {
+ tree stmt, clauses, block;
+
+ strcat (p_name, " parallel");
+ mask |= OMP_PARALLEL_CLAUSE_MASK;
+
+ if (c_parser_next_token_is_keyword (parser, RID_FOR))
{
- location_t here = c_parser_peek_token (parser)->location;
- stmt = c_begin_compound_stmt (true);
- c_parser_compound_statement_nostart (parser);
- add_stmt (c_end_compound_stmt (here, stmt, true));
+ tree cclauses_buf[C_OMP_CLAUSE_SPLIT_COUNT];
+ if (cclauses == NULL)
+ cclauses = cclauses_buf;
+
+ c_parser_consume_token (parser);
+ block = c_begin_omp_parallel ();
+ c_parser_omp_for (loc, parser, p_name, mask, cclauses);
+ stmt
+ = c_finish_omp_parallel (loc, cclauses[C_OMP_CLAUSE_SPLIT_PARALLEL],
+ block);
+ OMP_PARALLEL_COMBINED (stmt) = 1;
+ return stmt;
}
- else
- add_stmt (c_parser_c99_block_statement (parser));
- if (c_cont_label)
+ else if (cclauses)
{
- tree t = build1 (LABEL_EXPR, void_type_node, c_cont_label);
- SET_EXPR_LOCATION (t, loc);
- add_stmt (t);
+ error_at (loc, "expected %<for%> after %qs", p_name);
+ c_parser_skip_to_pragma_eol (parser);
+ return NULL_TREE;
}
-
- body = pop_stmt_list (body);
- c_break_label = save_break;
- c_cont_label = save_cont;
-
- while (nbraces)
+ else if (c_parser_next_token_is (parser, CPP_NAME))
{
- if (c_parser_next_token_is (parser, CPP_CLOSE_BRACE))
+ const char *p = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value);
+ if (strcmp (p, "sections") == 0)
{
+ tree cclauses_buf[C_OMP_CLAUSE_SPLIT_COUNT];
+ if (cclauses == NULL)
+ cclauses = cclauses_buf;
+
c_parser_consume_token (parser);
- nbraces--;
- }
- else if (c_parser_next_token_is (parser, CPP_SEMICOLON))
- c_parser_consume_token (parser);
- else
- {
- c_parser_error (parser, "collapsed loops not perfectly nested");
- while (nbraces)
- {
- location_t here = c_parser_peek_token (parser)->location;
- stmt = c_begin_compound_stmt (true);
- add_stmt (body);
- c_parser_compound_statement_nostart (parser);
- body = c_end_compound_stmt (here, stmt, true);
- nbraces--;
- }
- goto pop_scopes;
+ block = c_begin_omp_parallel ();
+ c_parser_omp_sections (loc, parser, p_name, mask, cclauses);
+ stmt = c_finish_omp_parallel (loc,
+ cclauses[C_OMP_CLAUSE_SPLIT_PARALLEL],
+ block);
+ OMP_PARALLEL_COMBINED (stmt) = 1;
+ return stmt;
}
}
"C++ requires promoted type, not enum type, in %<va_arg%>");
return build_va_arg (loc, expr, type);
}
- return TREE_INT_CST_LOW (t1) == TREE_INT_CST_LOW (t2)
- && TREE_INT_CST_HIGH (t1) == TREE_INT_CST_HIGH (t2);
+
+ /* Return truthvalue of whether T1 is the same tree structure as T2.
+ Return 1 if they are the same. Return 0 if they are different. */
+
+ bool
+ c_tree_equal (tree t1, tree t2)
+ {
+ enum tree_code code1, code2;
+
+ if (t1 == t2)
+ return true;
+ if (!t1 || !t2)
+ return false;
+
+ for (code1 = TREE_CODE (t1);
+ CONVERT_EXPR_CODE_P (code1)
+ || code1 == NON_LVALUE_EXPR;
+ code1 = TREE_CODE (t1))
+ t1 = TREE_OPERAND (t1, 0);
+ for (code2 = TREE_CODE (t2);
+ CONVERT_EXPR_CODE_P (code2)
+ || code2 == NON_LVALUE_EXPR;
+ code2 = TREE_CODE (t2))
+ t2 = TREE_OPERAND (t2, 0);
+
+ /* They might have become equal now. */
+ if (t1 == t2)
+ return true;
+
+ if (code1 != code2)
+ return false;
+
+ switch (code1)
+ {
+ case INTEGER_CST:
++ return wi::eq_p (t1, t2);
+
+ case REAL_CST:
+ return REAL_VALUES_EQUAL (TREE_REAL_CST (t1), TREE_REAL_CST (t2));
+
+ case STRING_CST:
+ return TREE_STRING_LENGTH (t1) == TREE_STRING_LENGTH (t2)
+ && !memcmp (TREE_STRING_POINTER (t1), TREE_STRING_POINTER (t2),
+ TREE_STRING_LENGTH (t1));
+
+ case FIXED_CST:
+ return FIXED_VALUES_IDENTICAL (TREE_FIXED_CST (t1),
+ TREE_FIXED_CST (t2));
+
+ case COMPLEX_CST:
+ return c_tree_equal (TREE_REALPART (t1), TREE_REALPART (t2))
+ && c_tree_equal (TREE_IMAGPART (t1), TREE_IMAGPART (t2));
+
+ case VECTOR_CST:
+ return operand_equal_p (t1, t2, OEP_ONLY_CONST);
+
+ case CONSTRUCTOR:
+ /* We need to do this when determining whether or not two
+ non-type pointer to member function template arguments
+ are the same. */
+ if (!comptypes (TREE_TYPE (t1), TREE_TYPE (t2))
+ || CONSTRUCTOR_NELTS (t1) != CONSTRUCTOR_NELTS (t2))
+ return false;
+ {
+ tree field, value;
+ unsigned int i;
+ FOR_EACH_CONSTRUCTOR_ELT (CONSTRUCTOR_ELTS (t1), i, field, value)
+ {
+ constructor_elt *elt2 = CONSTRUCTOR_ELT (t2, i);
+ if (!c_tree_equal (field, elt2->index)
+ || !c_tree_equal (value, elt2->value))
+ return false;
+ }
+ }
+ return true;
+
+ case TREE_LIST:
+ if (!c_tree_equal (TREE_PURPOSE (t1), TREE_PURPOSE (t2)))
+ return false;
+ if (!c_tree_equal (TREE_VALUE (t1), TREE_VALUE (t2)))
+ return false;
+ return c_tree_equal (TREE_CHAIN (t1), TREE_CHAIN (t2));
+
+ case SAVE_EXPR:
+ return c_tree_equal (TREE_OPERAND (t1, 0), TREE_OPERAND (t2, 0));
+
+ case CALL_EXPR:
+ {
+ tree arg1, arg2;
+ call_expr_arg_iterator iter1, iter2;
+ if (!c_tree_equal (CALL_EXPR_FN (t1), CALL_EXPR_FN (t2)))
+ return false;
+ for (arg1 = first_call_expr_arg (t1, &iter1),
+ arg2 = first_call_expr_arg (t2, &iter2);
+ arg1 && arg2;
+ arg1 = next_call_expr_arg (&iter1),
+ arg2 = next_call_expr_arg (&iter2))
+ if (!c_tree_equal (arg1, arg2))
+ return false;
+ if (arg1 || arg2)
+ return false;
+ return true;
+ }
+
+ case TARGET_EXPR:
+ {
+ tree o1 = TREE_OPERAND (t1, 0);
+ tree o2 = TREE_OPERAND (t2, 0);
+
+ /* Special case: if either target is an unallocated VAR_DECL,
+ it means that it's going to be unified with whatever the
+ TARGET_EXPR is really supposed to initialize, so treat it
+ as being equivalent to anything. */
+ if (TREE_CODE (o1) == VAR_DECL && DECL_NAME (o1) == NULL_TREE
+ && !DECL_RTL_SET_P (o1))
+ /*Nop*/;
+ else if (TREE_CODE (o2) == VAR_DECL && DECL_NAME (o2) == NULL_TREE
+ && !DECL_RTL_SET_P (o2))
+ /*Nop*/;
+ else if (!c_tree_equal (o1, o2))
+ return false;
+
+ return c_tree_equal (TREE_OPERAND (t1, 1), TREE_OPERAND (t2, 1));
+ }
+
+ case COMPONENT_REF:
+ if (TREE_OPERAND (t1, 1) != TREE_OPERAND (t2, 1))
+ return false;
+ return c_tree_equal (TREE_OPERAND (t1, 0), TREE_OPERAND (t2, 0));
+
+ case PARM_DECL:
+ case VAR_DECL:
+ case CONST_DECL:
+ case FIELD_DECL:
+ case FUNCTION_DECL:
+ case IDENTIFIER_NODE:
+ case SSA_NAME:
+ return false;
+
+ case TREE_VEC:
+ {
+ unsigned ix;
+ if (TREE_VEC_LENGTH (t1) != TREE_VEC_LENGTH (t2))
+ return false;
+ for (ix = TREE_VEC_LENGTH (t1); ix--;)
+ if (!c_tree_equal (TREE_VEC_ELT (t1, ix),
+ TREE_VEC_ELT (t2, ix)))
+ return false;
+ return true;
+ }
+
+ default:
+ break;
+ }
+
+ switch (TREE_CODE_CLASS (code1))
+ {
+ case tcc_unary:
+ case tcc_binary:
+ case tcc_comparison:
+ case tcc_expression:
+ case tcc_vl_exp:
+ case tcc_reference:
+ case tcc_statement:
+ {
+ int i, n = TREE_OPERAND_LENGTH (t1);
+
+ switch (code1)
+ {
+ case PREINCREMENT_EXPR:
+ case PREDECREMENT_EXPR:
+ case POSTINCREMENT_EXPR:
+ case POSTDECREMENT_EXPR:
+ n = 1;
+ break;
+ case ARRAY_REF:
+ n = 2;
+ break;
+ default:
+ break;
+ }
+
+ if (TREE_CODE_CLASS (code1) == tcc_vl_exp
+ && n != TREE_OPERAND_LENGTH (t2))
+ return false;
+
+ for (i = 0; i < n; ++i)
+ if (!c_tree_equal (TREE_OPERAND (t1, i), TREE_OPERAND (t2, i)))
+ return false;
+
+ return true;
+ }
+
+ case tcc_type:
+ return comptypes (t1, t2);
+ default:
+ gcc_unreachable ();
+ }
+ /* We can get here with --disable-checking. */
+ return false;
+ }
other hand, we don't want the function's stack frame size to
get completely out of hand. So we avoid adding scalars and
"small" aggregates to the list at all. */
- if (optimize == 0 && tree_to_uhwi (DECL_SIZE_UNIT (var)) < 32)
+ if (optimize == 0
- && (tree_low_cst (DECL_SIZE_UNIT (var), 1)
++ && (tree_to_uhwi (DECL_SIZE_UNIT (var))
+ < PARAM_VALUE (PARAM_MIN_SIZE_FOR_STACK_SHARING)))
return false;
return true;
return DECL_SOURCE_LOCATION (current_function_decl);
}
-record_niter_bound (struct loop *loop, double_int i_bound, bool realistic,
- bool upper)
+ /* Records that every statement in LOOP is executed I_BOUND times.
+ REALISTIC is true if I_BOUND is expected to be close to the real number
+ of iterations. UPPER is true if we are sure the loop iterates at most
+ I_BOUND times. */
+
+ void
- || i_bound.ult (loop->nb_iterations_upper_bound)))
++record_niter_bound (struct loop *loop, const max_wide_int &i_bound,
++ bool realistic, bool upper)
+ {
+ /* Update the bounds only when there is no previous estimation, or when the
+ current estimation is smaller. */
+ if (upper
+ && (!loop->any_upper_bound
- || i_bound.ult (loop->nb_iterations_estimate)))
++ || wi::ltu_p (i_bound, loop->nb_iterations_upper_bound)))
+ {
+ loop->any_upper_bound = true;
+ loop->nb_iterations_upper_bound = i_bound;
+ }
+ if (realistic
+ && (!loop->any_estimate
- && loop->nb_iterations_upper_bound.ult (loop->nb_iterations_estimate))
++ || wi::ltu_p (i_bound, loop->nb_iterations_estimate)))
+ {
+ loop->any_estimate = true;
+ loop->nb_iterations_estimate = i_bound;
+ }
+
+ /* If an upper bound is smaller than the realistic estimate of the
+ number of iterations, use the upper bound instead. */
+ if (loop->any_upper_bound
+ && loop->any_estimate
- double_int nit;
++ && wi::ltu_p (loop->nb_iterations_upper_bound,
++ loop->nb_iterations_estimate))
+ loop->nb_iterations_estimate = loop->nb_iterations_upper_bound;
+ }
+
+ /* Similar to get_estimated_loop_iterations, but returns the estimate only
+ if it fits to HOST_WIDE_INT. If this is not the case, or the estimate
+ on the number of iterations of LOOP could not be derived, returns -1. */
+
+ HOST_WIDE_INT
+ get_estimated_loop_iterations_int (struct loop *loop)
+ {
- if (!nit.fits_shwi ())
++ max_wide_int nit;
+ HOST_WIDE_INT hwi_nit;
+
+ if (!get_estimated_loop_iterations (loop, &nit))
+ return -1;
+
-get_estimated_loop_iterations (struct loop *loop, double_int *nit)
++ if (!wi::fits_shwi_p (nit))
+ return -1;
+ hwi_nit = nit.to_shwi ();
+
+ return hwi_nit < 0 ? -1 : hwi_nit;
+ }
+
+ /* Returns an upper bound on the number of executions of statements
+ in the LOOP. For statements before the loop exit, this exceeds
+ the number of execution of the latch by one. */
+
+ HOST_WIDE_INT
+ max_stmt_executions_int (struct loop *loop)
+ {
+ HOST_WIDE_INT nit = get_max_loop_iterations_int (loop);
+ HOST_WIDE_INT snit;
+
+ if (nit == -1)
+ return -1;
+
+ snit = (HOST_WIDE_INT) ((unsigned HOST_WIDE_INT) nit + 1);
+
+ /* If the computation overflows, return -1. */
+ return snit < 0 ? -1 : snit;
+ }
+
+ /* Sets NIT to the estimated number of executions of the latch of the
+ LOOP. If we have no reliable estimate, the function returns false, otherwise
+ returns true. */
+
+ bool
- *nit = gcov_type_to_double_int
++get_estimated_loop_iterations (struct loop *loop, max_wide_int *nit)
+ {
+ /* Even if the bound is not recorded, possibly we can derrive one from
+ profile. */
+ if (!loop->any_estimate)
+ {
+ if (loop->header->count)
+ {
-get_max_loop_iterations (struct loop *loop, double_int *nit)
++ *nit = gcov_type_to_wide_int
+ (expected_loop_iterations_unbounded (loop) + 1);
+ return true;
+ }
+ return false;
+ }
+
+ *nit = loop->nb_iterations_estimate;
+ return true;
+ }
+
+ /* Sets NIT to an upper bound for the maximum number of executions of the
+ latch of the LOOP. If we have no reliable estimate, the function returns
+ false, otherwise returns true. */
+
+ bool
- double_int nit;
++get_max_loop_iterations (struct loop *loop, max_wide_int *nit)
+ {
+ if (!loop->any_upper_bound)
+ return false;
+
+ *nit = loop->nb_iterations_upper_bound;
+ return true;
+ }
+
+ /* Similar to get_max_loop_iterations, but returns the estimate only
+ if it fits to HOST_WIDE_INT. If this is not the case, or the estimate
+ on the number of iterations of LOOP could not be derived, returns -1. */
+
+ HOST_WIDE_INT
+ get_max_loop_iterations_int (struct loop *loop)
+ {
- if (!nit.fits_shwi ())
++ max_wide_int nit;
+ HOST_WIDE_INT hwi_nit;
+
+ if (!get_max_loop_iterations (loop, &nit))
+ return -1;
+
++ if (!wi::fits_shwi_p (nit))
+ return -1;
+ hwi_nit = nit.to_shwi ();
+
+ return hwi_nit < 0 ? -1 : hwi_nit;
+ }
+
+ /* Returns the loop depth of the loop BB belongs to. */
+
+ int
+ bb_loop_depth (const_basic_block bb)
+ {
+ return bb->loop_father ? loop_depth (bb->loop_father) : 0;
+ }
#ifndef GCC_CFGLOOP_H
#define GCC_CFGLOOP_H
- #include "basic-block.h"
#include "double-int.h"
-
+#include "wide-int.h"
#include "bitmap.h"
#include "sbitmap.h"
+ #include "function.h"
/* Structure to hold decision about unrolling/peeling. */
enum lpt_dec
return (*loop->superloops)[1];
}
-extern void record_niter_bound (struct loop *, double_int, bool, bool);
++extern void record_niter_bound (struct loop *, const max_wide_int &, bool, bool);
+ extern HOST_WIDE_INT get_estimated_loop_iterations_int (struct loop *);
+ extern HOST_WIDE_INT get_max_loop_iterations_int (struct loop *);
-extern bool get_estimated_loop_iterations (struct loop *loop, double_int *nit);
-extern bool get_max_loop_iterations (struct loop *loop, double_int *nit);
++extern bool get_estimated_loop_iterations (struct loop *loop, max_wide_int *nit);
++extern bool get_max_loop_iterations (struct loop *loop, max_wide_int *nit);
+ extern int bb_loop_depth (const_basic_block);
-/* Converts VAL to double_int. */
++/* Converts VAL to max_wide_int. */
+
-static inline double_int
-gcov_type_to_double_int (gcov_type val)
++static inline max_wide_int
++gcov_type_to_wide_int (gcov_type val)
+ {
- double_int ret;
++ HOST_WIDE_INT a[2];
+
- ret.low = (unsigned HOST_WIDE_INT) val;
++ a[0] = (unsigned HOST_WIDE_INT) val;
+ /* If HOST_BITS_PER_WIDE_INT == HOST_BITS_PER_WIDEST_INT, avoid shifting by
+ the size of type. */
+ val >>= HOST_BITS_PER_WIDE_INT - 1;
+ val >>= 1;
- ret.high = (unsigned HOST_WIDE_INT) val;
++ a[1] = (unsigned HOST_WIDE_INT) val;
+
- return ret;
++ return max_wide_int::from_array (a, 2);
+ }
#endif /* GCC_CFGLOOP_H */
#include "diagnostic.h"
#include "dumpfile.h"
#include "tree-pass.h"
- #include "tree-flow.h"
+#include "wide-int.h"
#include "context.h"
#include "pass_manager.h"
tree id = cp_lexer_peek_token (parser->lexer)->u.value;
const char *p = IDENTIFIER_POINTER (id);
- if (!strcmp (p, "read"))
- code = OMP_ATOMIC_READ;
- else if (!strcmp (p, "write"))
- code = NOP_EXPR;
- else if (!strcmp (p, "update"))
- code = OMP_ATOMIC;
- else if (!strcmp (p, "capture"))
- code = OMP_ATOMIC_CAPTURE_NEW;
+ if (strcmp ("in", p) == 0)
+ kind = OMP_CLAUSE_DEPEND_IN;
+ else if (strcmp ("inout", p) == 0)
+ kind = OMP_CLAUSE_DEPEND_INOUT;
+ else if (strcmp ("out", p) == 0)
+ kind = OMP_CLAUSE_DEPEND_OUT;
else
- p = NULL;
- if (p)
- cp_lexer_consume_token (parser->lexer);
+ goto invalid_kind;
}
- cp_parser_require_pragma_eol (parser, pragma_tok);
+ else
+ goto invalid_kind;
- switch (code)
- {
- case OMP_ATOMIC_READ:
- case NOP_EXPR: /* atomic write */
- v = cp_parser_unary_expression (parser, /*address_p=*/false,
- /*cast_p=*/false, NULL);
- if (v == error_mark_node)
- goto saw_error;
- if (!cp_parser_require (parser, CPP_EQ, RT_EQ))
- goto saw_error;
- if (code == NOP_EXPR)
- lhs = cp_parser_expression (parser, /*cast_p=*/false, NULL);
- else
- lhs = cp_parser_unary_expression (parser, /*address_p=*/false,
- /*cast_p=*/false, NULL);
- if (lhs == error_mark_node)
- goto saw_error;
- if (code == NOP_EXPR)
- {
- /* atomic write is represented by OMP_ATOMIC with NOP_EXPR
- opcode. */
- code = OMP_ATOMIC;
- rhs = lhs;
- lhs = v;
- v = NULL_TREE;
- }
- goto done;
- case OMP_ATOMIC_CAPTURE_NEW:
- if (cp_lexer_next_token_is (parser->lexer, CPP_OPEN_BRACE))
- {
- cp_lexer_consume_token (parser->lexer);
- structured_block = true;
- }
- else
- {
- v = cp_parser_unary_expression (parser, /*address_p=*/false,
- /*cast_p=*/false, NULL);
- if (v == error_mark_node)
- goto saw_error;
- if (!cp_parser_require (parser, CPP_EQ, RT_EQ))
- goto saw_error;
- }
- default:
- break;
- }
+ cp_lexer_consume_token (parser->lexer);
+ if (!cp_parser_require (parser, CPP_COLON, RT_COLON))
+ goto resync_fail;
- restart:
- lhs = cp_parser_unary_expression (parser, /*address_p=*/false,
- /*cast_p=*/false, NULL);
- orig_lhs = lhs;
- switch (TREE_CODE (lhs))
- {
- case ERROR_MARK:
- goto saw_error;
+ nlist = cp_parser_omp_var_list_no_open (parser, OMP_CLAUSE_DEPEND, list,
+ NULL);
- case POSTINCREMENT_EXPR:
- if (code == OMP_ATOMIC_CAPTURE_NEW && !structured_block)
- code = OMP_ATOMIC_CAPTURE_OLD;
- /* FALLTHROUGH */
- case PREINCREMENT_EXPR:
- lhs = TREE_OPERAND (lhs, 0);
- opcode = PLUS_EXPR;
- rhs = integer_one_node;
- break;
+ for (c = nlist; c != list; c = OMP_CLAUSE_CHAIN (c))
+ OMP_CLAUSE_DEPEND_KIND (c) = kind;
- case POSTDECREMENT_EXPR:
- if (code == OMP_ATOMIC_CAPTURE_NEW && !structured_block)
- code = OMP_ATOMIC_CAPTURE_OLD;
- /* FALLTHROUGH */
- case PREDECREMENT_EXPR:
- lhs = TREE_OPERAND (lhs, 0);
- opcode = MINUS_EXPR;
- rhs = integer_one_node;
- break;
+ return nlist;
- case COMPOUND_EXPR:
- if (TREE_CODE (TREE_OPERAND (lhs, 0)) == SAVE_EXPR
- && TREE_CODE (TREE_OPERAND (lhs, 1)) == COMPOUND_EXPR
- && TREE_CODE (TREE_OPERAND (TREE_OPERAND (lhs, 1), 0)) == MODIFY_EXPR
- && TREE_OPERAND (TREE_OPERAND (lhs, 1), 1) == TREE_OPERAND (lhs, 0)
- && TREE_CODE (TREE_TYPE (TREE_OPERAND (TREE_OPERAND
- (TREE_OPERAND (lhs, 1), 0), 0)))
- == BOOLEAN_TYPE)
- /* Undo effects of boolean_increment for post {in,de}crement. */
- lhs = TREE_OPERAND (TREE_OPERAND (lhs, 1), 0);
- /* FALLTHRU */
- case MODIFY_EXPR:
- if (TREE_CODE (lhs) == MODIFY_EXPR
- && TREE_CODE (TREE_TYPE (TREE_OPERAND (lhs, 0))) == BOOLEAN_TYPE)
- {
- /* Undo effects of boolean_increment. */
- if (integer_onep (TREE_OPERAND (lhs, 1)))
- {
- /* This is pre or post increment. */
- rhs = TREE_OPERAND (lhs, 1);
- lhs = TREE_OPERAND (lhs, 0);
- opcode = NOP_EXPR;
- if (code == OMP_ATOMIC_CAPTURE_NEW
- && !structured_block
- && TREE_CODE (orig_lhs) == COMPOUND_EXPR)
- code = OMP_ATOMIC_CAPTURE_OLD;
- break;
- }
- }
- /* FALLTHRU */
- default:
- switch (cp_lexer_peek_token (parser->lexer)->type)
- {
- case CPP_MULT_EQ:
- opcode = MULT_EXPR;
- break;
- case CPP_DIV_EQ:
- opcode = TRUNC_DIV_EXPR;
- break;
- case CPP_PLUS_EQ:
- opcode = PLUS_EXPR;
- break;
- case CPP_MINUS_EQ:
- opcode = MINUS_EXPR;
- break;
- case CPP_LSHIFT_EQ:
- opcode = LSHIFT_EXPR;
- break;
- case CPP_RSHIFT_EQ:
- opcode = RSHIFT_EXPR;
- break;
- case CPP_AND_EQ:
- opcode = BIT_AND_EXPR;
- break;
- case CPP_OR_EQ:
- opcode = BIT_IOR_EXPR;
- break;
- case CPP_XOR_EQ:
- opcode = BIT_XOR_EXPR;
- break;
- case CPP_EQ:
- if (structured_block || code == OMP_ATOMIC)
- {
- enum cp_parser_prec oprec;
- cp_token *token;
- cp_lexer_consume_token (parser->lexer);
- rhs1 = cp_parser_unary_expression (parser, /*address_p=*/false,
- /*cast_p=*/false, NULL);
- if (rhs1 == error_mark_node)
- goto saw_error;
- token = cp_lexer_peek_token (parser->lexer);
- switch (token->type)
- {
- case CPP_SEMICOLON:
- if (code == OMP_ATOMIC_CAPTURE_NEW)
- {
- code = OMP_ATOMIC_CAPTURE_OLD;
- v = lhs;
- lhs = NULL_TREE;
- lhs1 = rhs1;
- rhs1 = NULL_TREE;
- cp_lexer_consume_token (parser->lexer);
- goto restart;
- }
- cp_parser_error (parser,
- "invalid form of %<#pragma omp atomic%>");
- goto saw_error;
- case CPP_MULT:
- opcode = MULT_EXPR;
- break;
- case CPP_DIV:
- opcode = TRUNC_DIV_EXPR;
- break;
- case CPP_PLUS:
- opcode = PLUS_EXPR;
- break;
- case CPP_MINUS:
- opcode = MINUS_EXPR;
- break;
- case CPP_LSHIFT:
- opcode = LSHIFT_EXPR;
- break;
- case CPP_RSHIFT:
- opcode = RSHIFT_EXPR;
- break;
- case CPP_AND:
- opcode = BIT_AND_EXPR;
- break;
- case CPP_OR:
- opcode = BIT_IOR_EXPR;
- break;
- case CPP_XOR:
- opcode = BIT_XOR_EXPR;
- break;
- default:
- cp_parser_error (parser,
- "invalid operator for %<#pragma omp atomic%>");
- goto saw_error;
- }
- oprec = TOKEN_PRECEDENCE (token);
- gcc_assert (oprec != PREC_NOT_OPERATOR);
- if (commutative_tree_code (opcode))
- oprec = (enum cp_parser_prec) (oprec - 1);
- cp_lexer_consume_token (parser->lexer);
- rhs = cp_parser_binary_expression (parser, false, false,
- oprec, NULL);
- if (rhs == error_mark_node)
- goto saw_error;
- goto stmt_done;
- }
- /* FALLTHROUGH */
- default:
- cp_parser_error (parser,
- "invalid operator for %<#pragma omp atomic%>");
- goto saw_error;
- }
- cp_lexer_consume_token (parser->lexer);
+ invalid_kind:
+ cp_parser_error (parser, "invalid depend kind");
+ resync_fail:
+ cp_parser_skip_to_closing_parenthesis (parser, /*recovering=*/true,
+ /*or_comma=*/false,
+ /*consume_paren=*/true);
+ return list;
+ }
- rhs = cp_parser_expression (parser, false, NULL);
- if (rhs == error_mark_node)
- goto saw_error;
- break;
- }
- stmt_done:
- if (structured_block && code == OMP_ATOMIC_CAPTURE_NEW)
- {
- if (!cp_parser_require (parser, CPP_SEMICOLON, RT_SEMICOLON))
- goto saw_error;
- v = cp_parser_unary_expression (parser, /*address_p=*/false,
- /*cast_p=*/false, NULL);
- if (v == error_mark_node)
- goto saw_error;
- if (!cp_parser_require (parser, CPP_EQ, RT_EQ))
- goto saw_error;
- lhs1 = cp_parser_unary_expression (parser, /*address_p=*/false,
- /*cast_p=*/false, NULL);
- if (lhs1 == error_mark_node)
- goto saw_error;
- }
- if (structured_block)
- {
- cp_parser_consume_semicolon_at_end_of_statement (parser);
- cp_parser_require (parser, CPP_CLOSE_BRACE, RT_CLOSE_BRACE);
- }
- done:
- finish_omp_atomic (code, opcode, lhs, rhs, v, lhs1, rhs1);
- if (!structured_block)
- cp_parser_consume_semicolon_at_end_of_statement (parser);
- return;
+ /* OpenMP 4.0:
+ map ( map-kind : variable-list )
+ map ( variable-list )
- saw_error:
- cp_parser_skip_to_end_of_block_or_statement (parser);
- if (structured_block)
+ map-kind:
+ alloc | to | from | tofrom */
+
+ static tree
+ cp_parser_omp_clause_map (cp_parser *parser, tree list)
+ {
+ tree nlist, c;
+ enum omp_clause_map_kind kind = OMP_CLAUSE_MAP_TOFROM;
+
+ if (!cp_parser_require (parser, CPP_OPEN_PAREN, RT_OPEN_PAREN))
+ return list;
+
+ if (cp_lexer_next_token_is (parser->lexer, CPP_NAME)
+ && cp_lexer_peek_nth_token (parser->lexer, 2)->type == CPP_COLON)
{
- if (cp_lexer_next_token_is (parser->lexer, CPP_CLOSE_BRACE))
- cp_lexer_consume_token (parser->lexer);
- else if (code == OMP_ATOMIC_CAPTURE_NEW)
+ tree id = cp_lexer_peek_token (parser->lexer)->u.value;
+ const char *p = IDENTIFIER_POINTER (id);
+
+ if (strcmp ("alloc", p) == 0)
+ kind = OMP_CLAUSE_MAP_ALLOC;
+ else if (strcmp ("to", p) == 0)
+ kind = OMP_CLAUSE_MAP_TO;
+ else if (strcmp ("from", p) == 0)
+ kind = OMP_CLAUSE_MAP_FROM;
+ else if (strcmp ("tofrom", p) == 0)
+ kind = OMP_CLAUSE_MAP_TOFROM;
+ else
{
- cp_parser_skip_to_end_of_block_or_statement (parser);
- if (cp_lexer_next_token_is (parser->lexer, CPP_CLOSE_BRACE))
- cp_lexer_consume_token (parser->lexer);
+ cp_parser_error (parser, "invalid map kind");
+ cp_parser_skip_to_closing_parenthesis (parser, /*recovering=*/true,
+ /*or_comma=*/false,
+ /*consume_paren=*/true);
+ return list;
}
+ cp_lexer_consume_token (parser->lexer);
+ cp_lexer_consume_token (parser->lexer);
}
- }
+ nlist = cp_parser_omp_var_list_no_open (parser, OMP_CLAUSE_MAP, list,
+ NULL);
- /* OpenMP 2.5:
- # pragma omp barrier new-line */
+ for (c = nlist; c != list; c = OMP_CLAUSE_CHAIN (c))
+ OMP_CLAUSE_MAP_KIND (c) = kind;
- static void
- cp_parser_omp_barrier (cp_parser *parser, cp_token *pragma_tok)
- {
- cp_parser_require_pragma_eol (parser, pragma_tok);
- finish_omp_barrier ();
+ return nlist;
}
- /* OpenMP 2.5:
- # pragma omp critical [(name)] new-line
- structured-block */
+ /* OpenMP 4.0:
+ device ( expression ) */
static tree
- cp_parser_omp_critical (cp_parser *parser, cp_token *pragma_tok)
+ cp_parser_omp_clause_device (cp_parser *parser, tree list,
+ location_t location)
{
- tree stmt, name = NULL;
+ tree t, c;
- if (cp_lexer_next_token_is (parser->lexer, CPP_OPEN_PAREN))
- {
- cp_lexer_consume_token (parser->lexer);
+ if (!cp_parser_require (parser, CPP_OPEN_PAREN, RT_OPEN_PAREN))
+ return list;
- name = cp_parser_identifier (parser);
+ t = cp_parser_expression (parser, false, NULL);
- if (name == error_mark_node
- || !cp_parser_require (parser, CPP_CLOSE_PAREN, RT_CLOSE_PAREN))
- cp_parser_skip_to_closing_parenthesis (parser, /*recovering=*/true,
- /*or_comma=*/false,
- /*consume_paren=*/true);
- if (name == error_mark_node)
- name = NULL;
- }
- cp_parser_require_pragma_eol (parser, pragma_tok);
+ if (t == error_mark_node
+ || !cp_parser_require (parser, CPP_CLOSE_PAREN, RT_CLOSE_PAREN))
+ cp_parser_skip_to_closing_parenthesis (parser, /*recovering=*/true,
+ /*or_comma=*/false,
+ /*consume_paren=*/true);
- stmt = cp_parser_omp_structured_block (parser);
- return c_finish_omp_critical (input_location, stmt, name);
- }
-
- /* OpenMP 2.5:
- # pragma omp flush flush-vars[opt] new-line
-
- flush-vars:
- ( variable-list ) */
+ check_no_duplicate_clause (list, OMP_CLAUSE_DEVICE,
+ "device", location);
- static void
- cp_parser_omp_flush (cp_parser *parser, cp_token *pragma_tok)
- {
- if (cp_lexer_next_token_is (parser->lexer, CPP_OPEN_PAREN))
- (void) cp_parser_omp_var_list (parser, OMP_CLAUSE_ERROR, NULL);
- cp_parser_require_pragma_eol (parser, pragma_tok);
+ c = build_omp_clause (location, OMP_CLAUSE_DEVICE);
+ OMP_CLAUSE_DEVICE_ID (c) = t;
+ OMP_CLAUSE_CHAIN (c) = list;
- finish_omp_flush ();
+ return c;
}
- /* Helper function, to parse omp for increment expression. */
+ /* OpenMP 4.0:
+ dist_schedule ( static )
+ dist_schedule ( static , expression ) */
static tree
- cp_parser_omp_for_cond (cp_parser *parser, tree decl)
+ cp_parser_omp_clause_dist_schedule (cp_parser *parser, tree list,
+ location_t location)
{
- tree cond = cp_parser_binary_expression (parser, false, true,
- PREC_NOT_OPERATOR, NULL);
- if (cond == error_mark_node
- || cp_lexer_next_token_is_not (parser->lexer, CPP_SEMICOLON))
- {
- cp_parser_skip_to_end_of_statement (parser);
- return error_mark_node;
- }
-
- switch (TREE_CODE (cond))
- {
- case GT_EXPR:
- case GE_EXPR:
- case LT_EXPR:
- case LE_EXPR:
- break;
- default:
- return error_mark_node;
- }
-
- /* If decl is an iterator, preserve LHS and RHS of the relational
- expr until finish_omp_for. */
- if (decl
- && (type_dependent_expression_p (decl)
- || CLASS_TYPE_P (TREE_TYPE (decl))))
- return cond;
-
- return build_x_binary_op (input_location, TREE_CODE (cond),
- TREE_OPERAND (cond, 0), ERROR_MARK,
- TREE_OPERAND (cond, 1), ERROR_MARK,
- /*overload=*/NULL, tf_warning_or_error);
- }
-
- /* Helper function, to parse omp for increment expression. */
+ tree c, t;
- static tree
- cp_parser_omp_for_incr (cp_parser *parser, tree decl)
- {
- cp_token *token = cp_lexer_peek_token (parser->lexer);
- enum tree_code op;
- tree lhs, rhs;
- cp_id_kind idk;
- bool decl_first;
+ if (!cp_parser_require (parser, CPP_OPEN_PAREN, RT_OPEN_PAREN))
+ return list;
- if (token->type == CPP_PLUS_PLUS || token->type == CPP_MINUS_MINUS)
- {
- op = (token->type == CPP_PLUS_PLUS
- ? PREINCREMENT_EXPR : PREDECREMENT_EXPR);
- cp_lexer_consume_token (parser->lexer);
- lhs = cp_parser_simple_cast_expression (parser);
- if (lhs != decl)
- return error_mark_node;
- return build2 (op, TREE_TYPE (decl), decl, NULL_TREE);
- }
+ c = build_omp_clause (location, OMP_CLAUSE_DIST_SCHEDULE);
- lhs = cp_parser_primary_expression (parser, false, false, false, &idk);
- if (lhs != decl)
- return error_mark_node;
+ if (!cp_lexer_next_token_is_keyword (parser->lexer, RID_STATIC))
+ goto invalid_kind;
+ cp_lexer_consume_token (parser->lexer);
- token = cp_lexer_peek_token (parser->lexer);
- if (token->type == CPP_PLUS_PLUS || token->type == CPP_MINUS_MINUS)
+ if (cp_lexer_next_token_is (parser->lexer, CPP_COMMA))
{
- op = (token->type == CPP_PLUS_PLUS
- ? POSTINCREMENT_EXPR : POSTDECREMENT_EXPR);
cp_lexer_consume_token (parser->lexer);
- return build2 (op, TREE_TYPE (decl), decl, NULL_TREE);
- }
-
- op = cp_parser_assignment_operator_opt (parser);
- if (op == ERROR_MARK)
- return error_mark_node;
- if (op != NOP_EXPR)
- {
- rhs = cp_parser_assignment_expression (parser, false, NULL);
- rhs = build2 (op, TREE_TYPE (decl), decl, rhs);
- return build2 (MODIFY_EXPR, TREE_TYPE (decl), decl, rhs);
- }
+ t = cp_parser_assignment_expression (parser, false, NULL);
- lhs = cp_parser_binary_expression (parser, false, false,
- PREC_ADDITIVE_EXPRESSION, NULL);
- token = cp_lexer_peek_token (parser->lexer);
- decl_first = lhs == decl;
- if (decl_first)
- lhs = NULL_TREE;
- if (token->type != CPP_PLUS
- && token->type != CPP_MINUS)
- return error_mark_node;
+ if (t == error_mark_node)
+ goto resync_fail;
+ OMP_CLAUSE_DIST_SCHEDULE_CHUNK_EXPR (c) = t;
- do
- {
- op = token->type == CPP_PLUS ? PLUS_EXPR : MINUS_EXPR;
- cp_lexer_consume_token (parser->lexer);
- rhs = cp_parser_binary_expression (parser, false, false,
- PREC_ADDITIVE_EXPRESSION, NULL);
- token = cp_lexer_peek_token (parser->lexer);
- if (token->type == CPP_PLUS || token->type == CPP_MINUS || decl_first)
- {
- if (lhs == NULL_TREE)
- {
- if (op == PLUS_EXPR)
- lhs = rhs;
- else
- lhs = build_x_unary_op (input_location, NEGATE_EXPR, rhs,
- tf_warning_or_error);
- }
- else
- lhs = build_x_binary_op (input_location, op, lhs, ERROR_MARK, rhs,
- ERROR_MARK, NULL, tf_warning_or_error);
- }
+ if (!cp_parser_require (parser, CPP_CLOSE_PAREN, RT_CLOSE_PAREN))
+ goto resync_fail;
}
- while (token->type == CPP_PLUS || token->type == CPP_MINUS);
+ else if (!cp_parser_require (parser, CPP_CLOSE_PAREN, RT_COMMA_CLOSE_PAREN))
+ goto resync_fail;
- if (!decl_first)
- {
- if (rhs != decl || op == MINUS_EXPR)
- return error_mark_node;
- rhs = build2 (op, TREE_TYPE (decl), lhs, decl);
- }
- else
- rhs = build2 (PLUS_EXPR, TREE_TYPE (decl), decl, lhs);
+ check_no_duplicate_clause (list, OMP_CLAUSE_DIST_SCHEDULE, "dist_schedule",
+ location);
+ OMP_CLAUSE_CHAIN (c) = list;
+ return c;
- return build2 (MODIFY_EXPR, TREE_TYPE (decl), decl, rhs);
+ invalid_kind:
+ cp_parser_error (parser, "invalid dist_schedule kind");
+ resync_fail:
+ cp_parser_skip_to_closing_parenthesis (parser, /*recovering=*/true,
+ /*or_comma=*/false,
+ /*consume_paren=*/true);
+ return list;
}
- /* Parse the restricted form of the for statement allowed by OpenMP. */
+ /* OpenMP 4.0:
+ proc_bind ( proc-bind-kind )
+
+ proc-bind-kind:
+ master | close | spread */
static tree
- cp_parser_omp_for_loop (cp_parser *parser, tree clauses, tree *par_clauses)
+ cp_parser_omp_clause_proc_bind (cp_parser *parser, tree list,
+ location_t location)
{
- tree init, cond, incr, body, decl, pre_body = NULL_TREE, ret;
- tree real_decl, initv, condv, incrv, declv;
- tree this_pre_body, cl;
- location_t loc_first;
- bool collapse_err = false;
- int i, collapse = 1, nbraces = 0;
- vec<tree, va_gc> *for_block = make_tree_vector ();
-
- for (cl = clauses; cl; cl = OMP_CLAUSE_CHAIN (cl))
- if (OMP_CLAUSE_CODE (cl) == OMP_CLAUSE_COLLAPSE)
- collapse = tree_to_shwi (OMP_CLAUSE_COLLAPSE_EXPR (cl));
-
- gcc_assert (collapse >= 1);
-
- declv = make_tree_vec (collapse);
- initv = make_tree_vec (collapse);
- condv = make_tree_vec (collapse);
- incrv = make_tree_vec (collapse);
+ tree c;
+ enum omp_clause_proc_bind_kind kind;
- loc_first = cp_lexer_peek_token (parser->lexer)->location;
+ if (!cp_parser_require (parser, CPP_OPEN_PAREN, RT_OPEN_PAREN))
+ return list;
- for (i = 0; i < collapse; i++)
+ if (cp_lexer_next_token_is (parser->lexer, CPP_NAME))
{
- int bracecount = 0;
- bool add_private_clause = false;
- location_t loc;
+ tree id = cp_lexer_peek_token (parser->lexer)->u.value;
+ const char *p = IDENTIFIER_POINTER (id);
- if (!cp_lexer_next_token_is_keyword (parser->lexer, RID_FOR))
- {
- cp_parser_error (parser, "for statement expected");
- return NULL;
- }
- loc = cp_lexer_consume_token (parser->lexer)->location;
+ if (strcmp ("master", p) == 0)
+ kind = OMP_CLAUSE_PROC_BIND_MASTER;
+ else if (strcmp ("close", p) == 0)
+ kind = OMP_CLAUSE_PROC_BIND_CLOSE;
+ else if (strcmp ("spread", p) == 0)
+ kind = OMP_CLAUSE_PROC_BIND_SPREAD;
+ else
+ goto invalid_kind;
+ }
+ else
+ goto invalid_kind;
- if (!cp_parser_require (parser, CPP_OPEN_PAREN, RT_OPEN_PAREN))
- return NULL;
+ cp_lexer_consume_token (parser->lexer);
+ if (!cp_parser_require (parser, CPP_CLOSE_PAREN, RT_COMMA_CLOSE_PAREN))
+ goto resync_fail;
- init = decl = real_decl = NULL;
- this_pre_body = push_stmt_list ();
- if (cp_lexer_next_token_is_not (parser->lexer, CPP_SEMICOLON))
- {
- /* See 2.5.1 (in OpenMP 3.0, similar wording is in 2.5 standard too):
+ c = build_omp_clause (location, OMP_CLAUSE_PROC_BIND);
+ check_no_duplicate_clause (list, OMP_CLAUSE_PROC_BIND, "proc_bind",
+ location);
+ OMP_CLAUSE_PROC_BIND_KIND (c) = kind;
+ OMP_CLAUSE_CHAIN (c) = list;
+ return c;
- init-expr:
- var = lb
- integer-type var = lb
- random-access-iterator-type var = lb
- pointer-type var = lb
- */
- cp_decl_specifier_seq type_specifiers;
+ invalid_kind:
+ cp_parser_error (parser, "invalid depend kind");
+ resync_fail:
+ cp_parser_skip_to_closing_parenthesis (parser, /*recovering=*/true,
+ /*or_comma=*/false,
+ /*consume_paren=*/true);
+ return list;
+ }
- /* First, try to parse as an initialized declaration. See
- cp_parser_condition, from whence the bulk of this is copied. */
+ /* Parse all OpenMP clauses. The set clauses allowed by the directive
+ is a bitmask in MASK. Return the list of clauses found; the result
+ of clause default goes in *pdefault. */
- cp_parser_parse_tentatively (parser);
- cp_parser_type_specifier_seq (parser, /*is_declaration=*/true,
- /*is_trailing_return=*/false,
- &type_specifiers);
- if (cp_parser_parse_definitely (parser))
- {
- /* If parsing a type specifier seq succeeded, then this
- MUST be a initialized declaration. */
- tree asm_specification, attributes;
- cp_declarator *declarator;
+ static tree
+ cp_parser_omp_all_clauses (cp_parser *parser, omp_clause_mask mask,
+ const char *where, cp_token *pragma_tok,
+ bool finish_p = true)
+ {
+ tree clauses = NULL;
+ bool first = true;
+ cp_token *token = NULL;
- declarator = cp_parser_declarator (parser,
- CP_PARSER_DECLARATOR_NAMED,
- /*ctor_dtor_or_conv_p=*/NULL,
- /*parenthesized_p=*/NULL,
- /*member_p=*/false);
- attributes = cp_parser_attributes_opt (parser);
- asm_specification = cp_parser_asm_specification_opt (parser);
+ while (cp_lexer_next_token_is_not (parser->lexer, CPP_PRAGMA_EOL))
+ {
+ pragma_omp_clause c_kind;
+ const char *c_name;
+ tree prev = clauses;
- if (declarator == cp_error_declarator)
- cp_parser_skip_to_end_of_statement (parser);
+ if (!first && cp_lexer_next_token_is (parser->lexer, CPP_COMMA))
+ cp_lexer_consume_token (parser->lexer);
- else
+ token = cp_lexer_peek_token (parser->lexer);
+ c_kind = cp_parser_omp_clause_name (parser);
+
+ switch (c_kind)
+ {
+ case PRAGMA_OMP_CLAUSE_COLLAPSE:
+ clauses = cp_parser_omp_clause_collapse (parser, clauses,
+ token->location);
+ c_name = "collapse";
+ break;
+ case PRAGMA_OMP_CLAUSE_COPYIN:
+ clauses = cp_parser_omp_var_list (parser, OMP_CLAUSE_COPYIN, clauses);
+ c_name = "copyin";
+ break;
+ case PRAGMA_OMP_CLAUSE_COPYPRIVATE:
+ clauses = cp_parser_omp_var_list (parser, OMP_CLAUSE_COPYPRIVATE,
+ clauses);
+ c_name = "copyprivate";
+ break;
+ case PRAGMA_OMP_CLAUSE_DEFAULT:
+ clauses = cp_parser_omp_clause_default (parser, clauses,
+ token->location);
+ c_name = "default";
+ break;
+ case PRAGMA_OMP_CLAUSE_FINAL:
+ clauses = cp_parser_omp_clause_final (parser, clauses, token->location);
+ c_name = "final";
+ break;
+ case PRAGMA_OMP_CLAUSE_FIRSTPRIVATE:
+ clauses = cp_parser_omp_var_list (parser, OMP_CLAUSE_FIRSTPRIVATE,
+ clauses);
+ c_name = "firstprivate";
+ break;
+ case PRAGMA_OMP_CLAUSE_IF:
+ clauses = cp_parser_omp_clause_if (parser, clauses, token->location);
+ c_name = "if";
+ break;
+ case PRAGMA_OMP_CLAUSE_LASTPRIVATE:
+ clauses = cp_parser_omp_var_list (parser, OMP_CLAUSE_LASTPRIVATE,
+ clauses);
+ c_name = "lastprivate";
+ break;
+ case PRAGMA_OMP_CLAUSE_MERGEABLE:
+ clauses = cp_parser_omp_clause_mergeable (parser, clauses,
+ token->location);
+ c_name = "mergeable";
+ break;
+ case PRAGMA_OMP_CLAUSE_NOWAIT:
+ clauses = cp_parser_omp_clause_nowait (parser, clauses, token->location);
+ c_name = "nowait";
+ break;
+ case PRAGMA_OMP_CLAUSE_NUM_THREADS:
+ clauses = cp_parser_omp_clause_num_threads (parser, clauses,
+ token->location);
+ c_name = "num_threads";
+ break;
+ case PRAGMA_OMP_CLAUSE_ORDERED:
+ clauses = cp_parser_omp_clause_ordered (parser, clauses,
+ token->location);
+ c_name = "ordered";
+ break;
+ case PRAGMA_OMP_CLAUSE_PRIVATE:
+ clauses = cp_parser_omp_var_list (parser, OMP_CLAUSE_PRIVATE,
+ clauses);
+ c_name = "private";
+ break;
+ case PRAGMA_OMP_CLAUSE_REDUCTION:
+ clauses = cp_parser_omp_clause_reduction (parser, clauses);
+ c_name = "reduction";
+ break;
+ case PRAGMA_OMP_CLAUSE_SCHEDULE:
+ clauses = cp_parser_omp_clause_schedule (parser, clauses,
+ token->location);
+ c_name = "schedule";
+ break;
+ case PRAGMA_OMP_CLAUSE_SHARED:
+ clauses = cp_parser_omp_var_list (parser, OMP_CLAUSE_SHARED,
+ clauses);
+ c_name = "shared";
+ break;
+ case PRAGMA_OMP_CLAUSE_UNTIED:
+ clauses = cp_parser_omp_clause_untied (parser, clauses,
+ token->location);
+ c_name = "untied";
+ break;
+ case PRAGMA_OMP_CLAUSE_INBRANCH:
+ clauses = cp_parser_omp_clause_branch (parser, OMP_CLAUSE_INBRANCH,
+ clauses, token->location);
+ c_name = "inbranch";
+ break;
+ case PRAGMA_OMP_CLAUSE_NOTINBRANCH:
+ clauses = cp_parser_omp_clause_branch (parser,
+ OMP_CLAUSE_NOTINBRANCH,
+ clauses, token->location);
+ c_name = "notinbranch";
+ break;
+ case PRAGMA_OMP_CLAUSE_PARALLEL:
+ clauses = cp_parser_omp_clause_cancelkind (parser, OMP_CLAUSE_PARALLEL,
+ clauses, token->location);
+ c_name = "parallel";
+ if (!first)
+ {
+ clause_not_first:
+ error_at (token->location, "%qs must be the first clause of %qs",
+ c_name, where);
+ clauses = prev;
+ }
+ break;
+ case PRAGMA_OMP_CLAUSE_FOR:
+ clauses = cp_parser_omp_clause_cancelkind (parser, OMP_CLAUSE_FOR,
+ clauses, token->location);
+ c_name = "for";
+ if (!first)
+ goto clause_not_first;
+ break;
+ case PRAGMA_OMP_CLAUSE_SECTIONS:
+ clauses = cp_parser_omp_clause_cancelkind (parser, OMP_CLAUSE_SECTIONS,
+ clauses, token->location);
+ c_name = "sections";
+ if (!first)
+ goto clause_not_first;
+ break;
+ case PRAGMA_OMP_CLAUSE_TASKGROUP:
+ clauses = cp_parser_omp_clause_cancelkind (parser, OMP_CLAUSE_TASKGROUP,
+ clauses, token->location);
+ c_name = "taskgroup";
+ if (!first)
+ goto clause_not_first;
+ break;
+ case PRAGMA_OMP_CLAUSE_TO:
+ clauses = cp_parser_omp_var_list (parser, OMP_CLAUSE_TO,
+ clauses);
+ c_name = "to";
+ break;
+ case PRAGMA_OMP_CLAUSE_FROM:
+ clauses = cp_parser_omp_var_list (parser, OMP_CLAUSE_FROM,
+ clauses);
+ c_name = "from";
+ break;
+ case PRAGMA_OMP_CLAUSE_UNIFORM:
+ clauses = cp_parser_omp_var_list (parser, OMP_CLAUSE_UNIFORM,
+ clauses);
+ c_name = "uniform";
+ break;
+ case PRAGMA_OMP_CLAUSE_NUM_TEAMS:
+ clauses = cp_parser_omp_clause_num_teams (parser, clauses,
+ token->location);
+ c_name = "num_teams";
+ break;
+ case PRAGMA_OMP_CLAUSE_THREAD_LIMIT:
+ clauses = cp_parser_omp_clause_thread_limit (parser, clauses,
+ token->location);
+ c_name = "thread_limit";
+ break;
+ case PRAGMA_OMP_CLAUSE_ALIGNED:
+ clauses = cp_parser_omp_clause_aligned (parser, clauses);
+ c_name = "aligned";
+ break;
+ case PRAGMA_OMP_CLAUSE_LINEAR:
+ clauses = cp_parser_omp_clause_linear (parser, clauses);
+ c_name = "linear";
+ break;
+ case PRAGMA_OMP_CLAUSE_DEPEND:
+ clauses = cp_parser_omp_clause_depend (parser, clauses);
+ c_name = "depend";
+ break;
+ case PRAGMA_OMP_CLAUSE_MAP:
+ clauses = cp_parser_omp_clause_map (parser, clauses);
+ c_name = "map";
+ break;
+ case PRAGMA_OMP_CLAUSE_DEVICE:
+ clauses = cp_parser_omp_clause_device (parser, clauses,
+ token->location);
+ c_name = "device";
+ break;
+ case PRAGMA_OMP_CLAUSE_DIST_SCHEDULE:
+ clauses = cp_parser_omp_clause_dist_schedule (parser, clauses,
+ token->location);
+ c_name = "dist_schedule";
+ break;
+ case PRAGMA_OMP_CLAUSE_PROC_BIND:
+ clauses = cp_parser_omp_clause_proc_bind (parser, clauses,
+ token->location);
+ c_name = "proc_bind";
+ break;
+ case PRAGMA_OMP_CLAUSE_SAFELEN:
+ clauses = cp_parser_omp_clause_safelen (parser, clauses,
+ token->location);
+ c_name = "safelen";
+ break;
+ case PRAGMA_OMP_CLAUSE_SIMDLEN:
+ clauses = cp_parser_omp_clause_simdlen (parser, clauses,
+ token->location);
+ c_name = "simdlen";
+ break;
+ default:
+ cp_parser_error (parser, "expected %<#pragma omp%> clause");
+ goto saw_error;
+ }
+
+ first = false;
+
+ if (((mask >> c_kind) & 1) == 0)
+ {
+ /* Remove the invalid clause(s) from the list to avoid
+ confusing the rest of the compiler. */
+ clauses = prev;
+ error_at (token->location, "%qs is not valid for %qs", c_name, where);
+ }
+ }
+ saw_error:
+ cp_parser_skip_to_pragma_eol (parser, pragma_tok);
+ if (finish_p)
+ return finish_omp_clauses (clauses);
+ return clauses;
+ }
+
+ /* OpenMP 2.5:
+ structured-block:
+ statement
+
+ In practice, we're also interested in adding the statement to an
+ outer node. So it is convenient if we work around the fact that
+ cp_parser_statement calls add_stmt. */
+
+ static unsigned
+ cp_parser_begin_omp_structured_block (cp_parser *parser)
+ {
+ unsigned save = parser->in_statement;
+
+ /* Only move the values to IN_OMP_BLOCK if they weren't false.
+ This preserves the "not within loop or switch" style error messages
+ for nonsense cases like
+ void foo() {
+ #pragma omp single
+ break;
+ }
+ */
+ if (parser->in_statement)
+ parser->in_statement = IN_OMP_BLOCK;
+
+ return save;
+ }
+
+ static void
+ cp_parser_end_omp_structured_block (cp_parser *parser, unsigned save)
+ {
+ parser->in_statement = save;
+ }
+
+ static tree
+ cp_parser_omp_structured_block (cp_parser *parser)
+ {
+ tree stmt = begin_omp_structured_block ();
+ unsigned int save = cp_parser_begin_omp_structured_block (parser);
+
+ cp_parser_statement (parser, NULL_TREE, false, NULL);
+
+ cp_parser_end_omp_structured_block (parser, save);
+ return finish_omp_structured_block (stmt);
+ }
+
+ /* OpenMP 2.5:
+ # pragma omp atomic new-line
+ expression-stmt
+
+ expression-stmt:
+ x binop= expr | x++ | ++x | x-- | --x
+ binop:
+ +, *, -, /, &, ^, |, <<, >>
+
+ where x is an lvalue expression with scalar type.
+
+ OpenMP 3.1:
+ # pragma omp atomic new-line
+ update-stmt
+
+ # pragma omp atomic read new-line
+ read-stmt
+
+ # pragma omp atomic write new-line
+ write-stmt
+
+ # pragma omp atomic update new-line
+ update-stmt
+
+ # pragma omp atomic capture new-line
+ capture-stmt
+
+ # pragma omp atomic capture new-line
+ capture-block
+
+ read-stmt:
+ v = x
+ write-stmt:
+ x = expr
+ update-stmt:
+ expression-stmt | x = x binop expr
+ capture-stmt:
+ v = expression-stmt
+ capture-block:
+ { v = x; update-stmt; } | { update-stmt; v = x; }
+
+ OpenMP 4.0:
+ update-stmt:
+ expression-stmt | x = x binop expr | x = expr binop x
+ capture-stmt:
+ v = update-stmt
+ capture-block:
+ { v = x; update-stmt; } | { update-stmt; v = x; } | { v = x; x = expr; }
+
+ where x and v are lvalue expressions with scalar type. */
+
+ static void
+ cp_parser_omp_atomic (cp_parser *parser, cp_token *pragma_tok)
+ {
+ tree lhs = NULL_TREE, rhs = NULL_TREE, v = NULL_TREE, lhs1 = NULL_TREE;
+ tree rhs1 = NULL_TREE, orig_lhs;
+ enum tree_code code = OMP_ATOMIC, opcode = NOP_EXPR;
+ bool structured_block = false;
+ bool seq_cst = false;
+
+ if (cp_lexer_next_token_is (parser->lexer, CPP_NAME))
+ {
+ tree id = cp_lexer_peek_token (parser->lexer)->u.value;
+ const char *p = IDENTIFIER_POINTER (id);
+
+ if (!strcmp (p, "read"))
+ code = OMP_ATOMIC_READ;
+ else if (!strcmp (p, "write"))
+ code = NOP_EXPR;
+ else if (!strcmp (p, "update"))
+ code = OMP_ATOMIC;
+ else if (!strcmp (p, "capture"))
+ code = OMP_ATOMIC_CAPTURE_NEW;
+ else
+ p = NULL;
+ if (p)
+ cp_lexer_consume_token (parser->lexer);
+ }
+
+ if (cp_lexer_next_token_is (parser->lexer, CPP_NAME))
+ {
+ tree id = cp_lexer_peek_token (parser->lexer)->u.value;
+ const char *p = IDENTIFIER_POINTER (id);
+
+ if (!strcmp (p, "seq_cst"))
+ {
+ seq_cst = true;
+ cp_lexer_consume_token (parser->lexer);
+ }
+ }
+ cp_parser_require_pragma_eol (parser, pragma_tok);
+
+ switch (code)
+ {
+ case OMP_ATOMIC_READ:
+ case NOP_EXPR: /* atomic write */
+ v = cp_parser_unary_expression (parser, /*address_p=*/false,
+ /*cast_p=*/false, NULL);
+ if (v == error_mark_node)
+ goto saw_error;
+ if (!cp_parser_require (parser, CPP_EQ, RT_EQ))
+ goto saw_error;
+ if (code == NOP_EXPR)
+ lhs = cp_parser_expression (parser, /*cast_p=*/false, NULL);
+ else
+ lhs = cp_parser_unary_expression (parser, /*address_p=*/false,
+ /*cast_p=*/false, NULL);
+ if (lhs == error_mark_node)
+ goto saw_error;
+ if (code == NOP_EXPR)
+ {
+ /* atomic write is represented by OMP_ATOMIC with NOP_EXPR
+ opcode. */
+ code = OMP_ATOMIC;
+ rhs = lhs;
+ lhs = v;
+ v = NULL_TREE;
+ }
+ goto done;
+ case OMP_ATOMIC_CAPTURE_NEW:
+ if (cp_lexer_next_token_is (parser->lexer, CPP_OPEN_BRACE))
+ {
+ cp_lexer_consume_token (parser->lexer);
+ structured_block = true;
+ }
+ else
+ {
+ v = cp_parser_unary_expression (parser, /*address_p=*/false,
+ /*cast_p=*/false, NULL);
+ if (v == error_mark_node)
+ goto saw_error;
+ if (!cp_parser_require (parser, CPP_EQ, RT_EQ))
+ goto saw_error;
+ }
+ default:
+ break;
+ }
+
+ restart:
+ lhs = cp_parser_unary_expression (parser, /*address_p=*/false,
+ /*cast_p=*/false, NULL);
+ orig_lhs = lhs;
+ switch (TREE_CODE (lhs))
+ {
+ case ERROR_MARK:
+ goto saw_error;
+
+ case POSTINCREMENT_EXPR:
+ if (code == OMP_ATOMIC_CAPTURE_NEW && !structured_block)
+ code = OMP_ATOMIC_CAPTURE_OLD;
+ /* FALLTHROUGH */
+ case PREINCREMENT_EXPR:
+ lhs = TREE_OPERAND (lhs, 0);
+ opcode = PLUS_EXPR;
+ rhs = integer_one_node;
+ break;
+
+ case POSTDECREMENT_EXPR:
+ if (code == OMP_ATOMIC_CAPTURE_NEW && !structured_block)
+ code = OMP_ATOMIC_CAPTURE_OLD;
+ /* FALLTHROUGH */
+ case PREDECREMENT_EXPR:
+ lhs = TREE_OPERAND (lhs, 0);
+ opcode = MINUS_EXPR;
+ rhs = integer_one_node;
+ break;
+
+ case COMPOUND_EXPR:
+ if (TREE_CODE (TREE_OPERAND (lhs, 0)) == SAVE_EXPR
+ && TREE_CODE (TREE_OPERAND (lhs, 1)) == COMPOUND_EXPR
+ && TREE_CODE (TREE_OPERAND (TREE_OPERAND (lhs, 1), 0)) == MODIFY_EXPR
+ && TREE_OPERAND (TREE_OPERAND (lhs, 1), 1) == TREE_OPERAND (lhs, 0)
+ && TREE_CODE (TREE_TYPE (TREE_OPERAND (TREE_OPERAND
+ (TREE_OPERAND (lhs, 1), 0), 0)))
+ == BOOLEAN_TYPE)
+ /* Undo effects of boolean_increment for post {in,de}crement. */
+ lhs = TREE_OPERAND (TREE_OPERAND (lhs, 1), 0);
+ /* FALLTHRU */
+ case MODIFY_EXPR:
+ if (TREE_CODE (lhs) == MODIFY_EXPR
+ && TREE_CODE (TREE_TYPE (TREE_OPERAND (lhs, 0))) == BOOLEAN_TYPE)
+ {
+ /* Undo effects of boolean_increment. */
+ if (integer_onep (TREE_OPERAND (lhs, 1)))
+ {
+ /* This is pre or post increment. */
+ rhs = TREE_OPERAND (lhs, 1);
+ lhs = TREE_OPERAND (lhs, 0);
+ opcode = NOP_EXPR;
+ if (code == OMP_ATOMIC_CAPTURE_NEW
+ && !structured_block
+ && TREE_CODE (orig_lhs) == COMPOUND_EXPR)
+ code = OMP_ATOMIC_CAPTURE_OLD;
+ break;
+ }
+ }
+ /* FALLTHRU */
+ default:
+ switch (cp_lexer_peek_token (parser->lexer)->type)
+ {
+ case CPP_MULT_EQ:
+ opcode = MULT_EXPR;
+ break;
+ case CPP_DIV_EQ:
+ opcode = TRUNC_DIV_EXPR;
+ break;
+ case CPP_PLUS_EQ:
+ opcode = PLUS_EXPR;
+ break;
+ case CPP_MINUS_EQ:
+ opcode = MINUS_EXPR;
+ break;
+ case CPP_LSHIFT_EQ:
+ opcode = LSHIFT_EXPR;
+ break;
+ case CPP_RSHIFT_EQ:
+ opcode = RSHIFT_EXPR;
+ break;
+ case CPP_AND_EQ:
+ opcode = BIT_AND_EXPR;
+ break;
+ case CPP_OR_EQ:
+ opcode = BIT_IOR_EXPR;
+ break;
+ case CPP_XOR_EQ:
+ opcode = BIT_XOR_EXPR;
+ break;
+ case CPP_EQ:
+ enum cp_parser_prec oprec;
+ cp_token *token;
+ cp_lexer_consume_token (parser->lexer);
+ cp_parser_parse_tentatively (parser);
+ rhs1 = cp_parser_simple_cast_expression (parser);
+ if (rhs1 == error_mark_node)
+ {
+ cp_parser_abort_tentative_parse (parser);
+ cp_parser_simple_cast_expression (parser);
+ goto saw_error;
+ }
+ token = cp_lexer_peek_token (parser->lexer);
+ if (token->type != CPP_SEMICOLON && !cp_tree_equal (lhs, rhs1))
+ {
+ cp_parser_abort_tentative_parse (parser);
+ cp_parser_parse_tentatively (parser);
+ rhs = cp_parser_binary_expression (parser, false, true,
+ PREC_NOT_OPERATOR, NULL);
+ if (rhs == error_mark_node)
+ {
+ cp_parser_abort_tentative_parse (parser);
+ cp_parser_binary_expression (parser, false, true,
+ PREC_NOT_OPERATOR, NULL);
+ goto saw_error;
+ }
+ switch (TREE_CODE (rhs))
+ {
+ case MULT_EXPR:
+ case TRUNC_DIV_EXPR:
+ case PLUS_EXPR:
+ case MINUS_EXPR:
+ case LSHIFT_EXPR:
+ case RSHIFT_EXPR:
+ case BIT_AND_EXPR:
+ case BIT_IOR_EXPR:
+ case BIT_XOR_EXPR:
+ if (cp_tree_equal (lhs, TREE_OPERAND (rhs, 1)))
+ {
+ if (cp_parser_parse_definitely (parser))
+ {
+ opcode = TREE_CODE (rhs);
+ rhs1 = TREE_OPERAND (rhs, 0);
+ rhs = TREE_OPERAND (rhs, 1);
+ goto stmt_done;
+ }
+ else
+ goto saw_error;
+ }
+ break;
+ default:
+ break;
+ }
+ cp_parser_abort_tentative_parse (parser);
+ if (structured_block && code == OMP_ATOMIC_CAPTURE_OLD)
+ {
+ rhs = cp_parser_expression (parser, /*cast_p=*/false, NULL);
+ if (rhs == error_mark_node)
+ goto saw_error;
+ opcode = NOP_EXPR;
+ rhs1 = NULL_TREE;
+ goto stmt_done;
+ }
+ cp_parser_error (parser,
+ "invalid form of %<#pragma omp atomic%>");
+ goto saw_error;
+ }
+ if (!cp_parser_parse_definitely (parser))
+ goto saw_error;
+ switch (token->type)
+ {
+ case CPP_SEMICOLON:
+ if (structured_block && code == OMP_ATOMIC_CAPTURE_NEW)
+ {
+ code = OMP_ATOMIC_CAPTURE_OLD;
+ v = lhs;
+ lhs = NULL_TREE;
+ lhs1 = rhs1;
+ rhs1 = NULL_TREE;
+ cp_lexer_consume_token (parser->lexer);
+ goto restart;
+ }
+ else if (structured_block)
+ {
+ opcode = NOP_EXPR;
+ rhs = rhs1;
+ rhs1 = NULL_TREE;
+ goto stmt_done;
+ }
+ cp_parser_error (parser,
+ "invalid form of %<#pragma omp atomic%>");
+ goto saw_error;
+ case CPP_MULT:
+ opcode = MULT_EXPR;
+ break;
+ case CPP_DIV:
+ opcode = TRUNC_DIV_EXPR;
+ break;
+ case CPP_PLUS:
+ opcode = PLUS_EXPR;
+ break;
+ case CPP_MINUS:
+ opcode = MINUS_EXPR;
+ break;
+ case CPP_LSHIFT:
+ opcode = LSHIFT_EXPR;
+ break;
+ case CPP_RSHIFT:
+ opcode = RSHIFT_EXPR;
+ break;
+ case CPP_AND:
+ opcode = BIT_AND_EXPR;
+ break;
+ case CPP_OR:
+ opcode = BIT_IOR_EXPR;
+ break;
+ case CPP_XOR:
+ opcode = BIT_XOR_EXPR;
+ break;
+ default:
+ cp_parser_error (parser,
+ "invalid operator for %<#pragma omp atomic%>");
+ goto saw_error;
+ }
+ oprec = TOKEN_PRECEDENCE (token);
+ gcc_assert (oprec != PREC_NOT_OPERATOR);
+ if (commutative_tree_code (opcode))
+ oprec = (enum cp_parser_prec) (oprec - 1);
+ cp_lexer_consume_token (parser->lexer);
+ rhs = cp_parser_binary_expression (parser, false, false,
+ oprec, NULL);
+ if (rhs == error_mark_node)
+ goto saw_error;
+ goto stmt_done;
+ /* FALLTHROUGH */
+ default:
+ cp_parser_error (parser,
+ "invalid operator for %<#pragma omp atomic%>");
+ goto saw_error;
+ }
+ cp_lexer_consume_token (parser->lexer);
+
+ rhs = cp_parser_expression (parser, false, NULL);
+ if (rhs == error_mark_node)
+ goto saw_error;
+ break;
+ }
+ stmt_done:
+ if (structured_block && code == OMP_ATOMIC_CAPTURE_NEW)
+ {
+ if (!cp_parser_require (parser, CPP_SEMICOLON, RT_SEMICOLON))
+ goto saw_error;
+ v = cp_parser_unary_expression (parser, /*address_p=*/false,
+ /*cast_p=*/false, NULL);
+ if (v == error_mark_node)
+ goto saw_error;
+ if (!cp_parser_require (parser, CPP_EQ, RT_EQ))
+ goto saw_error;
+ lhs1 = cp_parser_unary_expression (parser, /*address_p=*/false,
+ /*cast_p=*/false, NULL);
+ if (lhs1 == error_mark_node)
+ goto saw_error;
+ }
+ if (structured_block)
+ {
+ cp_parser_consume_semicolon_at_end_of_statement (parser);
+ cp_parser_require (parser, CPP_CLOSE_BRACE, RT_CLOSE_BRACE);
+ }
+ done:
+ finish_omp_atomic (code, opcode, lhs, rhs, v, lhs1, rhs1, seq_cst);
+ if (!structured_block)
+ cp_parser_consume_semicolon_at_end_of_statement (parser);
+ return;
+
+ saw_error:
+ cp_parser_skip_to_end_of_block_or_statement (parser);
+ if (structured_block)
+ {
+ if (cp_lexer_next_token_is (parser->lexer, CPP_CLOSE_BRACE))
+ cp_lexer_consume_token (parser->lexer);
+ else if (code == OMP_ATOMIC_CAPTURE_NEW)
+ {
+ cp_parser_skip_to_end_of_block_or_statement (parser);
+ if (cp_lexer_next_token_is (parser->lexer, CPP_CLOSE_BRACE))
+ cp_lexer_consume_token (parser->lexer);
+ }
+ }
+ }
+
+
+ /* OpenMP 2.5:
+ # pragma omp barrier new-line */
+
+ static void
+ cp_parser_omp_barrier (cp_parser *parser, cp_token *pragma_tok)
+ {
+ cp_parser_require_pragma_eol (parser, pragma_tok);
+ finish_omp_barrier ();
+ }
+
+ /* OpenMP 2.5:
+ # pragma omp critical [(name)] new-line
+ structured-block */
+
+ static tree
+ cp_parser_omp_critical (cp_parser *parser, cp_token *pragma_tok)
+ {
+ tree stmt, name = NULL;
+
+ if (cp_lexer_next_token_is (parser->lexer, CPP_OPEN_PAREN))
+ {
+ cp_lexer_consume_token (parser->lexer);
+
+ name = cp_parser_identifier (parser);
+
+ if (name == error_mark_node
+ || !cp_parser_require (parser, CPP_CLOSE_PAREN, RT_CLOSE_PAREN))
+ cp_parser_skip_to_closing_parenthesis (parser, /*recovering=*/true,
+ /*or_comma=*/false,
+ /*consume_paren=*/true);
+ if (name == error_mark_node)
+ name = NULL;
+ }
+ cp_parser_require_pragma_eol (parser, pragma_tok);
+
+ stmt = cp_parser_omp_structured_block (parser);
+ return c_finish_omp_critical (input_location, stmt, name);
+ }
+
+ /* OpenMP 2.5:
+ # pragma omp flush flush-vars[opt] new-line
+
+ flush-vars:
+ ( variable-list ) */
+
+ static void
+ cp_parser_omp_flush (cp_parser *parser, cp_token *pragma_tok)
+ {
+ if (cp_lexer_next_token_is (parser->lexer, CPP_OPEN_PAREN))
+ (void) cp_parser_omp_var_list (parser, OMP_CLAUSE_ERROR, NULL);
+ cp_parser_require_pragma_eol (parser, pragma_tok);
+
+ finish_omp_flush ();
+ }
+
+ /* Helper function, to parse omp for increment expression. */
+
+ static tree
+ cp_parser_omp_for_cond (cp_parser *parser, tree decl)
+ {
+ tree cond = cp_parser_binary_expression (parser, false, true,
+ PREC_NOT_OPERATOR, NULL);
+ if (cond == error_mark_node
+ || cp_lexer_next_token_is_not (parser->lexer, CPP_SEMICOLON))
+ {
+ cp_parser_skip_to_end_of_statement (parser);
+ return error_mark_node;
+ }
+
+ switch (TREE_CODE (cond))
+ {
+ case GT_EXPR:
+ case GE_EXPR:
+ case LT_EXPR:
+ case LE_EXPR:
+ break;
+ default:
+ return error_mark_node;
+ }
+
+ /* If decl is an iterator, preserve LHS and RHS of the relational
+ expr until finish_omp_for. */
+ if (decl
+ && (type_dependent_expression_p (decl)
+ || CLASS_TYPE_P (TREE_TYPE (decl))))
+ return cond;
+
+ return build_x_binary_op (input_location, TREE_CODE (cond),
+ TREE_OPERAND (cond, 0), ERROR_MARK,
+ TREE_OPERAND (cond, 1), ERROR_MARK,
+ /*overload=*/NULL, tf_warning_or_error);
+ }
+
+ /* Helper function, to parse omp for increment expression. */
+
+ static tree
+ cp_parser_omp_for_incr (cp_parser *parser, tree decl)
+ {
+ cp_token *token = cp_lexer_peek_token (parser->lexer);
+ enum tree_code op;
+ tree lhs, rhs;
+ cp_id_kind idk;
+ bool decl_first;
+
+ if (token->type == CPP_PLUS_PLUS || token->type == CPP_MINUS_MINUS)
+ {
+ op = (token->type == CPP_PLUS_PLUS
+ ? PREINCREMENT_EXPR : PREDECREMENT_EXPR);
+ cp_lexer_consume_token (parser->lexer);
+ lhs = cp_parser_simple_cast_expression (parser);
+ if (lhs != decl)
+ return error_mark_node;
+ return build2 (op, TREE_TYPE (decl), decl, NULL_TREE);
+ }
+
+ lhs = cp_parser_primary_expression (parser, false, false, false, &idk);
+ if (lhs != decl)
+ return error_mark_node;
+
+ token = cp_lexer_peek_token (parser->lexer);
+ if (token->type == CPP_PLUS_PLUS || token->type == CPP_MINUS_MINUS)
+ {
+ op = (token->type == CPP_PLUS_PLUS
+ ? POSTINCREMENT_EXPR : POSTDECREMENT_EXPR);
+ cp_lexer_consume_token (parser->lexer);
+ return build2 (op, TREE_TYPE (decl), decl, NULL_TREE);
+ }
+
+ op = cp_parser_assignment_operator_opt (parser);
+ if (op == ERROR_MARK)
+ return error_mark_node;
+
+ if (op != NOP_EXPR)
+ {
+ rhs = cp_parser_assignment_expression (parser, false, NULL);
+ rhs = build2 (op, TREE_TYPE (decl), decl, rhs);
+ return build2 (MODIFY_EXPR, TREE_TYPE (decl), decl, rhs);
+ }
+
+ lhs = cp_parser_binary_expression (parser, false, false,
+ PREC_ADDITIVE_EXPRESSION, NULL);
+ token = cp_lexer_peek_token (parser->lexer);
+ decl_first = lhs == decl;
+ if (decl_first)
+ lhs = NULL_TREE;
+ if (token->type != CPP_PLUS
+ && token->type != CPP_MINUS)
+ return error_mark_node;
+
+ do
+ {
+ op = token->type == CPP_PLUS ? PLUS_EXPR : MINUS_EXPR;
+ cp_lexer_consume_token (parser->lexer);
+ rhs = cp_parser_binary_expression (parser, false, false,
+ PREC_ADDITIVE_EXPRESSION, NULL);
+ token = cp_lexer_peek_token (parser->lexer);
+ if (token->type == CPP_PLUS || token->type == CPP_MINUS || decl_first)
+ {
+ if (lhs == NULL_TREE)
+ {
+ if (op == PLUS_EXPR)
+ lhs = rhs;
+ else
+ lhs = build_x_unary_op (input_location, NEGATE_EXPR, rhs,
+ tf_warning_or_error);
+ }
+ else
+ lhs = build_x_binary_op (input_location, op, lhs, ERROR_MARK, rhs,
+ ERROR_MARK, NULL, tf_warning_or_error);
+ }
+ }
+ while (token->type == CPP_PLUS || token->type == CPP_MINUS);
+
+ if (!decl_first)
+ {
+ if (rhs != decl || op == MINUS_EXPR)
+ return error_mark_node;
+ rhs = build2 (op, TREE_TYPE (decl), lhs, decl);
+ }
+ else
+ rhs = build2 (PLUS_EXPR, TREE_TYPE (decl), decl, lhs);
+
+ return build2 (MODIFY_EXPR, TREE_TYPE (decl), decl, rhs);
+ }
+
+ /* Parse the restricted form of the for statement allowed by OpenMP. */
+
+ static tree
+ cp_parser_omp_for_loop (cp_parser *parser, enum tree_code code, tree clauses,
+ tree *cclauses)
+ {
+ tree init, cond, incr, body, decl, pre_body = NULL_TREE, ret;
+ tree real_decl, initv, condv, incrv, declv;
+ tree this_pre_body, cl;
+ location_t loc_first;
+ bool collapse_err = false;
+ int i, collapse = 1, nbraces = 0;
+ vec<tree, va_gc> *for_block = make_tree_vector ();
+
+ for (cl = clauses; cl; cl = OMP_CLAUSE_CHAIN (cl))
+ if (OMP_CLAUSE_CODE (cl) == OMP_CLAUSE_COLLAPSE)
- collapse = tree_low_cst (OMP_CLAUSE_COLLAPSE_EXPR (cl), 0);
++ collapse = tree_to_shwi (OMP_CLAUSE_COLLAPSE_EXPR (cl));
+
+ gcc_assert (collapse >= 1);
+
+ declv = make_tree_vec (collapse);
+ initv = make_tree_vec (collapse);
+ condv = make_tree_vec (collapse);
+ incrv = make_tree_vec (collapse);
+
+ loc_first = cp_lexer_peek_token (parser->lexer)->location;
+
+ for (i = 0; i < collapse; i++)
+ {
+ int bracecount = 0;
+ bool add_private_clause = false;
+ location_t loc;
+
+ if (!cp_lexer_next_token_is_keyword (parser->lexer, RID_FOR))
+ {
+ cp_parser_error (parser, "for statement expected");
+ return NULL;
+ }
+ loc = cp_lexer_consume_token (parser->lexer)->location;
+
+ if (!cp_parser_require (parser, CPP_OPEN_PAREN, RT_OPEN_PAREN))
+ return NULL;
+
+ init = decl = real_decl = NULL;
+ this_pre_body = push_stmt_list ();
+ if (cp_lexer_next_token_is_not (parser->lexer, CPP_SEMICOLON))
+ {
+ /* See 2.5.1 (in OpenMP 3.0, similar wording is in 2.5 standard too):
+
+ init-expr:
+ var = lb
+ integer-type var = lb
+ random-access-iterator-type var = lb
+ pointer-type var = lb
+ */
+ cp_decl_specifier_seq type_specifiers;
+
+ /* First, try to parse as an initialized declaration. See
+ cp_parser_condition, from whence the bulk of this is copied. */
+
+ cp_parser_parse_tentatively (parser);
+ cp_parser_type_specifier_seq (parser, /*is_declaration=*/true,
+ /*is_trailing_return=*/false,
+ &type_specifiers);
+ if (cp_parser_parse_definitely (parser))
+ {
+ /* If parsing a type specifier seq succeeded, then this
+ MUST be a initialized declaration. */
+ tree asm_specification, attributes;
+ cp_declarator *declarator;
+
+ declarator = cp_parser_declarator (parser,
+ CP_PARSER_DECLARATOR_NAMED,
+ /*ctor_dtor_or_conv_p=*/NULL,
+ /*parenthesized_p=*/NULL,
+ /*member_p=*/false);
+ attributes = cp_parser_attributes_opt (parser);
+ asm_specification = cp_parser_asm_specification_opt (parser);
+
+ if (declarator == cp_error_declarator)
+ cp_parser_skip_to_end_of_statement (parser);
+
+ else
+ {
+ tree pushed_scope, auto_node;
+
+ decl = start_decl (declarator, &type_specifiers,
+ SD_INITIALIZED, attributes,
+ /*prefix_attributes=*/NULL_TREE,
+ &pushed_scope);
+
+ auto_node = type_uses_auto (TREE_TYPE (decl));
+ if (cp_lexer_next_token_is_not (parser->lexer, CPP_EQ))
+ {
+ if (cp_lexer_next_token_is (parser->lexer,
+ CPP_OPEN_PAREN))
+ error ("parenthesized initialization is not allowed in "
+ "OpenMP %<for%> loop");
+ else
+ /* Trigger an error. */
+ cp_parser_require (parser, CPP_EQ, RT_EQ);
+
+ init = error_mark_node;
+ cp_parser_skip_to_end_of_statement (parser);
+ }
+ else if (CLASS_TYPE_P (TREE_TYPE (decl))
+ || type_dependent_expression_p (decl)
+ || auto_node)
+ {
+ bool is_direct_init, is_non_constant_init;
+
+ init = cp_parser_initializer (parser,
+ &is_direct_init,
+ &is_non_constant_init);
+
+ if (auto_node)
+ {
+ TREE_TYPE (decl)
+ = do_auto_deduction (TREE_TYPE (decl), init,
+ auto_node);
+
+ if (!CLASS_TYPE_P (TREE_TYPE (decl))
+ && !type_dependent_expression_p (decl))
+ goto non_class;
+ }
+
+ cp_finish_decl (decl, init, !is_non_constant_init,
+ asm_specification,
+ LOOKUP_ONLYCONVERTING);
+ if (CLASS_TYPE_P (TREE_TYPE (decl)))
+ {
+ vec_safe_push (for_block, this_pre_body);
+ init = NULL_TREE;
+ }
+ else
+ init = pop_stmt_list (this_pre_body);
+ this_pre_body = NULL_TREE;
+ }
+ else
+ {
+ /* Consume '='. */
+ cp_lexer_consume_token (parser->lexer);
+ init = cp_parser_assignment_expression (parser, false, NULL);
+
+ non_class:
+ if (TREE_CODE (TREE_TYPE (decl)) == REFERENCE_TYPE)
+ init = error_mark_node;
+ else
+ cp_finish_decl (decl, NULL_TREE,
+ /*init_const_expr_p=*/false,
+ asm_specification,
+ LOOKUP_ONLYCONVERTING);
+ }
+
+ if (pushed_scope)
+ pop_scope (pushed_scope);
+ }
+ }
+ else
+ {
+ cp_id_kind idk;
+ /* If parsing a type specifier sequence failed, then
+ this MUST be a simple expression. */
+ cp_parser_parse_tentatively (parser);
+ decl = cp_parser_primary_expression (parser, false, false,
+ false, &idk);
+ if (!cp_parser_error_occurred (parser)
+ && decl
+ && DECL_P (decl)
+ && CLASS_TYPE_P (TREE_TYPE (decl)))
{
- tree pushed_scope, auto_node;
+ tree rhs;
+
+ cp_parser_parse_definitely (parser);
+ cp_parser_require (parser, CPP_EQ, RT_EQ);
+ rhs = cp_parser_assignment_expression (parser, false, NULL);
+ finish_expr_stmt (build_x_modify_expr (EXPR_LOCATION (rhs),
+ decl, NOP_EXPR,
+ rhs,
+ tf_warning_or_error));
+ add_private_clause = true;
+ }
+ else
+ {
+ decl = NULL;
+ cp_parser_abort_tentative_parse (parser);
+ init = cp_parser_expression (parser, false, NULL);
+ if (init)
+ {
+ if (TREE_CODE (init) == MODIFY_EXPR
+ || TREE_CODE (init) == MODOP_EXPR)
+ real_decl = TREE_OPERAND (init, 0);
+ }
+ }
+ }
+ }
+ cp_parser_require (parser, CPP_SEMICOLON, RT_SEMICOLON);
+ if (this_pre_body)
+ {
+ this_pre_body = pop_stmt_list (this_pre_body);
+ if (pre_body)
+ {
+ tree t = pre_body;
+ pre_body = push_stmt_list ();
+ add_stmt (t);
+ add_stmt (this_pre_body);
+ pre_body = pop_stmt_list (pre_body);
+ }
+ else
+ pre_body = this_pre_body;
+ }
+
+ if (decl)
+ real_decl = decl;
+ if (cclauses != NULL
+ && cclauses[C_OMP_CLAUSE_SPLIT_PARALLEL] != NULL
+ && real_decl != NULL_TREE)
+ {
+ tree *c;
+ for (c = &cclauses[C_OMP_CLAUSE_SPLIT_PARALLEL]; *c ; )
+ if (OMP_CLAUSE_CODE (*c) == OMP_CLAUSE_FIRSTPRIVATE
+ && OMP_CLAUSE_DECL (*c) == real_decl)
+ {
+ error_at (loc, "iteration variable %qD"
+ " should not be firstprivate", real_decl);
+ *c = OMP_CLAUSE_CHAIN (*c);
+ }
+ else if (OMP_CLAUSE_CODE (*c) == OMP_CLAUSE_LASTPRIVATE
+ && OMP_CLAUSE_DECL (*c) == real_decl)
+ {
+ /* Add lastprivate (decl) clause to OMP_FOR_CLAUSES,
+ change it to shared (decl) in OMP_PARALLEL_CLAUSES. */
+ tree l = build_omp_clause (loc, OMP_CLAUSE_LASTPRIVATE);
+ OMP_CLAUSE_DECL (l) = real_decl;
+ OMP_CLAUSE_CHAIN (l) = clauses;
+ CP_OMP_CLAUSE_INFO (l) = CP_OMP_CLAUSE_INFO (*c);
+ clauses = l;
+ OMP_CLAUSE_SET_CODE (*c, OMP_CLAUSE_SHARED);
+ CP_OMP_CLAUSE_INFO (*c) = NULL;
+ add_private_clause = false;
+ }
+ else
+ {
+ if (OMP_CLAUSE_CODE (*c) == OMP_CLAUSE_PRIVATE
+ && OMP_CLAUSE_DECL (*c) == real_decl)
+ add_private_clause = false;
+ c = &OMP_CLAUSE_CHAIN (*c);
+ }
+ }
+
+ if (add_private_clause)
+ {
+ tree c;
+ for (c = clauses; c ; c = OMP_CLAUSE_CHAIN (c))
+ {
+ if ((OMP_CLAUSE_CODE (c) == OMP_CLAUSE_PRIVATE
+ || OMP_CLAUSE_CODE (c) == OMP_CLAUSE_LASTPRIVATE)
+ && OMP_CLAUSE_DECL (c) == decl)
+ break;
+ else if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_FIRSTPRIVATE
+ && OMP_CLAUSE_DECL (c) == decl)
+ error_at (loc, "iteration variable %qD "
+ "should not be firstprivate",
+ decl);
+ else if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_REDUCTION
+ && OMP_CLAUSE_DECL (c) == decl)
+ error_at (loc, "iteration variable %qD should not be reduction",
+ decl);
+ }
+ if (c == NULL)
+ {
+ c = build_omp_clause (loc, OMP_CLAUSE_PRIVATE);
+ OMP_CLAUSE_DECL (c) = decl;
+ c = finish_omp_clauses (c);
+ if (c)
+ {
+ OMP_CLAUSE_CHAIN (c) = clauses;
+ clauses = c;
+ }
+ }
+ }
+
+ cond = NULL;
+ if (cp_lexer_next_token_is_not (parser->lexer, CPP_SEMICOLON))
+ cond = cp_parser_omp_for_cond (parser, decl);
+ cp_parser_require (parser, CPP_SEMICOLON, RT_SEMICOLON);
+
+ incr = NULL;
+ if (cp_lexer_next_token_is_not (parser->lexer, CPP_CLOSE_PAREN))
+ {
+ /* If decl is an iterator, preserve the operator on decl
+ until finish_omp_for. */
+ if (real_decl
+ && ((processing_template_decl
+ && !POINTER_TYPE_P (TREE_TYPE (real_decl)))
+ || CLASS_TYPE_P (TREE_TYPE (real_decl))))
+ incr = cp_parser_omp_for_incr (parser, real_decl);
+ else
+ incr = cp_parser_expression (parser, false, NULL);
+ if (CAN_HAVE_LOCATION_P (incr) && !EXPR_HAS_LOCATION (incr))
+ SET_EXPR_LOCATION (incr, input_location);
+ }
+
+ if (!cp_parser_require (parser, CPP_CLOSE_PAREN, RT_CLOSE_PAREN))
+ cp_parser_skip_to_closing_parenthesis (parser, /*recovering=*/true,
+ /*or_comma=*/false,
+ /*consume_paren=*/true);
+
+ TREE_VEC_ELT (declv, i) = decl;
+ TREE_VEC_ELT (initv, i) = init;
+ TREE_VEC_ELT (condv, i) = cond;
+ TREE_VEC_ELT (incrv, i) = incr;
+
+ if (i == collapse - 1)
+ break;
+
+ /* FIXME: OpenMP 3.0 draft isn't very clear on what exactly is allowed
+ in between the collapsed for loops to be still considered perfectly
+ nested. Hopefully the final version clarifies this.
+ For now handle (multiple) {'s and empty statements. */
+ cp_parser_parse_tentatively (parser);
+ do
+ {
+ if (cp_lexer_next_token_is_keyword (parser->lexer, RID_FOR))
+ break;
+ else if (cp_lexer_next_token_is (parser->lexer, CPP_OPEN_BRACE))
+ {
+ cp_lexer_consume_token (parser->lexer);
+ bracecount++;
+ }
+ else if (bracecount
+ && cp_lexer_next_token_is (parser->lexer, CPP_SEMICOLON))
+ cp_lexer_consume_token (parser->lexer);
+ else
+ {
+ loc = cp_lexer_peek_token (parser->lexer)->location;
+ error_at (loc, "not enough collapsed for loops");
+ collapse_err = true;
+ cp_parser_abort_tentative_parse (parser);
+ declv = NULL_TREE;
+ break;
+ }
+ }
+ while (1);
+
+ if (declv)
+ {
+ cp_parser_parse_definitely (parser);
+ nbraces += bracecount;
+ }
+ }
+
+ /* Note that we saved the original contents of this flag when we entered
+ the structured block, and so we don't need to re-save it here. */
+ parser->in_statement = IN_OMP_FOR;
+
+ /* Note that the grammar doesn't call for a structured block here,
+ though the loop as a whole is a structured block. */
+ body = push_stmt_list ();
+ cp_parser_statement (parser, NULL_TREE, false, NULL);
+ body = pop_stmt_list (body);
+
+ if (declv == NULL_TREE)
+ ret = NULL_TREE;
+ else
+ ret = finish_omp_for (loc_first, code, declv, initv, condv, incrv, body,
+ pre_body, clauses);
+
+ while (nbraces)
+ {
+ if (cp_lexer_next_token_is (parser->lexer, CPP_CLOSE_BRACE))
+ {
+ cp_lexer_consume_token (parser->lexer);
+ nbraces--;
+ }
+ else if (cp_lexer_next_token_is (parser->lexer, CPP_SEMICOLON))
+ cp_lexer_consume_token (parser->lexer);
+ else
+ {
+ if (!collapse_err)
+ {
+ error_at (cp_lexer_peek_token (parser->lexer)->location,
+ "collapsed loops not perfectly nested");
+ }
+ collapse_err = true;
+ cp_parser_statement_seq_opt (parser, NULL);
+ if (cp_lexer_next_token_is (parser->lexer, CPP_EOF))
+ break;
+ }
+ }
+
+ while (!for_block->is_empty ())
+ add_stmt (pop_stmt_list (for_block->pop ()));
+ release_tree_vector (for_block);
+
+ return ret;
+ }
+
+ /* Helper function for OpenMP parsing, split clauses and call
+ finish_omp_clauses on each of the set of clauses afterwards. */
+
+ static void
+ cp_omp_split_clauses (location_t loc, enum tree_code code,
+ omp_clause_mask mask, tree clauses, tree *cclauses)
+ {
+ int i;
+ c_omp_split_clauses (loc, code, mask, clauses, cclauses);
+ for (i = 0; i < C_OMP_CLAUSE_SPLIT_COUNT; i++)
+ if (cclauses[i])
+ cclauses[i] = finish_omp_clauses (cclauses[i]);
+ }
+
+ /* OpenMP 4.0:
+ #pragma omp simd simd-clause[optseq] new-line
+ for-loop */
+
+ #define OMP_SIMD_CLAUSE_MASK \
+ ( (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_SAFELEN) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_LINEAR) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_ALIGNED) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_PRIVATE) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_LASTPRIVATE) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_REDUCTION) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_COLLAPSE))
+
+ static tree
+ cp_parser_omp_simd (cp_parser *parser, cp_token *pragma_tok,
+ char *p_name, omp_clause_mask mask, tree *cclauses)
+ {
+ tree clauses, sb, ret;
+ unsigned int save;
+ location_t loc = cp_lexer_peek_token (parser->lexer)->location;
- decl = start_decl (declarator, &type_specifiers,
- SD_INITIALIZED, attributes,
- /*prefix_attributes=*/NULL_TREE,
- &pushed_scope);
+ strcat (p_name, " simd");
+ mask |= OMP_SIMD_CLAUSE_MASK;
+ mask &= ~(OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_ORDERED);
- auto_node = type_uses_auto (TREE_TYPE (decl));
- if (cp_lexer_next_token_is_not (parser->lexer, CPP_EQ))
- {
- if (cp_lexer_next_token_is (parser->lexer,
- CPP_OPEN_PAREN))
- error ("parenthesized initialization is not allowed in "
- "OpenMP %<for%> loop");
- else
- /* Trigger an error. */
- cp_parser_require (parser, CPP_EQ, RT_EQ);
+ clauses = cp_parser_omp_all_clauses (parser, mask, p_name, pragma_tok,
+ cclauses == NULL);
+ if (cclauses)
+ {
+ cp_omp_split_clauses (loc, OMP_SIMD, mask, clauses, cclauses);
+ clauses = cclauses[C_OMP_CLAUSE_SPLIT_SIMD];
+ }
- init = error_mark_node;
- cp_parser_skip_to_end_of_statement (parser);
- }
- else if (CLASS_TYPE_P (TREE_TYPE (decl))
- || type_dependent_expression_p (decl)
- || auto_node)
- {
- bool is_direct_init, is_non_constant_init;
+ sb = begin_omp_structured_block ();
+ save = cp_parser_begin_omp_structured_block (parser);
- init = cp_parser_initializer (parser,
- &is_direct_init,
- &is_non_constant_init);
+ ret = cp_parser_omp_for_loop (parser, OMP_SIMD, clauses, cclauses);
+
+ cp_parser_end_omp_structured_block (parser, save);
+ add_stmt (finish_omp_structured_block (sb));
+
+ return ret;
+ }
+
+ /* OpenMP 2.5:
+ #pragma omp for for-clause[optseq] new-line
+ for-loop
+
+ OpenMP 4.0:
+ #pragma omp for simd for-simd-clause[optseq] new-line
+ for-loop */
+
+ #define OMP_FOR_CLAUSE_MASK \
+ ( (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_PRIVATE) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_FIRSTPRIVATE) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_LASTPRIVATE) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_REDUCTION) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_ORDERED) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_SCHEDULE) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_NOWAIT) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_COLLAPSE))
+
+ static tree
+ cp_parser_omp_for (cp_parser *parser, cp_token *pragma_tok,
+ char *p_name, omp_clause_mask mask, tree *cclauses)
+ {
+ tree clauses, sb, ret;
+ unsigned int save;
+ location_t loc = cp_lexer_peek_token (parser->lexer)->location;
+
+ strcat (p_name, " for");
+ mask |= OMP_FOR_CLAUSE_MASK;
+ if (cclauses)
+ mask &= ~(OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_NOWAIT);
+
+ if (cp_lexer_next_token_is (parser->lexer, CPP_NAME))
+ {
+ tree id = cp_lexer_peek_token (parser->lexer)->u.value;
+ const char *p = IDENTIFIER_POINTER (id);
+
+ if (strcmp (p, "simd") == 0)
+ {
+ tree cclauses_buf[C_OMP_CLAUSE_SPLIT_COUNT];
+ if (cclauses == NULL)
+ cclauses = cclauses_buf;
+
+ cp_lexer_consume_token (parser->lexer);
+ sb = begin_omp_structured_block ();
+ save = cp_parser_begin_omp_structured_block (parser);
+ ret = cp_parser_omp_simd (parser, pragma_tok, p_name, mask,
+ cclauses);
+ cp_parser_end_omp_structured_block (parser, save);
+ tree body = finish_omp_structured_block (sb);
+ if (ret == NULL)
+ return ret;
+ ret = make_node (OMP_FOR);
+ TREE_TYPE (ret) = void_type_node;
+ OMP_FOR_BODY (ret) = body;
+ OMP_FOR_CLAUSES (ret) = cclauses[C_OMP_CLAUSE_SPLIT_FOR];
+ SET_EXPR_LOCATION (ret, loc);
+ add_stmt (ret);
+ return ret;
+ }
+ }
+
+ clauses = cp_parser_omp_all_clauses (parser, mask, p_name, pragma_tok,
+ cclauses == NULL);
+ if (cclauses)
+ {
+ cp_omp_split_clauses (loc, OMP_FOR, mask, clauses, cclauses);
+ clauses = cclauses[C_OMP_CLAUSE_SPLIT_FOR];
+ }
+
+ sb = begin_omp_structured_block ();
+ save = cp_parser_begin_omp_structured_block (parser);
+
+ ret = cp_parser_omp_for_loop (parser, OMP_FOR, clauses, cclauses);
+
+ cp_parser_end_omp_structured_block (parser, save);
+ add_stmt (finish_omp_structured_block (sb));
+
+ return ret;
+ }
+
+ /* OpenMP 2.5:
+ # pragma omp master new-line
+ structured-block */
+
+ static tree
+ cp_parser_omp_master (cp_parser *parser, cp_token *pragma_tok)
+ {
+ cp_parser_require_pragma_eol (parser, pragma_tok);
+ return c_finish_omp_master (input_location,
+ cp_parser_omp_structured_block (parser));
+ }
+
+ /* OpenMP 2.5:
+ # pragma omp ordered new-line
+ structured-block */
+
+ static tree
+ cp_parser_omp_ordered (cp_parser *parser, cp_token *pragma_tok)
+ {
+ location_t loc = cp_lexer_peek_token (parser->lexer)->location;
+ cp_parser_require_pragma_eol (parser, pragma_tok);
+ return c_finish_omp_ordered (loc, cp_parser_omp_structured_block (parser));
+ }
+
+ /* OpenMP 2.5:
+
+ section-scope:
+ { section-sequence }
+
+ section-sequence:
+ section-directive[opt] structured-block
+ section-sequence section-directive structured-block */
+
+ static tree
+ cp_parser_omp_sections_scope (cp_parser *parser)
+ {
+ tree stmt, substmt;
+ bool error_suppress = false;
+ cp_token *tok;
+
+ if (!cp_parser_require (parser, CPP_OPEN_BRACE, RT_OPEN_BRACE))
+ return NULL_TREE;
+
+ stmt = push_stmt_list ();
+
+ if (cp_lexer_peek_token (parser->lexer)->pragma_kind != PRAGMA_OMP_SECTION)
+ {
+ substmt = cp_parser_omp_structured_block (parser);
+ substmt = build1 (OMP_SECTION, void_type_node, substmt);
+ add_stmt (substmt);
+ }
+
+ while (1)
+ {
+ tok = cp_lexer_peek_token (parser->lexer);
+ if (tok->type == CPP_CLOSE_BRACE)
+ break;
+ if (tok->type == CPP_EOF)
+ break;
+
+ if (tok->pragma_kind == PRAGMA_OMP_SECTION)
+ {
+ cp_lexer_consume_token (parser->lexer);
+ cp_parser_require_pragma_eol (parser, tok);
+ error_suppress = false;
+ }
+ else if (!error_suppress)
+ {
+ cp_parser_error (parser, "expected %<#pragma omp section%> or %<}%>");
+ error_suppress = true;
+ }
+
+ substmt = cp_parser_omp_structured_block (parser);
+ substmt = build1 (OMP_SECTION, void_type_node, substmt);
+ add_stmt (substmt);
+ }
+ cp_parser_require (parser, CPP_CLOSE_BRACE, RT_CLOSE_BRACE);
+
+ substmt = pop_stmt_list (stmt);
+
+ stmt = make_node (OMP_SECTIONS);
+ TREE_TYPE (stmt) = void_type_node;
+ OMP_SECTIONS_BODY (stmt) = substmt;
+
+ add_stmt (stmt);
+ return stmt;
+ }
+
+ /* OpenMP 2.5:
+ # pragma omp sections sections-clause[optseq] newline
+ sections-scope */
+
+ #define OMP_SECTIONS_CLAUSE_MASK \
+ ( (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_PRIVATE) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_FIRSTPRIVATE) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_LASTPRIVATE) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_REDUCTION) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_NOWAIT))
+
+ static tree
+ cp_parser_omp_sections (cp_parser *parser, cp_token *pragma_tok,
+ char *p_name, omp_clause_mask mask, tree *cclauses)
+ {
+ tree clauses, ret;
+ location_t loc = cp_lexer_peek_token (parser->lexer)->location;
+
+ strcat (p_name, " sections");
+ mask |= OMP_SECTIONS_CLAUSE_MASK;
+ if (cclauses)
+ mask &= ~(OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_NOWAIT);
+
+ clauses = cp_parser_omp_all_clauses (parser, mask, p_name, pragma_tok,
+ cclauses == NULL);
+ if (cclauses)
+ {
+ cp_omp_split_clauses (loc, OMP_SECTIONS, mask, clauses, cclauses);
+ clauses = cclauses[C_OMP_CLAUSE_SPLIT_SECTIONS];
+ }
+
+ ret = cp_parser_omp_sections_scope (parser);
+ if (ret)
+ OMP_SECTIONS_CLAUSES (ret) = clauses;
+
+ return ret;
+ }
+
+ /* OpenMP 2.5:
+ # pragma parallel parallel-clause new-line
+ # pragma parallel for parallel-for-clause new-line
+ # pragma parallel sections parallel-sections-clause new-line
+
+ OpenMP 4.0:
+ # pragma parallel for simd parallel-for-simd-clause new-line */
+
+ #define OMP_PARALLEL_CLAUSE_MASK \
+ ( (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_IF) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_PRIVATE) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_FIRSTPRIVATE) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_DEFAULT) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_SHARED) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_COPYIN) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_REDUCTION) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_NUM_THREADS) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_PROC_BIND))
+
+ static tree
+ cp_parser_omp_parallel (cp_parser *parser, cp_token *pragma_tok,
+ char *p_name, omp_clause_mask mask, tree *cclauses)
+ {
+ tree stmt, clauses, block;
+ unsigned int save;
+ location_t loc = cp_lexer_peek_token (parser->lexer)->location;
+
+ strcat (p_name, " parallel");
+ mask |= OMP_PARALLEL_CLAUSE_MASK;
+
+ if (cp_lexer_next_token_is_keyword (parser->lexer, RID_FOR))
+ {
+ tree cclauses_buf[C_OMP_CLAUSE_SPLIT_COUNT];
+ if (cclauses == NULL)
+ cclauses = cclauses_buf;
+
+ cp_lexer_consume_token (parser->lexer);
+ block = begin_omp_parallel ();
+ save = cp_parser_begin_omp_structured_block (parser);
+ cp_parser_omp_for (parser, pragma_tok, p_name, mask, cclauses);
+ cp_parser_end_omp_structured_block (parser, save);
+ stmt = finish_omp_parallel (cclauses[C_OMP_CLAUSE_SPLIT_PARALLEL],
+ block);
+ OMP_PARALLEL_COMBINED (stmt) = 1;
+ return stmt;
+ }
+ else if (cclauses)
+ {
+ error_at (loc, "expected %<for%> after %qs", p_name);
+ cp_parser_skip_to_pragma_eol (parser, pragma_tok);
+ return NULL_TREE;
+ }
+ else if (cp_lexer_next_token_is (parser->lexer, CPP_NAME))
+ {
+ tree id = cp_lexer_peek_token (parser->lexer)->u.value;
+ const char *p = IDENTIFIER_POINTER (id);
+ if (strcmp (p, "sections") == 0)
+ {
+ tree cclauses_buf[C_OMP_CLAUSE_SPLIT_COUNT];
+ cclauses = cclauses_buf;
+
+ cp_lexer_consume_token (parser->lexer);
+ block = begin_omp_parallel ();
+ save = cp_parser_begin_omp_structured_block (parser);
+ cp_parser_omp_sections (parser, pragma_tok, p_name, mask, cclauses);
+ cp_parser_end_omp_structured_block (parser, save);
+ stmt = finish_omp_parallel (cclauses[C_OMP_CLAUSE_SPLIT_PARALLEL],
+ block);
+ OMP_PARALLEL_COMBINED (stmt) = 1;
+ return stmt;
+ }
+ }
+
+ clauses = cp_parser_omp_all_clauses (parser, mask, p_name, pragma_tok);
+
+ block = begin_omp_parallel ();
+ save = cp_parser_begin_omp_structured_block (parser);
+ cp_parser_statement (parser, NULL_TREE, false, NULL);
+ cp_parser_end_omp_structured_block (parser, save);
+ stmt = finish_omp_parallel (clauses, block);
+ return stmt;
+ }
+
+ /* OpenMP 2.5:
+ # pragma omp single single-clause[optseq] new-line
+ structured-block */
+
+ #define OMP_SINGLE_CLAUSE_MASK \
+ ( (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_PRIVATE) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_FIRSTPRIVATE) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_COPYPRIVATE) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_NOWAIT))
+
+ static tree
+ cp_parser_omp_single (cp_parser *parser, cp_token *pragma_tok)
+ {
+ tree stmt = make_node (OMP_SINGLE);
+ TREE_TYPE (stmt) = void_type_node;
+
+ OMP_SINGLE_CLAUSES (stmt)
+ = cp_parser_omp_all_clauses (parser, OMP_SINGLE_CLAUSE_MASK,
+ "#pragma omp single", pragma_tok);
+ OMP_SINGLE_BODY (stmt) = cp_parser_omp_structured_block (parser);
+
+ return add_stmt (stmt);
+ }
+
+ /* OpenMP 3.0:
+ # pragma omp task task-clause[optseq] new-line
+ structured-block */
+
+ #define OMP_TASK_CLAUSE_MASK \
+ ( (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_IF) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_UNTIED) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_DEFAULT) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_PRIVATE) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_FIRSTPRIVATE) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_SHARED) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_FINAL) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_MERGEABLE) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_DEPEND))
+
+ static tree
+ cp_parser_omp_task (cp_parser *parser, cp_token *pragma_tok)
+ {
+ tree clauses, block;
+ unsigned int save;
+
+ clauses = cp_parser_omp_all_clauses (parser, OMP_TASK_CLAUSE_MASK,
+ "#pragma omp task", pragma_tok);
+ block = begin_omp_task ();
+ save = cp_parser_begin_omp_structured_block (parser);
+ cp_parser_statement (parser, NULL_TREE, false, NULL);
+ cp_parser_end_omp_structured_block (parser, save);
+ return finish_omp_task (clauses, block);
+ }
- if (auto_node)
- {
- TREE_TYPE (decl)
- = do_auto_deduction (TREE_TYPE (decl), init,
- auto_node);
+ /* OpenMP 3.0:
+ # pragma omp taskwait new-line */
- if (!CLASS_TYPE_P (TREE_TYPE (decl))
- && !type_dependent_expression_p (decl))
- goto non_class;
- }
-
- cp_finish_decl (decl, init, !is_non_constant_init,
- asm_specification,
- LOOKUP_ONLYCONVERTING);
- if (CLASS_TYPE_P (TREE_TYPE (decl)))
- {
- vec_safe_push (for_block, this_pre_body);
- init = NULL_TREE;
- }
- else
- init = pop_stmt_list (this_pre_body);
- this_pre_body = NULL_TREE;
- }
- else
- {
- /* Consume '='. */
- cp_lexer_consume_token (parser->lexer);
- init = cp_parser_assignment_expression (parser, false, NULL);
+ static void
+ cp_parser_omp_taskwait (cp_parser *parser, cp_token *pragma_tok)
+ {
+ cp_parser_require_pragma_eol (parser, pragma_tok);
+ finish_omp_taskwait ();
+ }
- non_class:
- if (TREE_CODE (TREE_TYPE (decl)) == REFERENCE_TYPE)
- init = error_mark_node;
- else
- cp_finish_decl (decl, NULL_TREE,
- /*init_const_expr_p=*/false,
- asm_specification,
- LOOKUP_ONLYCONVERTING);
- }
+ /* OpenMP 3.1:
+ # pragma omp taskyield new-line */
- if (pushed_scope)
- pop_scope (pushed_scope);
- }
- }
- else
- {
- cp_id_kind idk;
- /* If parsing a type specifier sequence failed, then
- this MUST be a simple expression. */
- cp_parser_parse_tentatively (parser);
- decl = cp_parser_primary_expression (parser, false, false,
- false, &idk);
- if (!cp_parser_error_occurred (parser)
- && decl
- && DECL_P (decl)
- && CLASS_TYPE_P (TREE_TYPE (decl)))
- {
- tree rhs;
+ static void
+ cp_parser_omp_taskyield (cp_parser *parser, cp_token *pragma_tok)
+ {
+ cp_parser_require_pragma_eol (parser, pragma_tok);
+ finish_omp_taskyield ();
+ }
- cp_parser_parse_definitely (parser);
- cp_parser_require (parser, CPP_EQ, RT_EQ);
- rhs = cp_parser_assignment_expression (parser, false, NULL);
- finish_expr_stmt (build_x_modify_expr (EXPR_LOCATION (rhs),
- decl, NOP_EXPR,
- rhs,
- tf_warning_or_error));
- add_private_clause = true;
- }
- else
- {
- decl = NULL;
- cp_parser_abort_tentative_parse (parser);
- init = cp_parser_expression (parser, false, NULL);
- if (init)
- {
- if (TREE_CODE (init) == MODIFY_EXPR
- || TREE_CODE (init) == MODOP_EXPR)
- real_decl = TREE_OPERAND (init, 0);
- }
- }
- }
- }
- cp_parser_require (parser, CPP_SEMICOLON, RT_SEMICOLON);
- if (this_pre_body)
- {
- this_pre_body = pop_stmt_list (this_pre_body);
- if (pre_body)
- {
- tree t = pre_body;
- pre_body = push_stmt_list ();
- add_stmt (t);
- add_stmt (this_pre_body);
- pre_body = pop_stmt_list (pre_body);
- }
- else
- pre_body = this_pre_body;
- }
+ /* OpenMP 4.0:
+ # pragma omp taskgroup new-line
+ structured-block */
- if (decl)
- real_decl = decl;
- if (par_clauses != NULL && real_decl != NULL_TREE)
- {
- tree *c;
- for (c = par_clauses; *c ; )
- if (OMP_CLAUSE_CODE (*c) == OMP_CLAUSE_FIRSTPRIVATE
- && OMP_CLAUSE_DECL (*c) == real_decl)
- {
- error_at (loc, "iteration variable %qD"
- " should not be firstprivate", real_decl);
- *c = OMP_CLAUSE_CHAIN (*c);
- }
- else if (OMP_CLAUSE_CODE (*c) == OMP_CLAUSE_LASTPRIVATE
- && OMP_CLAUSE_DECL (*c) == real_decl)
- {
- /* Add lastprivate (decl) clause to OMP_FOR_CLAUSES,
- change it to shared (decl) in OMP_PARALLEL_CLAUSES. */
- tree l = build_omp_clause (loc, OMP_CLAUSE_LASTPRIVATE);
- OMP_CLAUSE_DECL (l) = real_decl;
- OMP_CLAUSE_CHAIN (l) = clauses;
- CP_OMP_CLAUSE_INFO (l) = CP_OMP_CLAUSE_INFO (*c);
- clauses = l;
- OMP_CLAUSE_SET_CODE (*c, OMP_CLAUSE_SHARED);
- CP_OMP_CLAUSE_INFO (*c) = NULL;
- add_private_clause = false;
- }
- else
- {
- if (OMP_CLAUSE_CODE (*c) == OMP_CLAUSE_PRIVATE
- && OMP_CLAUSE_DECL (*c) == real_decl)
- add_private_clause = false;
- c = &OMP_CLAUSE_CHAIN (*c);
- }
- }
+ static tree
+ cp_parser_omp_taskgroup (cp_parser *parser, cp_token *pragma_tok)
+ {
+ cp_parser_require_pragma_eol (parser, pragma_tok);
+ return c_finish_omp_taskgroup (input_location,
+ cp_parser_omp_structured_block (parser));
+ }
- if (add_private_clause)
- {
- tree c;
- for (c = clauses; c ; c = OMP_CLAUSE_CHAIN (c))
- {
- if ((OMP_CLAUSE_CODE (c) == OMP_CLAUSE_PRIVATE
- || OMP_CLAUSE_CODE (c) == OMP_CLAUSE_LASTPRIVATE)
- && OMP_CLAUSE_DECL (c) == decl)
- break;
- else if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_FIRSTPRIVATE
- && OMP_CLAUSE_DECL (c) == decl)
- error_at (loc, "iteration variable %qD "
- "should not be firstprivate",
- decl);
- else if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_REDUCTION
- && OMP_CLAUSE_DECL (c) == decl)
- error_at (loc, "iteration variable %qD should not be reduction",
- decl);
- }
- if (c == NULL)
- {
- c = build_omp_clause (loc, OMP_CLAUSE_PRIVATE);
- OMP_CLAUSE_DECL (c) = decl;
- c = finish_omp_clauses (c);
- if (c)
- {
- OMP_CLAUSE_CHAIN (c) = clauses;
- clauses = c;
- }
- }
- }
- cond = NULL;
- if (cp_lexer_next_token_is_not (parser->lexer, CPP_SEMICOLON))
- cond = cp_parser_omp_for_cond (parser, decl);
- cp_parser_require (parser, CPP_SEMICOLON, RT_SEMICOLON);
+ /* OpenMP 2.5:
+ # pragma omp threadprivate (variable-list) */
- incr = NULL;
- if (cp_lexer_next_token_is_not (parser->lexer, CPP_CLOSE_PAREN))
- {
- /* If decl is an iterator, preserve the operator on decl
- until finish_omp_for. */
- if (real_decl
- && ((processing_template_decl
- && !POINTER_TYPE_P (TREE_TYPE (real_decl)))
- || CLASS_TYPE_P (TREE_TYPE (real_decl))))
- incr = cp_parser_omp_for_incr (parser, real_decl);
- else
- incr = cp_parser_expression (parser, false, NULL);
- if (CAN_HAVE_LOCATION_P (incr) && !EXPR_HAS_LOCATION (incr))
- SET_EXPR_LOCATION (incr, input_location);
- }
+ static void
+ cp_parser_omp_threadprivate (cp_parser *parser, cp_token *pragma_tok)
+ {
+ tree vars;
- if (!cp_parser_require (parser, CPP_CLOSE_PAREN, RT_CLOSE_PAREN))
- cp_parser_skip_to_closing_parenthesis (parser, /*recovering=*/true,
- /*or_comma=*/false,
- /*consume_paren=*/true);
+ vars = cp_parser_omp_var_list (parser, OMP_CLAUSE_ERROR, NULL);
+ cp_parser_require_pragma_eol (parser, pragma_tok);
- TREE_VEC_ELT (declv, i) = decl;
- TREE_VEC_ELT (initv, i) = init;
- TREE_VEC_ELT (condv, i) = cond;
- TREE_VEC_ELT (incrv, i) = incr;
+ finish_omp_threadprivate (vars);
+ }
- if (i == collapse - 1)
- break;
+ /* OpenMP 4.0:
+ # pragma omp cancel cancel-clause[optseq] new-line */
- /* FIXME: OpenMP 3.0 draft isn't very clear on what exactly is allowed
- in between the collapsed for loops to be still considered perfectly
- nested. Hopefully the final version clarifies this.
- For now handle (multiple) {'s and empty statements. */
- cp_parser_parse_tentatively (parser);
- do
- {
- if (cp_lexer_next_token_is_keyword (parser->lexer, RID_FOR))
- break;
- else if (cp_lexer_next_token_is (parser->lexer, CPP_OPEN_BRACE))
- {
- cp_lexer_consume_token (parser->lexer);
- bracecount++;
- }
- else if (bracecount
- && cp_lexer_next_token_is (parser->lexer, CPP_SEMICOLON))
- cp_lexer_consume_token (parser->lexer);
- else
- {
- loc = cp_lexer_peek_token (parser->lexer)->location;
- error_at (loc, "not enough collapsed for loops");
- collapse_err = true;
- cp_parser_abort_tentative_parse (parser);
- declv = NULL_TREE;
- break;
- }
- }
- while (1);
+ #define OMP_CANCEL_CLAUSE_MASK \
+ ( (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_PARALLEL) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_FOR) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_SECTIONS) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_TASKGROUP) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_IF))
- if (declv)
- {
- cp_parser_parse_definitely (parser);
- nbraces += bracecount;
- }
- }
+ static void
+ cp_parser_omp_cancel (cp_parser *parser, cp_token *pragma_tok)
+ {
+ tree clauses = cp_parser_omp_all_clauses (parser, OMP_CANCEL_CLAUSE_MASK,
+ "#pragma omp cancel", pragma_tok);
+ finish_omp_cancel (clauses);
+ }
- /* Note that we saved the original contents of this flag when we entered
- the structured block, and so we don't need to re-save it here. */
- parser->in_statement = IN_OMP_FOR;
+ /* OpenMP 4.0:
+ # pragma omp cancellation point cancelpt-clause[optseq] new-line */
- /* Note that the grammar doesn't call for a structured block here,
- though the loop as a whole is a structured block. */
- body = push_stmt_list ();
- cp_parser_statement (parser, NULL_TREE, false, NULL);
- body = pop_stmt_list (body);
+ #define OMP_CANCELLATION_POINT_CLAUSE_MASK \
+ ( (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_PARALLEL) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_FOR) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_SECTIONS) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_TASKGROUP))
- if (declv == NULL_TREE)
- ret = NULL_TREE;
- else
- ret = finish_omp_for (loc_first, declv, initv, condv, incrv, body,
- pre_body, clauses);
+ static void
+ cp_parser_omp_cancellation_point (cp_parser *parser, cp_token *pragma_tok)
+ {
+ tree clauses;
+ bool point_seen = false;
- while (nbraces)
+ if (cp_lexer_next_token_is (parser->lexer, CPP_NAME))
{
- if (cp_lexer_next_token_is (parser->lexer, CPP_CLOSE_BRACE))
+ tree id = cp_lexer_peek_token (parser->lexer)->u.value;
+ const char *p = IDENTIFIER_POINTER (id);
+
+ if (strcmp (p, "point") == 0)
{
cp_lexer_consume_token (parser->lexer);
- nbraces--;
- }
- else if (cp_lexer_next_token_is (parser->lexer, CPP_SEMICOLON))
- cp_lexer_consume_token (parser->lexer);
- else
- {
- if (!collapse_err)
- {
- error_at (cp_lexer_peek_token (parser->lexer)->location,
- "collapsed loops not perfectly nested");
- }
- collapse_err = true;
- cp_parser_statement_seq_opt (parser, NULL);
- if (cp_lexer_next_token_is (parser->lexer, CPP_EOF))
- break;
+ point_seen = true;
}
}
+ if (!point_seen)
+ {
+ cp_parser_error (parser, "expected %<point%>");
+ cp_parser_require_pragma_eol (parser, pragma_tok);
+ return;
+ }
- while (!for_block->is_empty ())
- add_stmt (pop_stmt_list (for_block->pop ()));
- release_tree_vector (for_block);
-
- return ret;
+ clauses = cp_parser_omp_all_clauses (parser,
+ OMP_CANCELLATION_POINT_CLAUSE_MASK,
+ "#pragma omp cancellation point",
+ pragma_tok);
+ finish_omp_cancellation_point (clauses);
}
- /* OpenMP 2.5:
- #pragma omp for for-clause[optseq] new-line
+ /* OpenMP 4.0:
+ #pragma omp distribute distribute-clause[optseq] new-line
for-loop */
- #define OMP_FOR_CLAUSE_MASK \
- ( (1u << PRAGMA_OMP_CLAUSE_PRIVATE) \
- | (1u << PRAGMA_OMP_CLAUSE_FIRSTPRIVATE) \
- | (1u << PRAGMA_OMP_CLAUSE_LASTPRIVATE) \
- | (1u << PRAGMA_OMP_CLAUSE_REDUCTION) \
- | (1u << PRAGMA_OMP_CLAUSE_ORDERED) \
- | (1u << PRAGMA_OMP_CLAUSE_SCHEDULE) \
- | (1u << PRAGMA_OMP_CLAUSE_NOWAIT) \
- | (1u << PRAGMA_OMP_CLAUSE_COLLAPSE))
+ #define OMP_DISTRIBUTE_CLAUSE_MASK \
+ ( (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_PRIVATE) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_FIRSTPRIVATE) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_DIST_SCHEDULE)\
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_COLLAPSE))
static tree
- cp_parser_omp_for (cp_parser *parser, cp_token *pragma_tok)
+ cp_parser_omp_distribute (cp_parser *parser, cp_token *pragma_tok,
+ char *p_name, omp_clause_mask mask, tree *cclauses)
{
tree clauses, sb, ret;
unsigned int save;
rtx);
static rtx extract_fixed_bit_field (enum machine_mode, rtx,
unsigned HOST_WIDE_INT,
- unsigned HOST_WIDE_INT, rtx, int, bool);
+ unsigned HOST_WIDE_INT, rtx, int);
-static rtx mask_rtx (enum machine_mode, int, int, int);
static rtx lshift_value (enum machine_mode, unsigned HOST_WIDE_INT, int);
static rtx extract_split_bit_field (rtx, unsigned HOST_WIDE_INT,
unsigned HOST_WIDE_INT, int);
/* Static constructors for variably sized objects makes no sense. */
gcc_assert (TREE_CODE (TYPE_MIN_VALUE (domain_type)) == INTEGER_CST);
index_type = TREE_TYPE (TYPE_MIN_VALUE (domain_type));
- low_bound = tree_to_double_int (TYPE_MIN_VALUE (domain_type));
+ low_bound = TYPE_MIN_VALUE (domain_type);
}
else
- low_bound = double_int_zero;
+ low_bound = 0;
/* Static constructors for variably sized objects makes no sense. */
- gcc_assert (TREE_CODE(TYPE_SIZE_UNIT (TREE_TYPE (TREE_TYPE (ctor))))
+ gcc_assert (TREE_CODE (TYPE_SIZE_UNIT (TREE_TYPE (TREE_TYPE (ctor))))
== INTEGER_CST);
- elt_size =
- tree_to_double_int (TYPE_SIZE_UNIT (TREE_TYPE (TREE_TYPE (ctor))));
-
+ elt_size = TYPE_SIZE_UNIT (TREE_TYPE (TREE_TYPE (ctor)));
/* We can handle only constantly sized accesses that are known to not
be larger than size of array element. */
return false;
}
- && host_integerp (off, 1))
+
+ /* Given a pointer value OP0, return a simplified version of an
+ indirection through OP0, or NULL_TREE if no simplification is
+ possible. Note that the resulting type may be different from
+ the type pointed to in the sense that it is still compatible
+ from the langhooks point of view. */
+
+ tree
+ gimple_fold_indirect_ref (tree t)
+ {
+ tree ptype = TREE_TYPE (t), type = TREE_TYPE (ptype);
+ tree sub = t;
+ tree subtype;
+
+ STRIP_NOPS (sub);
+ subtype = TREE_TYPE (sub);
+ if (!POINTER_TYPE_P (subtype))
+ return NULL_TREE;
+
+ if (TREE_CODE (sub) == ADDR_EXPR)
+ {
+ tree op = TREE_OPERAND (sub, 0);
+ tree optype = TREE_TYPE (op);
+ /* *&p => p */
+ if (useless_type_conversion_p (type, optype))
+ return op;
+
+ /* *(foo *)&fooarray => fooarray[0] */
+ if (TREE_CODE (optype) == ARRAY_TYPE
+ && TREE_CODE (TYPE_SIZE (TREE_TYPE (optype))) == INTEGER_CST
+ && useless_type_conversion_p (type, TREE_TYPE (optype)))
+ {
+ tree type_domain = TYPE_DOMAIN (optype);
+ tree min_val = size_zero_node;
+ if (type_domain && TYPE_MIN_VALUE (type_domain))
+ min_val = TYPE_MIN_VALUE (type_domain);
+ if (TREE_CODE (min_val) == INTEGER_CST)
+ return build4 (ARRAY_REF, type, op, min_val, NULL_TREE, NULL_TREE);
+ }
+ /* *(foo *)&complexfoo => __real__ complexfoo */
+ else if (TREE_CODE (optype) == COMPLEX_TYPE
+ && useless_type_conversion_p (type, TREE_TYPE (optype)))
+ return fold_build1 (REALPART_EXPR, type, op);
+ /* *(foo *)&vectorfoo => BIT_FIELD_REF<vectorfoo,...> */
+ else if (TREE_CODE (optype) == VECTOR_TYPE
+ && useless_type_conversion_p (type, TREE_TYPE (optype)))
+ {
+ tree part_width = TYPE_SIZE (type);
+ tree index = bitsize_int (0);
+ return fold_build3 (BIT_FIELD_REF, type, op, part_width, index);
+ }
+ }
+
+ /* *(p + CST) -> ... */
+ if (TREE_CODE (sub) == POINTER_PLUS_EXPR
+ && TREE_CODE (TREE_OPERAND (sub, 1)) == INTEGER_CST)
+ {
+ tree addr = TREE_OPERAND (sub, 0);
+ tree off = TREE_OPERAND (sub, 1);
+ tree addrtype;
+
+ STRIP_NOPS (addr);
+ addrtype = TREE_TYPE (addr);
+
+ /* ((foo*)&vectorfoo)[1] -> BIT_FIELD_REF<vectorfoo,...> */
+ if (TREE_CODE (addr) == ADDR_EXPR
+ && TREE_CODE (TREE_TYPE (addrtype)) == VECTOR_TYPE
+ && useless_type_conversion_p (type, TREE_TYPE (TREE_TYPE (addrtype)))
- unsigned HOST_WIDE_INT offset = tree_low_cst (off, 1);
++ && tree_fits_uhwi_p (off))
+ {
- = tree_low_cst (part_width, 0) / BITS_PER_UNIT;
++ unsigned HOST_WIDE_INT offset = tree_to_uhwi (off);
+ tree part_width = TYPE_SIZE (type);
+ unsigned HOST_WIDE_INT part_widthi
- build_int_cst_wide (ptype,
- TREE_INT_CST_LOW (off),
- TREE_INT_CST_HIGH (off)));
++ = tree_to_shwi (part_width) / BITS_PER_UNIT;
+ unsigned HOST_WIDE_INT indexi = offset * BITS_PER_UNIT;
+ tree index = bitsize_int (indexi);
+ if (offset / part_widthi
+ <= TYPE_VECTOR_SUBPARTS (TREE_TYPE (addrtype)))
+ return fold_build3 (BIT_FIELD_REF, type, TREE_OPERAND (addr, 0),
+ part_width, index);
+ }
+
+ /* ((foo*)&complexfoo)[1] -> __imag__ complexfoo */
+ if (TREE_CODE (addr) == ADDR_EXPR
+ && TREE_CODE (TREE_TYPE (addrtype)) == COMPLEX_TYPE
+ && useless_type_conversion_p (type, TREE_TYPE (TREE_TYPE (addrtype))))
+ {
+ tree size = TYPE_SIZE_UNIT (type);
+ if (tree_int_cst_equal (size, off))
+ return fold_build1 (IMAGPART_EXPR, type, TREE_OPERAND (addr, 0));
+ }
+
+ /* *(p + CST) -> MEM_REF <p, CST>. */
+ if (TREE_CODE (addr) != ADDR_EXPR
+ || DECL_P (TREE_OPERAND (addr, 0)))
+ return fold_build2 (MEM_REF, type,
+ addr,
++ wide_int_to_tree (ptype, off));
+ }
+
+ /* *(foo *)fooarrptr => (*fooarrptr)[0] */
+ if (TREE_CODE (TREE_TYPE (subtype)) == ARRAY_TYPE
+ && TREE_CODE (TYPE_SIZE (TREE_TYPE (TREE_TYPE (subtype)))) == INTEGER_CST
+ && useless_type_conversion_p (type, TREE_TYPE (TREE_TYPE (subtype))))
+ {
+ tree type_domain;
+ tree min_val = size_zero_node;
+ tree osub = sub;
+ sub = gimple_fold_indirect_ref (sub);
+ if (! sub)
+ sub = build1 (INDIRECT_REF, TREE_TYPE (subtype), osub);
+ type_domain = TYPE_DOMAIN (TREE_TYPE (sub));
+ if (type_domain && TYPE_MIN_VALUE (type_domain))
+ min_val = TYPE_MIN_VALUE (type_domain);
+ if (TREE_CODE (min_val) == INTEGER_CST)
+ return build4 (ARRAY_REF, type, sub, min_val, NULL_TREE, NULL_TREE);
+ }
+
+ return NULL_TREE;
+ }
pp_string (buffer, "# ");
}
- double_int min, max;
+ if (!POINTER_TYPE_P (TREE_TYPE (node))
+ && SSA_NAME_RANGE_INFO (node))
+ {
- pp_double_int (buffer, min, TYPE_UNSIGNED (TREE_TYPE (node)));
++ max_wide_int min, max;
+ value_range_type range_type = get_range_info (node, &min, &max);
+
+ if (range_type == VR_VARYING)
+ pp_printf (buffer, "# RANGE VR_VARYING");
+ else if (range_type == VR_RANGE || range_type == VR_ANTI_RANGE)
+ {
+ pp_printf (buffer, "# RANGE ");
+ pp_printf (buffer, "%s[", range_type == VR_RANGE ? "" : "~");
- pp_double_int (buffer, max, TYPE_UNSIGNED (TREE_TYPE (node)));
++ pp_wide_int (buffer, min, TYPE_SIGN (TREE_TYPE (node)));
+ pp_printf (buffer, ", ");
++ pp_wide_int (buffer, max, TYPE_SIGN (TREE_TYPE (node)));
+ pp_printf (buffer, "]");
+ newline_and_indent (buffer, spc);
+ }
+ }
+ }
+
+
+ /* Dump a PHI node PHI. BUFFER, SPC and FLAGS are as in pp_gimple_stmt_1.
+ The caller is responsible for calling pp_flush on BUFFER to finalize
+ pretty printer. */
+
+ static void
+ dump_gimple_phi (pretty_printer *buffer, gimple phi, int spc, int flags)
+ {
+ size_t i;
+ tree lhs = gimple_phi_result (phi);
+
+ if (flags & TDF_ALIAS)
+ dump_ssaname_info (buffer, lhs, spc);
+
if (flags & TDF_RAW)
- dump_gimple_fmt (buffer, spc, flags, "%G <%T, ", phi,
- gimple_phi_result (phi));
+ dump_gimple_fmt (buffer, spc, flags, "%G <%T, ", phi,
+ gimple_phi_result (phi));
else
{
dump_generic_node (buffer, lhs, spc, flags, false);
#include "expmed.h"
#include "params.h"
#include "hash-table.h"
-
+ #include "tree-ssa-address.h"
+#include "wide-int-print.h"
\f
/* Information about a strength reduction candidate. Each statement
in the candidate table represents an expression of one of the
slsr_cand_t base_cand;
STRIP_NOPS (base_in);
+
+ /* Strip off widening conversion(s) to handle cases where
+ e.g. 'B' is widened from an 'int' in order to calculate
+ a 64-bit address. */
+ if (CONVERT_EXPR_P (base_in)
+ && legal_cast_p_1 (base_in, TREE_OPERAND (base_in, 0)))
+ base_in = get_unwidened (base_in, NULL_TREE);
+
if (TREE_CODE (base_in) != SSA_NAME)
- return tree_to_double_int (integer_zero_node);
+ return 0;
base_cand = base_cand_from_table (base_in);
if (!binfo)
return NULL_TREE;
token = OBJ_TYPE_REF_TOKEN (otr);
- fndecl = gimple_get_virt_method_for_binfo (tree_low_cst (token, 1),
+ fndecl = gimple_get_virt_method_for_binfo (tree_to_uhwi (token),
binfo);
+ #ifdef ENABLE_CHECKING
+ if (fndecl)
+ gcc_assert (possible_polymorphic_call_target_p
+ (otr, cgraph_get_node (fndecl)));
+ #endif
return fndecl;
}
return possible_polymorphic_call_target_p (e->indirect_info->otr_type,
e->indirect_info->otr_token, n);
}
- tree_low_cst
- (OBJ_TYPE_REF_TOKEN (call), 1),
+
+ /* Return true if N can be possibly target of a polymorphic call of
+ OBJ_TYPE_REF expression CALL. */
+
+ inline bool
+ possible_polymorphic_call_target_p (tree call,
+ struct cgraph_node *n)
+ {
+ return possible_polymorphic_call_target_p (obj_type_ref_class (call),
++ tree_to_uhwi
++ (OBJ_TYPE_REF_TOKEN (call)),
+ n);
+ }
#endif /* GCC_IPA_UTILS_H */
/* Determine if the iteration counter will be non-negative.
Note that the maximum value loaded is iterations_max - 1. */
- if (max_loop_iterations (loop, &iterations)
+ if (get_max_loop_iterations (loop, &iterations)
- && (iterations.ule (double_int_one.llshift
- (GET_MODE_PRECISION (mode) - 1,
- GET_MODE_PRECISION (mode)))))
+ && wi::leu_p (iterations,
+ wi::set_bit_in_zero (GET_MODE_PRECISION (mode) - 1,
+ GET_MODE_PRECISION (mode))))
nonneg = 1;
break;
{
rtx init;
unsigned level = get_loop_level (loop) + 1;
- double_int iter;
+ wide_int iter;
rtx iter_rtx;
- if (!max_loop_iterations (loop, &iter)
+ if (!get_max_loop_iterations (loop, &iter)
- || !iter.fits_shwi ())
+ || !wi::fits_shwi_p (iter))
iter_rtx = const0_rtx;
else
iter_rtx = GEN_INT (iter.to_shwi ());
count = copy_rtx (desc->niter_expr);
iterations = desc->const_iter ? desc->niter_expr : const0_rtx;
- if (!max_loop_iterations (loop, &iter)
+ if (!get_max_loop_iterations (loop, &iter)
- || !iter.fits_shwi ())
+ || !wi::fits_shwi_p (iter))
iterations_max = const0_rtx;
else
- iterations_max = GEN_INT (iter.to_shwi ());
+ iterations_max = immed_wide_int_const (iter, mode);
level = get_loop_level (loop) + 1;
/* Generate looping insn. If the pattern FAILs then give up trying
than one exit it may well loop less than determined maximal number
of iterations. */
if (desc->niter < 2 * nunroll
- || ((estimated_loop_iterations (loop, &iterations)
- || max_loop_iterations (loop, &iterations))
+ || ((get_estimated_loop_iterations (loop, &iterations)
+ || get_max_loop_iterations (loop, &iterations))
- && iterations.ult (double_int::from_shwi (2 * nunroll))))
+ && wi::ltu_p (iterations, 2 * nunroll)))
{
if (dump_file)
fprintf (dump_file, ";; Not unrolling loop, doesn't roll\n");
}
/* Check whether the loop rolls. */
- if ((estimated_loop_iterations (loop, &iterations)
- || max_loop_iterations (loop, &iterations))
+ if ((get_estimated_loop_iterations (loop, &iterations)
+ || get_max_loop_iterations (loop, &iterations))
- && iterations.ult (double_int::from_shwi (2 * nunroll)))
+ && wi::ltu_p (iterations, 2 * nunroll))
{
if (dump_file)
fprintf (dump_file, ";; Not unrolling loop, doesn't roll\n");
}
/* If we have realistic estimate on number of iterations, use it. */
- if (estimated_loop_iterations (loop, &iterations))
+ if (get_estimated_loop_iterations (loop, &iterations))
{
- if (double_int::from_shwi (npeel).ule (iterations))
+ /* TODO: unsigned/signed confusion */
+ if (wi::leu_p (npeel, iterations))
{
if (dump_file)
{
}
/* If we have small enough bound on iterations, we can still peel (completely
unroll). */
- else if (max_loop_iterations (loop, &iterations)
+ else if (get_max_loop_iterations (loop, &iterations)
- && iterations.ult (double_int::from_shwi (npeel)))
+ && wi::ltu_p (iterations, npeel))
npeel = iterations.to_shwi () + 1;
else
{
}
/* Check whether the loop rolls. */
- if ((estimated_loop_iterations (loop, &iterations)
- || max_loop_iterations (loop, &iterations))
+ if ((get_estimated_loop_iterations (loop, &iterations)
+ || get_max_loop_iterations (loop, &iterations))
- && iterations.ult (double_int::from_shwi (2 * nunroll)))
+ && wi::ltu_p (iterations, 2 * nunroll))
{
if (dump_file)
fprintf (dump_file, ";; Not unrolling loop, doesn't roll\n");
case GIMPLE_OMP_FOR:
if (gimple_omp_for_kind (stmt) == GF_OMP_FOR_KIND_SIMD)
return true;
- switch (host_integerp (gimple_call_arg (stmt, 0), 0)
- ? tree_low_cst (gimple_call_arg (stmt, 0), 0)
+ 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 (tree_fits_shwi_p (gimple_call_arg (stmt, 0))
++ ? tree_to_shwi (gimple_call_arg (stmt, 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:
#include "obstack.h"
#include "input.h"
++#include "wide-int-print.h"
/* Maximum number of format string arguments. */
#define PP_NL_ARGMAX 30
#define pp_decimal_int(PP, I) pp_scalar (PP, "%d", I)
#define pp_unsigned_wide_integer(PP, I) \
pp_scalar (PP, HOST_WIDE_INT_PRINT_UNSIGNED, (unsigned HOST_WIDE_INT) I)
++#define pp_wide_int(PP, W, SGN) \
++ do \
++ { \
++ print_dec (W, pp_buffer (PP)->digit_buffer, SGN); \
++ pp_string (PP, pp_buffer (PP)->digit_buffer); \
++ } \
++ while (0)
#define pp_wide_integer(PP, I) \
pp_scalar (PP, HOST_WIDE_INT_PRINT_DEC, (HOST_WIDE_INT) I)
#define pp_widest_integer(PP, I) \
#define HARD_REGISTER_NUM_P(REG_NO) ((REG_NO) < FIRST_PSEUDO_REGISTER)
/* For a CONST_INT rtx, INTVAL extracts the integer. */
- #define INTVAL(RTX) XCWINT(RTX, 0, CONST_INT)
+ #define INTVAL(RTX) XCWINT (RTX, 0, CONST_INT)
#define UINTVAL(RTX) ((unsigned HOST_WIDE_INT) INTVAL (RTX))
+/* For a CONST_WIDE_INT, CONST_WIDE_INT_NUNITS is the number of
+ elements actually needed to represent the constant.
+ CONST_WIDE_INT_ELT gets one of the elements. 0 is the least
+ significant HOST_WIDE_INT. */
+#define CONST_WIDE_INT_VEC(RTX) HWIVEC_CHECK (RTX, CONST_WIDE_INT)
+#define CONST_WIDE_INT_NUNITS(RTX) CWI_GET_NUM_ELEM (RTX)
+#define CONST_WIDE_INT_ELT(RTX, N) CWI_ELT (RTX, N)
+
/* For a CONST_DOUBLE:
+#if TARGET_SUPPORTS_WIDE_INT == 0
For a VOIDmode, there are two integers CONST_DOUBLE_LOW is the
low-order word and ..._HIGH the high-order.
+#endif
For a float, there is a REAL_VALUE_TYPE structure, and
CONST_DOUBLE_REAL_VALUE(r) is a pointer to it. */
#define CONST_DOUBLE_LOW(r) XCMWINT (r, 0, CONST_DOUBLE, VOIDmode)
void
set_min_and_max_values_for_integral_type (tree type,
int precision,
- bool is_unsigned)
+ signop sgn)
{
- tree min_value;
- tree max_value;
-
+ /* For bitfields with zero width we end up creating integer types
+ with zero precision. Don't assign any minimum/maximum values
+ to those types, they don't have any valid value. */
+ if (precision < 1)
+ return;
+
- if (is_unsigned)
- {
- min_value = build_int_cst (type, 0);
- max_value
- = build_int_cst_wide (type, precision - HOST_BITS_PER_WIDE_INT >= 0
- ? -1
- : ((HOST_WIDE_INT) 1 << precision) - 1,
- precision - HOST_BITS_PER_WIDE_INT > 0
- ? ((unsigned HOST_WIDE_INT) ~0
- >> (HOST_BITS_PER_WIDE_INT
- - (precision - HOST_BITS_PER_WIDE_INT)))
- : 0);
- }
- else
- {
- min_value
- = build_int_cst_wide (type,
- (precision - HOST_BITS_PER_WIDE_INT > 0
- ? 0
- : (HOST_WIDE_INT) (-1) << (precision - 1)),
- (((HOST_WIDE_INT) (-1)
- << (precision - HOST_BITS_PER_WIDE_INT - 1 > 0
- ? precision - HOST_BITS_PER_WIDE_INT - 1
- : 0))));
- max_value
- = build_int_cst_wide (type,
- (precision - HOST_BITS_PER_WIDE_INT > 0
- ? -1
- : (HOST_WIDE_INT)
- (((unsigned HOST_WIDE_INT) 1
- << (precision - 1)) - 1)),
- (precision - HOST_BITS_PER_WIDE_INT - 1 > 0
- ? (HOST_WIDE_INT)
- ((((unsigned HOST_WIDE_INT) 1
- << (precision - HOST_BITS_PER_WIDE_INT
- - 1))) - 1)
- : 0));
- }
-
- TYPE_MIN_VALUE (type) = min_value;
- TYPE_MAX_VALUE (type) = max_value;
+ TYPE_MIN_VALUE (type)
+ = wide_int_to_tree (type, wi::min_value (precision, sgn));
+ TYPE_MAX_VALUE (type)
+ = wide_int_to_tree (type, wi::max_value (precision, sgn));
}
/* Set the extreme values of TYPE based on its precision in bits,
#include "pointer-set.h"
#include "tree-inline.h"
#include "target.h"
+ #include "tree-ssa-live.h"
+ #include "omp-low.h"
+ #include "tree-cfgcleanup.h"
+#include "wide-int.h"
+#include "wide-int-print.h"
/* This file contains functions for building the Control Flow Graph (CFG)
for a function tree. */
--- /dev/null
- HOST_WIDE_INT this_off = TREE_INT_CST_LOW (TREE_OPERAND (exp, 2));
+ /* Header file for tree data flow functions.
+ Copyright (C) 2013 Free Software Foundation, Inc.
+
+ This file is part of GCC.
+
+ GCC is free software; you can redistribute it and/or modify it under
+ the terms of the GNU General Public License as published by the Free
+ Software Foundation; either version 3, or (at your option) any later
+ version.
+
+ GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GCC; see the file COPYING3. If not see
+ <http://www.gnu.org/licenses/>. */
+
+ #ifndef GCC_TREE_DFA_H
+ #define GCC_TREE_DFA_H
+
+ extern void renumber_gimple_stmt_uids (void);
+ extern void renumber_gimple_stmt_uids_in_blocks (basic_block *, int);
+ extern void dump_variable (FILE *, tree);
+ extern void debug_variable (tree);
+ extern void dump_dfa_stats (FILE *);
+ extern void debug_dfa_stats (void);
+ extern tree ssa_default_def (struct function *, tree);
+ extern void set_ssa_default_def (struct function *, tree, tree);
+ extern tree get_or_create_ssa_default_def (struct function *, tree);
+ extern tree get_ref_base_and_extent (tree, HOST_WIDE_INT *,
+ HOST_WIDE_INT *, HOST_WIDE_INT *);
+ extern tree get_addr_base_and_unit_offset (tree, HOST_WIDE_INT *);
+ extern bool stmt_references_abnormal_ssa_name (gimple);
+ extern void dump_enumerated_decls (FILE *, int);
+
+ /* Returns the base object and a constant BITS_PER_UNIT offset in *POFFSET that
+ denotes the starting address of the memory access EXP.
+ Returns NULL_TREE if the offset is not constant or any component
+ is not BITS_PER_UNIT-aligned.
+ VALUEIZE if non-NULL is used to valueize SSA names. It should return
+ its argument or a constant if the argument is known to be constant. */
+ /* ??? This is a static inline here to avoid the overhead of the indirect calls
+ to VALUEIZE. But is this overhead really that significant? And should we
+ perhaps just rely on WHOPR to specialize the function? */
+
+ static inline tree
+ get_addr_base_and_unit_offset_1 (tree exp, HOST_WIDE_INT *poffset,
+ tree (*valueize) (tree))
+ {
+ HOST_WIDE_INT byte_offset = 0;
+
+ /* Compute cumulative byte-offset for nested component-refs and array-refs,
+ and find the ultimate containing object. */
+ while (1)
+ {
+ switch (TREE_CODE (exp))
+ {
+ case BIT_FIELD_REF:
+ {
- || (TREE_INT_CST_LOW (DECL_FIELD_BIT_OFFSET (field))
++ HOST_WIDE_INT this_off = tree_to_hwi (TREE_OPERAND (exp, 2));
+ if (this_off % BITS_PER_UNIT)
+ return NULL_TREE;
+ byte_offset += this_off / BITS_PER_UNIT;
+ }
+ break;
+
+ case COMPONENT_REF:
+ {
+ tree field = TREE_OPERAND (exp, 1);
+ tree this_offset = component_ref_field_offset (exp);
+ HOST_WIDE_INT hthis_offset;
+
+ if (!this_offset
+ || TREE_CODE (this_offset) != INTEGER_CST
- hthis_offset = TREE_INT_CST_LOW (this_offset);
- hthis_offset += (TREE_INT_CST_LOW (DECL_FIELD_BIT_OFFSET (field))
++ || (tree_to_hwi (DECL_FIELD_BIT_OFFSET (field))
+ % BITS_PER_UNIT))
+ return NULL_TREE;
+
- HOST_WIDE_INT hindex = TREE_INT_CST_LOW (index);
++ hthis_offset = tree_to_hwi (this_offset);
++ hthis_offset += (tree_to_hwi (DECL_FIELD_BIT_OFFSET (field))
+ / BITS_PER_UNIT);
+ byte_offset += hthis_offset;
+ }
+ break;
+
+ case ARRAY_REF:
+ case ARRAY_RANGE_REF:
+ {
+ tree index = TREE_OPERAND (exp, 1);
+ tree low_bound, unit_size;
+
+ if (valueize
+ && TREE_CODE (index) == SSA_NAME)
+ index = (*valueize) (index);
+
+ /* If the resulting bit-offset is constant, track it. */
+ if (TREE_CODE (index) == INTEGER_CST
+ && (low_bound = array_ref_low_bound (exp),
+ TREE_CODE (low_bound) == INTEGER_CST)
+ && (unit_size = array_ref_element_size (exp),
+ TREE_CODE (unit_size) == INTEGER_CST))
+ {
- hindex -= TREE_INT_CST_LOW (low_bound);
- hindex *= TREE_INT_CST_LOW (unit_size);
++ HOST_WIDE_INT hindex = tree_to_hwi (index);
+
- byte_offset += TREE_INT_CST_LOW (TYPE_SIZE_UNIT (TREE_TYPE (exp)));
++ hindex -= tree_to_hwi (low_bound);
++ hindex *= tree_to_hwi (unit_size);
+ byte_offset += hindex;
+ }
+ else
+ return NULL_TREE;
+ }
+ break;
+
+ case REALPART_EXPR:
+ break;
+
+ case IMAGPART_EXPR:
- double_int off = mem_ref_offset (exp);
- gcc_assert (off.high == -1 || off.high == 0);
- byte_offset += off.to_shwi ();
++ byte_offset += tree_to_hwi (TYPE_SIZE_UNIT (TREE_TYPE (exp)));
+ break;
+
+ case VIEW_CONVERT_EXPR:
+ break;
+
+ case MEM_REF:
+ {
+ tree base = TREE_OPERAND (exp, 0);
+ if (valueize
+ && TREE_CODE (base) == SSA_NAME)
+ base = (*valueize) (base);
+
+ /* Hand back the decl for MEM[&decl, off]. */
+ if (TREE_CODE (base) == ADDR_EXPR)
+ {
+ if (!integer_zerop (TREE_OPERAND (exp, 1)))
+ {
- double_int off = mem_ref_offset (exp);
- gcc_assert (off.high == -1 || off.high == 0);
- byte_offset += off.to_shwi ();
++ addr_wide_int off = mem_ref_offset (exp);
++ byte_offset += off.to_short_addr ();
+ }
+ exp = TREE_OPERAND (base, 0);
+ }
+ goto done;
+ }
+
+ case TARGET_MEM_REF:
+ {
+ tree base = TREE_OPERAND (exp, 0);
+ if (valueize
+ && TREE_CODE (base) == SSA_NAME)
+ base = (*valueize) (base);
+
+ /* Hand back the decl for MEM[&decl, off]. */
+ if (TREE_CODE (base) == ADDR_EXPR)
+ {
+ if (TMR_INDEX (exp) || TMR_INDEX2 (exp))
+ return NULL_TREE;
+ if (!integer_zerop (TMR_OFFSET (exp)))
+ {
++ addr_wide_int off = mem_ref_offset (exp);
++ byte_offset += off.to_short_addr ();
+ }
+ exp = TREE_OPERAND (base, 0);
+ }
+ goto done;
+ }
+
+ default:
+ goto done;
+ }
+
+ exp = TREE_OPERAND (exp, 0);
+ }
+ done:
+
+ *poffset = byte_offset;
+ return exp;
+ }
+
+
+
+ #endif /* GCC_TREE_DFA_H */
#include "langhooks.h"
#include "tree-iterator.h"
#include "tree-pretty-print.h"
+ #include "tree-cfg.h"
+#include "wide-int.h"
+#include "wide-int-print.h"
static unsigned int queue (dump_info_p, const_tree, int);
static void dump_index (dump_info_p, unsigned int);
NB: Neither of the following divisors can be trivially
used to recover the original literal:
- TREE_INT_CST_LOW (TYPE_SIZE_UNIT (TREE_TYPE (node)))
+ tree_to_hwi (TYPE_SIZE_UNIT (TREE_TYPE (node)))
TYPE_PRECISION (TREE_TYPE (TREE_TYPE (node))) */
- pp_wide_integer (buffer, TREE_INT_CST_LOW (node));
+ pp_wide_integer (buffer, tree_to_hwi (node));
pp_string (buffer, "B"); /* pseudo-unit */
}
+ else if (tree_fits_shwi_p (node))
+ pp_wide_integer (buffer, tree_to_shwi (node));
+ else if (tree_fits_uhwi_p (node))
+ pp_unsigned_wide_integer (buffer, tree_to_uhwi (node));
else
- pp_double_int (buffer, tree_to_double_int (node),
- TYPE_UNSIGNED (TREE_TYPE (node)));
+ {
+ wide_int val = node;
+
+ if (wi::neg_p (val, TYPE_SIGN (TREE_TYPE (node))))
+ {
+ pp_minus (buffer);
+ val = -val;
+ }
+ print_hex (val, pp_buffer (buffer)->digit_buffer);
+ pp_string (buffer, pp_buffer (buffer)->digit_buffer);
+ }
+ if (TREE_OVERFLOW (node))
+ pp_string (buffer, "(OVF)");
break;
case REAL_CST:
#include "target.h"
#include "diagnostic-core.h"
#include "dbgcnt.h"
- #include "gimple-fold.h"
#include "params.h"
#include "hash-table.h"
-
+#include "wide-int-print.h"
/* Possible lattice values. */
typedef enum
#include "diagnostic-core.h"
#include "tree-inline.h"
#include "tree-pass.h"
+#include "wide-int-print.h"
+
#define SWAP(X, Y) do { affine_iv *tmp = (X); (X) = (Y); (Y) = tmp; } while (0)
/* The maximum number of dominator BBs we search for conditions
free (bbs);
}
- /* Converts VAL to max_wide_int. */
-
- static max_wide_int
- gcov_type_to_wide_int (gcov_type val)
- {
- HOST_WIDE_INT a[2];
-
- a[0] = (unsigned HOST_WIDE_INT) val;
- /* If HOST_BITS_PER_WIDE_INT == HOST_BITS_PER_WIDEST_INT, avoid shifting by
- the size of type. */
- val >>= HOST_BITS_PER_WIDE_INT - 1;
- val >>= 1;
- a[1] = (unsigned HOST_WIDE_INT) val;
--
- return max_wide_int::from_array (a, 2);
- }
--
-/* Compare double ints, callback for qsort. */
+/* Compare wide ints, callback for qsort. */
- int
+ static int
-double_int_cmp (const void *p1, const void *p2)
+wide_int_cmp (const void *p1, const void *p2)
{
- const double_int *d1 = (const double_int *)p1;
- const double_int *d2 = (const double_int *)p2;
- if (*d1 == *d2)
- return 0;
- if (d1->ult (*d2))
- return -1;
- return 1;
+ const max_wide_int *d1 = (const max_wide_int *)p1;
+ const max_wide_int *d2 = (const max_wide_int *)p2;
+ return wi::cmpu (*d1, *d2);
}
/* Return index of BOUND in BOUNDS array sorted in increasing order.
Lookup by binary search. */
- int
+ static int
-bound_index (vec<double_int> bounds, double_int bound)
+bound_index (vec<max_wide_int> bounds, const max_wide_int &bound)
{
unsigned int end = bounds.length ();
unsigned int begin = 0;
return hwi_nit < 0 ? -1 : hwi_nit;
}
-max_loop_iterations (struct loop *loop, double_int *nit)
+
+ /* Sets NIT to an upper bound for the maximum number of executions of the
+ latch of the LOOP. If we have no reliable estimate, the function returns
+ false, otherwise returns true. */
+
+ bool
++max_loop_iterations (struct loop *loop, max_wide_int *nit)
+ {
+ /* When SCEV information is available, try to update loop iterations
+ estimate. Otherwise just return whatever we recorded earlier. */
+ if (scev_initialized_p ())
+ estimate_numbers_of_iterations_loop (loop);
+
+ return get_max_loop_iterations (loop, nit);
+ }
+
/* Similar to max_loop_iterations, but returns the estimate only
if it fits to HOST_WIDE_INT. If this is not the case, or the estimate
on the number of iterations of LOOP could not be derived, returns -1. */
--- /dev/null
-extern bool estimated_loop_iterations (struct loop *, double_int *);
+ /* Header file for loop interation estimates.
+ Copyright (C) 2013 Free Software Foundation, Inc.
+
+ This file is part of GCC.
+
+ GCC is free software; you can redistribute it and/or modify it under
+ the terms of the GNU General Public License as published by the Free
+ Software Foundation; either version 3, or (at your option) any later
+ version.
+
+ GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GCC; see the file COPYING3. If not see
+ <http://www.gnu.org/licenses/>. */
+
+ #ifndef GCC_TREE_SSA_LOOP_NITER_H
+ #define GCC_TREE_SSA_LOOP_NITER_H
+
+ extern tree expand_simple_operations (tree);
+ extern bool loop_only_exit_p (const struct loop *, const_edge);
+ extern bool number_of_iterations_exit (struct loop *, edge,
+ struct tree_niter_desc *niter, bool,
+ bool every_iteration = true);
+ extern tree find_loop_niter (struct loop *, edge *);
+ extern bool finite_loop_p (struct loop *);
+ extern tree loop_niter_by_eval (struct loop *, edge);
+ extern tree find_loop_niter_by_eval (struct loop *, edge *);
-extern bool max_loop_iterations (struct loop *, double_int *);
++extern bool estimated_loop_iterations (struct loop *, max_wide_int *);
+ extern HOST_WIDE_INT estimated_loop_iterations_int (struct loop *);
-extern bool max_stmt_executions (struct loop *, double_int *);
-extern bool estimated_stmt_executions (struct loop *, double_int *);
++extern bool max_loop_iterations (struct loop *, max_wide_int *);
+ extern HOST_WIDE_INT max_loop_iterations_int (struct loop *);
+ extern HOST_WIDE_INT max_stmt_executions_int (struct loop *);
+ extern HOST_WIDE_INT estimated_stmt_executions_int (struct loop *);
++extern bool max_stmt_executions (struct loop *, max_wide_int *);
++extern bool estimated_stmt_executions (struct loop *, max_wide_int *);
+ extern void estimate_numbers_of_iterations (void);
+ extern bool stmt_dominates_stmt_p (gimple, gimple);
+ extern bool nowrap_type_p (tree);
+ extern bool scev_probably_wraps_p (tree, tree, gimple, struct loop *, bool);
+ extern void free_numbers_of_iterations_estimates_loop (struct loop *);
+ extern void free_numbers_of_iterations_estimates (void);
+ extern void substitute_in_loop_info (struct loop *, tree, tree);
+
+ #endif /* GCC_TREE_SSA_LOOP_NITER_H */
--- /dev/null
- double_int max; /* The upper bound on the number of iterations of
+ /* Header file for SSA loop optimizations.
+ Copyright (C) 2013 Free Software Foundation, Inc.
+
+ This file is part of GCC.
+
+ GCC is free software; you can redistribute it and/or modify it under
+ the terms of the GNU General Public License as published by the Free
+ Software Foundation; either version 3, or (at your option) any later
+ version.
+
+ GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GCC; see the file COPYING3. If not see
+ <http://www.gnu.org/licenses/>. */
+
+ #ifndef GCC_TREE_SSA_LOOP_H
+ #define GCC_TREE_SSA_LOOP_H
+
+ #include "tree-ssa-loop-ivopts.h"
+ #include "tree-ssa-loop-manip.h"
+ #include "tree-ssa-loop-niter.h"
++#include "wide-int.h"
+
+ /* Affine iv. */
+
+ typedef struct affine_iv_d
+ {
+ /* Iv = BASE + STEP * i. */
+ tree base, step;
+
+ /* True if this iv does not overflow. */
+ bool no_overflow;
+ } affine_iv;
+
+ /* Description of number of iterations of a loop. All the expressions inside
+ the structure can be evaluated at the end of the loop's preheader
+ (and due to ssa form, also anywhere inside the body of the loop). */
+
+ struct tree_niter_desc
+ {
+ tree assumptions; /* The boolean expression. If this expression evaluates
+ to false, then the other fields in this structure
+ should not be used; there is no guarantee that they
+ will be correct. */
+ tree may_be_zero; /* The boolean expression. If it evaluates to true,
+ the loop will exit in the first iteration (i.e.
+ its latch will not be executed), even if the niter
+ field says otherwise. */
+ tree niter; /* The expression giving the number of iterations of
+ a loop (provided that assumptions == true and
+ may_be_zero == false), more precisely the number
+ of executions of the latch of the loop. */
++ max_wide_int max; /* The upper bound on the number of iterations of
+ the loop. */
+
+ /* The simplified shape of the exit condition. The loop exits if
+ CONTROL CMP BOUND is false, where CMP is one of NE_EXPR,
+ LT_EXPR, or GT_EXPR, and step of CONTROL is positive if CMP is
+ LE_EXPR and negative if CMP is GE_EXPR. This information is used
+ by loop unrolling. */
+ affine_iv control;
+ tree bound;
+ enum tree_code cmp;
+ };
+
+ extern bool for_each_index (tree *, bool (*) (tree, tree *, void *), void *);
+ extern char *get_lsm_tmp_name (tree ref, unsigned n, const char *suffix = NULL);
+ extern unsigned tree_num_loop_insns (struct loop *, struct eni_weights_d *);
+
+ /* Returns the loop of the statement STMT. */
+
+ static inline struct loop *
+ loop_containing_stmt (gimple stmt)
+ {
+ basic_block bb = gimple_bb (stmt);
+ if (!bb)
+ return NULL;
+
+ return bb->loop_father;
+ }
+
+ #endif /* GCC_TREE_SSA_LOOP_H */
return t;
}
-set_range_info (tree name, double_int min, double_int max)
+ /* Store range information MIN, and MAX to tree ssa_name NAME. */
+
+ void
-get_range_info (tree name, double_int *min, double_int *max)
++set_range_info (tree name, max_wide_int min, max_wide_int max)
+ {
+ gcc_assert (!POINTER_TYPE_P (TREE_TYPE (name)));
+ range_info_def *ri = SSA_NAME_RANGE_INFO (name);
+
+ /* Allocate if not available. */
+ if (ri == NULL)
+ {
+ ri = ggc_alloc_cleared_range_info_def ();
+ SSA_NAME_RANGE_INFO (name) = ri;
+ }
+
+ /* Set the values. */
+ ri->min = min;
+ ri->max = max;
+ }
+
+
+ /* Gets range information MIN, MAX and returns enum value_range_type
+ corresponding to tree ssa_name NAME. enum value_range_type returned
+ is used to determine if MIN and MAX are valid values. */
+
+ enum value_range_type
- if (ri->min.cmp (ri->max, TYPE_UNSIGNED (TREE_TYPE (name))) == 1)
++get_range_info (tree name, max_wide_int *min, max_wide_int *max)
+ {
+ enum value_range_type range_type;
+ gcc_assert (!POINTER_TYPE_P (TREE_TYPE (name)));
+ gcc_assert (min && max);
+ range_info_def *ri = SSA_NAME_RANGE_INFO (name);
+
+ /* Return VR_VARYING for SSA_NAMEs with NULL RANGE_INFO or SSA_NAMEs
+ with integral types width > 2 * HOST_BITS_PER_WIDE_INT precision. */
+ if (!ri || (GET_MODE_PRECISION (TYPE_MODE (TREE_TYPE (name)))
+ > 2 * HOST_BITS_PER_WIDE_INT))
+ return VR_VARYING;
+
+ /* If min > max, it is VR_ANTI_RANGE. */
- *min = ri->max + double_int_one;
- *max = ri->min - double_int_one;
++ if (wi::cmp (ri->min, ri->max, TYPE_SIGN (TREE_TYPE (name))) == 1)
+ {
+ /* VR_ANTI_RANGE ~[min, max] is encoded as [max + 1, min - 1]. */
+ range_type = VR_ANTI_RANGE;
++ *min = ri->max + 1;
++ *max = ri->min - 1;
+ }
+ else
+ {
+ /* Otherwise (when min <= max), it is VR_RANGE. */
+ range_type = VR_RANGE;
+ *min = ri->min;
+ *max = ri->max;
+ }
+ return range_type;
+ }
/* We no longer need the SSA_NAME expression VAR, release it so that
it may be reused.
unsigned int misalign;
};
- double_int min;
+ /* Value range information for SSA_NAMEs representing non-pointer variables. */
+
+ struct GTY (()) range_info_def {
+ /* Minimum for value range. */
- double_int max;
++ max_wide_int min;
+ /* Maximum for value range. */
++ max_wide_int max;
+ };
+
#define SSANAMES(fun) (fun)->gimple_df->ssa_names
#define MODIFIED_NORETURN_CALLS(fun) (fun)->gimple_df->modified_noreturn_calls
#define ssa_name(i) ((*cfun->gimple_df->ssa_names)[(i)])
-extern void set_range_info (tree ssa, double_int min, double_int max);
+ /* Type of value ranges. See value_range_d In tree-vrp.c for a
+ description of these types. */
+ enum value_range_type { VR_UNDEFINED, VR_RANGE, VR_ANTI_RANGE, VR_VARYING };
+
+ /* Sets the value range to SSA. */
-extern enum value_range_type get_range_info (tree name, double_int *min,
- double_int *max);
++extern void set_range_info (tree ssa, max_wide_int min, max_wide_int max);
+ /* Gets the value range from SSA. */
++extern enum value_range_type get_range_info (tree name, max_wide_int *min,
++ max_wide_int *max);
extern void init_ssanames (struct function *, int);
extern void fini_ssanames (void);
extern void ssanames_print_statistics (void);
(L)->may_alias_ddrs.length () > 0
#define NITERS_KNOWN_P(n) \
-(host_integerp ((n),0) \
-&& TREE_INT_CST_LOW ((n)) > 0)
+(tree_fits_shwi_p ((n)) \
+&& tree_to_shwi ((n)) > 0)
#define LOOP_VINFO_NITERS_KNOWN_P(L) \
- NITERS_KNOWN_P((L)->num_iters)
+ NITERS_KNOWN_P ((L)->num_iters)
static inline loop_vec_info
loop_vec_info_for_loop (struct loop *loop)
#include "tree-scalar-evolution.h"
#include "tree-ssa-propagate.h"
#include "tree-chrec.h"
- #include "gimple-fold.h"
+ #include "tree-ssa-threadupdate.h"
#include "expr.h"
#include "optabs.h"
+ #include "tree-ssa-threadedge.h"
++#include "wide-int.h"
- /* Type of value ranges. See value_range_d for a description of these
- types. */
- enum value_range_type { VR_UNDEFINED, VR_RANGE, VR_ANTI_RANGE, VR_VARYING };
/* Range of values that can be associated with an SSA_NAME after VRP
has executed. */
}
- int idx = TREE_INT_CST_LOW (TREE_VALUE (t)) - 1;
+ /* If OP can be inferred to be non-zero after STMT executes, return true. */
+
+ static bool
+ infer_nonnull_range (gimple stmt, tree op)
+ {
+ /* We can only assume that a pointer dereference will yield
+ non-NULL if -fdelete-null-pointer-checks is enabled. */
+ if (!flag_delete_null_pointer_checks
+ || !POINTER_TYPE_P (TREE_TYPE (op))
+ || gimple_code (stmt) == GIMPLE_ASM)
+ return false;
+
+ unsigned num_uses, num_loads, num_stores;
+
+ count_uses_and_derefs (op, stmt, &num_uses, &num_loads, &num_stores);
+ if (num_loads + num_stores > 0)
+ return true;
+
+ if (is_gimple_call (stmt) && !gimple_call_internal_p (stmt))
+ {
+ tree fntype = gimple_call_fntype (stmt);
+ tree attrs = TYPE_ATTRIBUTES (fntype);
+ for (; attrs; attrs = TREE_CHAIN (attrs))
+ {
+ attrs = lookup_attribute ("nonnull", attrs);
+
+ /* If "nonnull" wasn't specified, we know nothing about
+ the argument. */
+ if (attrs == NULL_TREE)
+ return false;
+
+ /* If "nonnull" applies to all the arguments, then ARG
+ is non-null. */
+ if (TREE_VALUE (attrs) == NULL_TREE)
+ return true;
+
+ /* Now see if op appears in the nonnull list. */
+ for (tree t = TREE_VALUE (attrs); t; t = TREE_CHAIN (t))
+ {
++ int idx = tree_to_shwi (TREE_VALUE (t)) - 1;
+ tree arg = gimple_call_arg (stmt, idx);
+ if (op == arg)
+ return true;
+ }
+ }
+ }
+
+ return false;
+ }
+
/* If the range of values taken by OP can be inferred after STMT executes,
return the comparison code (COMP_CODE_P) and value (VAL_P) that
describes the inferred range. Return true if a range could be
the datastructures built by VRP. */
identify_jump_threads ();
- set_range_info (name,
- tree_to_double_int (vr_value[i]->min),
- tree_to_double_int (vr_value[i]->max));
+ /* Set value range to non pointer SSA_NAMEs. */
+ for (i = 0; i < num_vr_values; i++)
+ if (vr_value[i])
+ {
+ tree name = ssa_name (i);
+
+ if (!name
+ || POINTER_TYPE_P (TREE_TYPE (name))
+ || (vr_value[i]->type == VR_VARYING)
+ || (vr_value[i]->type == VR_UNDEFINED))
+ continue;
+
+ if ((TREE_CODE (vr_value[i]->min) == INTEGER_CST)
+ && (TREE_CODE (vr_value[i]->max) == INTEGER_CST))
+ {
+ if (vr_value[i]->type == VR_RANGE)
- set_range_info (name,
- double_int_one,
- double_int::max_value
- (TYPE_PRECISION (TREE_TYPE (name)), true));
++ set_range_info (name, vr_value[i]->min, vr_value[i]->max);
+ else if (vr_value[i]->type == VR_ANTI_RANGE)
+ {
+ /* VR_ANTI_RANGE ~[min, max] is encoded compactly as
+ [max + 1, min - 1] without additional attributes.
+ When min value > max value, we know that it is
+ VR_ANTI_RANGE; it is VR_RANGE otherwise. */
+
+ /* ~[0,0] anti-range is represented as
+ range. */
+ if (TYPE_UNSIGNED (TREE_TYPE (name))
+ && integer_zerop (vr_value[i]->min)
+ && integer_zerop (vr_value[i]->max))
- tree_to_double_int (vr_value[i]->max)
- + double_int_one,
- tree_to_double_int (vr_value[i]->min)
- - double_int_one);
++ {
++ max_wide_int tmmwi
++ = max_wide_int::from (wi::max_value (TYPE_PRECISION (TREE_TYPE (name)),
++ UNSIGNED),
++ UNSIGNED);
++ set_range_info (name, 1, tmmwi);
++ }
+ else
+ set_range_info (name,
++ vr_value[i]->max + 1,
++ vr_value[i]->min - 1);
+ }
+ }
+ }
+
/* Free allocated memory. */
for (i = 0; i < num_vr_values; i++)
if (vr_value[i])
mem_ref_offset (const_tree t)
{
tree toff = TREE_OPERAND (t, 1);
- return tree_to_double_int (toff).sext (TYPE_PRECISION (TREE_TYPE (toff)));
+ return wi::sext (addr_wide_int (toff), TYPE_PRECISION (TREE_TYPE (toff)));
}
- /* Return the pointer-type relevant for TBAA purposes from the
- gimple memory reference tree T. This is the type to be used for
- the offset operand of MEM_REF or TARGET_MEM_REF replacements of T. */
-
- tree
- reference_alias_ptr_type (const_tree t)
- {
- const_tree base = t;
- while (handled_component_p (base))
- base = TREE_OPERAND (base, 0);
- if (TREE_CODE (base) == MEM_REF)
- return TREE_TYPE (TREE_OPERAND (base, 1));
- else if (TREE_CODE (base) == TARGET_MEM_REF)
- return TREE_TYPE (TMR_OFFSET (base));
- else
- return build_pointer_type (TYPE_MAIN_VARIANT (TREE_TYPE (base)));
- }
-
/* Return an invariant ADDR_EXPR of type TYPE taking the address of BASE
offsetted by OFFSET units. */
(CASE_LABEL_EXPR_CHECK (NODE)->base.addressable_flag)
#define PREDICT_EXPR_OUTCOME(NODE) \
- ((enum prediction) (PREDICT_EXPR_CHECK(NODE)->base.addressable_flag))
+ ((enum prediction) (PREDICT_EXPR_CHECK (NODE)->base.addressable_flag))
#define SET_PREDICT_EXPR_OUTCOME(NODE, OUTCOME) \
- (PREDICT_EXPR_CHECK(NODE)->base.addressable_flag = (int) OUTCOME)
+ (PREDICT_EXPR_CHECK (NODE)->base.addressable_flag = (int) OUTCOME)
#define PREDICT_EXPR_PREDICTOR(NODE) \
- ((enum br_predictor)tree_low_cst (TREE_OPERAND (PREDICT_EXPR_CHECK (NODE), 0), 0))
+ ((enum br_predictor)tree_to_shwi (TREE_OPERAND (PREDICT_EXPR_CHECK (NODE), 0)))
/* In a VAR_DECL, nonzero means allocate static storage.
In a FUNCTION_DECL, nonzero if function has been defined.
extern tree build_simple_mem_ref_loc (location_t, tree);
#define build_simple_mem_ref(T)\
build_simple_mem_ref_loc (UNKNOWN_LOCATION, T)
- extern tree reference_alias_ptr_type (const_tree);
-extern double_int mem_ref_offset (const_tree);
extern tree build_invariant_address (tree, tree, HOST_WIDE_INT);
extern tree constant_boolean_node (bool, tree);
-extern tree div_if_zero_remainder (enum tree_code, const_tree, const_tree);
+extern tree div_if_zero_remainder (const_tree, const_tree);
extern bool tree_swap_operands_p (const_tree, const_tree, bool);
extern enum tree_code swap_tree_comparison (enum tree_code);