#include "config.h"
#include "system.h"
#include "coretypes.h"
#include "tm.h"
#include "tree.h"
#include "function.h"
#include "c-common.h"
#include "toplev.h"
#include "tree-gimple.h"
#include "bitmap.h"
#include "langhooks.h"
tree
c_finish_omp_master (tree stmt)
{
return add_stmt (build1 (OMP_MASTER, void_type_node, stmt));
}
tree
c_finish_omp_critical (tree body, tree name)
{
tree stmt = make_node (OMP_CRITICAL);
TREE_TYPE (stmt) = void_type_node;
OMP_CRITICAL_BODY (stmt) = body;
OMP_CRITICAL_NAME (stmt) = name;
return add_stmt (stmt);
}
tree
c_finish_omp_ordered (tree stmt)
{
return add_stmt (build1 (OMP_ORDERED, void_type_node, stmt));
}
void
c_finish_omp_barrier (void)
{
tree x;
x = built_in_decls[BUILT_IN_GOMP_BARRIER];
x = build_function_call_expr (x, NULL);
add_stmt (x);
}
tree
c_finish_omp_atomic (enum tree_code code, tree lhs, tree rhs)
{
tree x, type, addr;
if (lhs == error_mark_node || rhs == error_mark_node)
return error_mark_node;
type = TREE_TYPE (lhs);
if (!INTEGRAL_TYPE_P (type)
&& !POINTER_TYPE_P (type)
&& !SCALAR_FLOAT_TYPE_P (type))
{
error ("invalid expression type for %<#pragma omp atomic%>");
return error_mark_node;
}
addr = build_unary_op (ADDR_EXPR, lhs, 0);
if (addr == error_mark_node)
return error_mark_node;
addr = save_expr (addr);
if (TREE_CODE (addr) != SAVE_EXPR
&& (TREE_CODE (addr) != ADDR_EXPR
|| TREE_CODE (TREE_OPERAND (addr, 0)) != VAR_DECL))
{
tree var = create_tmp_var_raw (TREE_TYPE (addr), NULL);
addr = build4 (TARGET_EXPR, TREE_TYPE (addr), var, addr, NULL, NULL);
}
lhs = build_indirect_ref (addr, NULL);
x = build_modify_expr (lhs, code, rhs);
if (x == error_mark_node)
return error_mark_node;
gcc_assert (TREE_CODE (x) == MODIFY_EXPR);
rhs = TREE_OPERAND (x, 1);
return build2 (OMP_ATOMIC, void_type_node, addr, rhs);
}
void
c_finish_omp_flush (void)
{
tree x;
x = built_in_decls[BUILT_IN_SYNCHRONIZE];
x = build_function_call_expr (x, NULL);
add_stmt (x);
}
static tree
check_omp_for_incr_expr (tree exp, tree decl)
{
tree t;
if (!INTEGRAL_TYPE_P (TREE_TYPE (exp))
|| TYPE_PRECISION (TREE_TYPE (exp)) < TYPE_PRECISION (TREE_TYPE (decl)))
return error_mark_node;
if (exp == decl)
return build_int_cst (TREE_TYPE (exp), 0);
switch (TREE_CODE (exp))
{
case NOP_EXPR:
t = check_omp_for_incr_expr (TREE_OPERAND (exp, 0), decl);
if (t != error_mark_node)
return fold_convert (TREE_TYPE (exp), t);
break;
case MINUS_EXPR:
t = check_omp_for_incr_expr (TREE_OPERAND (exp, 0), decl);
if (t != error_mark_node)
return fold_build2 (MINUS_EXPR, TREE_TYPE (exp), t, TREE_OPERAND (exp, 1));
break;
case PLUS_EXPR:
t = check_omp_for_incr_expr (TREE_OPERAND (exp, 0), decl);
if (t != error_mark_node)
return fold_build2 (PLUS_EXPR, TREE_TYPE (exp), t, TREE_OPERAND (exp, 1));
t = check_omp_for_incr_expr (TREE_OPERAND (exp, 1), decl);
if (t != error_mark_node)
return fold_build2 (PLUS_EXPR, TREE_TYPE (exp), TREE_OPERAND (exp, 0), t);
break;
default:
break;
}
return error_mark_node;
}
tree
c_finish_omp_for (location_t locus, tree decl, tree init, tree cond,
tree incr, tree body, tree pre_body)
{
location_t elocus = locus;
bool fail = false;
if (EXPR_HAS_LOCATION (init))
elocus = EXPR_LOCATION (init);
if (!INTEGRAL_TYPE_P (TREE_TYPE (decl)))
{
error ("%Hinvalid type for iteration variable %qE", &elocus, decl);
fail = true;
}
if (TYPE_UNSIGNED (TREE_TYPE (decl)))
warning (0, "%Hiteration variable %qE is unsigned", &elocus, decl);
if (init == decl)
{
elocus = DECL_SOURCE_LOCATION (decl);
init = DECL_INITIAL (decl);
if (init == NULL)
{
error ("%H%qE is not initialized", &elocus, decl);
init = integer_zero_node;
fail = true;
}
init = build_modify_expr (decl, NOP_EXPR, init);
SET_EXPR_LOCATION (init, elocus);
}
gcc_assert (TREE_CODE (init) == MODIFY_EXPR);
gcc_assert (TREE_OPERAND (init, 0) == decl);
if (cond == NULL_TREE)
{
error ("%Hmissing controlling predicate", &elocus);
fail = true;
}
else
{
bool cond_ok = false;
if (EXPR_HAS_LOCATION (cond))
elocus = EXPR_LOCATION (cond);
if (TREE_CODE (cond) == LT_EXPR
|| TREE_CODE (cond) == LE_EXPR
|| TREE_CODE (cond) == GT_EXPR
|| TREE_CODE (cond) == GE_EXPR)
{
tree op0 = TREE_OPERAND (cond, 0);
tree op1 = TREE_OPERAND (cond, 1);
if (TREE_CODE (op0) == NOP_EXPR
&& decl == TREE_OPERAND (op0, 0))
{
TREE_OPERAND (cond, 0) = TREE_OPERAND (op0, 0);
TREE_OPERAND (cond, 1) = fold_build1 (NOP_EXPR, TREE_TYPE (decl),
TREE_OPERAND (cond, 1));
}
else if (TREE_CODE (op1) == NOP_EXPR
&& decl == TREE_OPERAND (op1, 0))
{
TREE_OPERAND (cond, 1) = TREE_OPERAND (op1, 0);
TREE_OPERAND (cond, 0) = fold_build1 (NOP_EXPR, TREE_TYPE (decl),
TREE_OPERAND (cond, 0));
}
if (decl == TREE_OPERAND (cond, 0))
cond_ok = true;
else if (decl == TREE_OPERAND (cond, 1))
{
TREE_SET_CODE (cond, swap_tree_comparison (TREE_CODE (cond)));
TREE_OPERAND (cond, 1) = TREE_OPERAND (cond, 0);
TREE_OPERAND (cond, 0) = decl;
cond_ok = true;
}
}
if (!cond_ok)
{
error ("%Hinvalid controlling predicate", &elocus);
fail = true;
}
}
if (incr == NULL_TREE)
{
error ("%Hmissing increment expression", &elocus);
fail = true;
}
else
{
bool incr_ok = false;
if (EXPR_HAS_LOCATION (incr))
elocus = EXPR_LOCATION (incr);
switch (TREE_CODE (incr))
{
case POSTINCREMENT_EXPR:
case PREINCREMENT_EXPR:
case POSTDECREMENT_EXPR:
case PREDECREMENT_EXPR:
incr_ok = (TREE_OPERAND (incr, 0) == decl);
break;
case MODIFY_EXPR:
if (TREE_OPERAND (incr, 0) != decl)
break;
if (TREE_OPERAND (incr, 1) == decl)
break;
if (TREE_CODE (TREE_OPERAND (incr, 1)) == PLUS_EXPR
&& (TREE_OPERAND (TREE_OPERAND (incr, 1), 0) == decl
|| TREE_OPERAND (TREE_OPERAND (incr, 1), 1) == decl))
incr_ok = true;
else if (TREE_CODE (TREE_OPERAND (incr, 1)) == MINUS_EXPR
&& TREE_OPERAND (TREE_OPERAND (incr, 1), 0) == decl)
incr_ok = true;
else
{
tree t = check_omp_for_incr_expr (TREE_OPERAND (incr, 1), decl);
if (t != error_mark_node)
{
incr_ok = true;
t = build2 (PLUS_EXPR, TREE_TYPE (decl), decl, t);
incr = build2 (MODIFY_EXPR, void_type_node, decl, t);
}
}
break;
default:
break;
}
if (!incr_ok)
{
error ("%Hinvalid increment expression", &elocus);
fail = true;
}
}
if (fail)
return NULL;
else
{
tree t = make_node (OMP_FOR);
TREE_TYPE (t) = void_type_node;
OMP_FOR_INIT (t) = init;
OMP_FOR_COND (t) = cond;
OMP_FOR_INCR (t) = incr;
OMP_FOR_BODY (t) = body;
OMP_FOR_PRE_BODY (t) = pre_body;
SET_EXPR_LOCATION (t, locus);
return add_stmt (t);
}
}
void
c_split_parallel_clauses (tree clauses, tree *par_clauses, tree *ws_clauses)
{
tree next;
*par_clauses = NULL;
*ws_clauses = build_omp_clause (OMP_CLAUSE_NOWAIT);
for (; clauses ; clauses = next)
{
next = OMP_CLAUSE_CHAIN (clauses);
switch (OMP_CLAUSE_CODE (clauses))
{
case OMP_CLAUSE_PRIVATE:
case OMP_CLAUSE_SHARED:
case OMP_CLAUSE_FIRSTPRIVATE:
case OMP_CLAUSE_LASTPRIVATE:
case OMP_CLAUSE_REDUCTION:
case OMP_CLAUSE_COPYIN:
case OMP_CLAUSE_IF:
case OMP_CLAUSE_NUM_THREADS:
case OMP_CLAUSE_DEFAULT:
OMP_CLAUSE_CHAIN (clauses) = *par_clauses;
*par_clauses = clauses;
break;
case OMP_CLAUSE_SCHEDULE:
case OMP_CLAUSE_ORDERED:
OMP_CLAUSE_CHAIN (clauses) = *ws_clauses;
*ws_clauses = clauses;
break;
default:
gcc_unreachable ();
}
}
}
enum omp_clause_default_kind
c_omp_predetermined_sharing (tree decl)
{
if (TREE_READONLY (decl))
return OMP_CLAUSE_DEFAULT_SHARED;
return OMP_CLAUSE_DEFAULT_UNSPECIFIED;
}