===================================================================
@@ -228,6 +228,20 @@ int print_struct_values;
const char *constant_string_class_name;
+/* UPC language option variables. */
+
+/* Nonzero whenever UPC -fupc-threads=N is asserted.
+ The value N gives the number of UPC threads to be
+ defined at compile-time. */
+int flag_upc_threads;
+
+/* Nonzero whenever UPC -fupc-pthreads-model-* is asserted. */
+int flag_upc_pthreads;
+
+/* The implementation model for UPC threads that
+ are mapped to POSIX threads, specified at compilation
+ time by the -fupc-pthreads-model-* switch. */
+upc_pthreads_model_kind upc_pthreads_model;
/* C++ language option variables. */
@@ -408,8 +422,9 @@ static int resort_field_decl_cmp (const
C --std=c89: D_C99 | D_CXXONLY | D_OBJC | D_CXX_OBJC
C --std=c99: D_CXXONLY | D_OBJC
ObjC is like C except that D_OBJC and D_CXX_OBJC are not set
- C++ --std=c98: D_CONLY | D_CXXOX | D_OBJC
- C++ --std=c0x: D_CONLY | D_OBJC
+ UPC is like C except that D_UPC is not set
+ C++ --std=c98: D_CONLY | D_CXXOX | D_OBJC | D_UPC
+ C++ --std=c0x: D_CONLY | D_OBJC | D_UPC
ObjC++ is like C++ except that D_OBJC is not set
If -fno-asm is used, D_ASM is added to the mask. If
@@ -625,6 +640,19 @@ const struct c_common_resword c_common_r
{ "inout", RID_INOUT, D_OBJC },
{ "oneway", RID_ONEWAY, D_OBJC },
{ "out", RID_OUT, D_OBJC },
+
+ /* UPC keywords */
+ { "shared", RID_SHARED, D_UPC },
+ { "relaxed", RID_RELAXED, D_UPC },
+ { "strict", RID_STRICT, D_UPC },
+ { "upc_barrier", RID_UPC_BARRIER, D_UPC },
+ { "upc_blocksizeof", RID_UPC_BLOCKSIZEOF, D_UPC },
+ { "upc_elemsizeof", RID_UPC_ELEMSIZEOF, D_UPC },
+ { "upc_forall", RID_UPC_FORALL, D_UPC },
+ { "upc_localsizeof", RID_UPC_LOCALSIZEOF, D_UPC },
+ { "upc_notify", RID_UPC_NOTIFY, D_UPC },
+ { "upc_wait", RID_UPC_WAIT, D_UPC },
+
/* These are recognized inside a property attribute list */
{ "assign", RID_ASSIGN, D_OBJC },
{ "copy", RID_COPY, D_OBJC },
@@ -1467,11 +1495,14 @@ c_fully_fold_internal (tree expr, bool i
goto out;
/* ??? Cope with user tricks that amount to offsetof. The middle-end is
- not prepared to deal with them if they occur in initializers. */
+ not prepared to deal with them if they occur in initializers.
+ Avoid attempts to fold references to UPC shared components
+ due to the complexities of UPC pointer-to-shared arithmetic. */
if (op0 != orig_op0
&& code == ADDR_EXPR
&& (op1 = get_base_address (op0)) != NULL_TREE
&& INDIRECT_REF_P (op1)
+ && !SHARED_TYPE_P (TREE_TYPE (op1))
&& TREE_CONSTANT (TREE_OPERAND (op1, 0)))
ret = fold_convert_loc (loc, TREE_TYPE (expr), fold_offsetof_1 (op0));
else if (op0 != orig_op0 || in_init)
@@ -4797,6 +4828,11 @@ pointer_int_sum (location_t loc, enum tr
/* The result is a pointer of the same type that is being added. */
tree result_type = TREE_TYPE (ptrop);
+ /* If the pointer lives in UPC shared memory, then
+ drop the 'shared' qualifier. */
+ if (TREE_SHARED (ptrop) || SHARED_TYPE_P (result_type))
+ result_type = build_unshared_type (result_type);
+
if (TREE_CODE (TREE_TYPE (result_type)) == VOID_TYPE)
{
if (complain && warn_pointer_arith)
@@ -5212,6 +5248,17 @@ c_apply_type_quals_to_decl (int type_qua
|| !C_TYPE_OBJECT_OR_INCOMPLETE_P (TREE_TYPE (type)))
error ("invalid use of %<restrict%>");
}
+ if (type_quals & TYPE_QUAL_SHARED)
+ {
+ TREE_SHARED (decl) = 1;
+ if (type_quals & TYPE_QUAL_STRICT)
+ TREE_STRICT(decl) = 1;
+ else if (type_quals & TYPE_QUAL_RELAXED)
+ TREE_RELAXED(decl) = 1;
+ /* The declaration's type should have been previously defined
+ as a UPC shared type. */
+ gcc_assert (SHARED_TYPE_P (type));
+ }
}
struct c_type_hasher : ggc_ptr_hash<tree_node>
@@ -5328,6 +5375,18 @@ c_common_get_alias_set (tree t)
return get_alias_set (t1);
}
+ /* For the time being, make UPC pointers-to-shared conflict
+ with everything else. Ideally, UPC pointers-to-shared should
+ only conflict with the internal type used to represent
+ the UPC pointer-to-shared (i.e., upc_pts_rep_type_node). */
+
+ if (TYPE_P (t) ? (TREE_CODE (t) == POINTER_TYPE
+ && SHARED_TYPE_P (TREE_TYPE (t)))
+ : (TREE_TYPE(t)
+ && TREE_CODE (TREE_TYPE (t)) == POINTER_TYPE
+ && SHARED_TYPE_P (TREE_TYPE (TREE_TYPE (t)))))
+ return 0;
+
/* Handle the case of multiple type nodes referring to "the same" type,
which occurs with IMA. These share an alias set. FIXME: Currently only
C90 is handled. (In C99 type compatibility is not transitive, which
@@ -5385,6 +5444,44 @@ c_common_get_alias_set (tree t)
return -1;
}
+/* Return the value of THREADS.
+
+ UPC defines a reserved variable, THREADS, which returns the
+ number of threads that will be created when the UPC program
+ executes. The value of threads can be specified at runtime via
+ the -fupc-threads=N switch, where N is an integer specifying
+ the number of threads. When the value of THREADS is specified
+ at compile-time, this is called the "static threads compilation
+ environment".
+
+ In the static threads compilation environment, THREADS is a
+ pre-defined preprocessor macro with the value, N.
+
+ If no value for threads is given at compile-time, then the value
+ must be specified when the application program is executed.
+ This method of establishing the value of THREADS is called
+ the "dynamic threads compilation environment". */
+
+tree
+upc_num_threads (void)
+{
+ tree n;
+ gcc_assert (flag_upc);
+ n = flag_upc_threads ? ssize_int (flag_upc_threads)
+ : lookup_name (get_identifier ("THREADS"));
+ if (!n)
+ {
+ error ("the UPC-required THREADS variable is undefined; "
+ "when compiling pre-processed source, "
+ "all -fupc-* switches must be passed on the command line, "
+ "asserting the same values as supplied when the "
+ "original source file was preprocessed");
+ abort ();
+ }
+
+ return n;
+}
+
/* Compute the value of 'sizeof (TYPE)' or '__alignof__ (TYPE)', where
the IS_SIZEOF parameter indicates which operator is being applied.
The COMPLAIN flag controls whether we should diagnose possibly
@@ -5431,11 +5528,16 @@ c_sizeof_or_alignof_type (location_t loc
}
else if (type_code == VOID_TYPE || type_code == ERROR_MARK)
{
- if (type_code == VOID_TYPE
- && complain && warn_pointer_arith)
- pedwarn (loc, OPT_Wpointer_arith,
- "invalid application of %qs to a void type", op_name);
- else if (!complain)
+ if (complain)
+ {
+ if (type_code == VOID_TYPE && SHARED_TYPE_P (type))
+ error_at (loc, "invalid application of %qs"
+ " to %<shared void%> type", op_name);
+ else if (type_code == VOID_TYPE && warn_pointer_arith)
+ pedwarn (loc, pedantic ? OPT_Wpedantic : OPT_Wpointer_arith,
+ "invalid application of %qs to a void type", op_name);
+ }
+ else
return error_mark_node;
value = size_one_node;
}
@@ -5468,6 +5570,14 @@ c_sizeof_or_alignof_type (location_t loc
value = size_int (TYPE_ALIGN_UNIT (type));
}
+ if (is_sizeof && (TREE_CODE (type) == ARRAY_TYPE)
+ && SHARED_TYPE_P (type)
+ && TYPE_HAS_THREADS_FACTOR (type))
+ {
+ const tree n_threads = convert (sizetype, upc_num_threads ());
+ value = size_binop (MULT_EXPR, value, n_threads);
+ }
+
/* VALUE will have the middle-end integer type sizetype.
However, we should really return a value of type `size_t',
which is just a typedef for an ordinary integer type. */
@@ -11093,6 +11203,10 @@ complete_array_type (tree *ptype, tree i
}
type = *ptype;
+ /* Force an indefinite layout factor. */
+ if (SHARED_TYPE_P (type))
+ type = c_build_qualified_type_1 (type, TYPE_QUAL_SHARED,
+ size_zero_node);
elt = TREE_TYPE (type);
quals = TYPE_QUALS (strip_array_types (elt));
if (quals == 0)
@@ -12862,6 +12976,8 @@ c_common_init_ts (void)
MARK_TS_TYPED (C_MAYBE_CONST_EXPR);
MARK_TS_TYPED (EXCESS_PRECISION_EXPR);
MARK_TS_TYPED (ARRAY_NOTATION_REF);
+ MARK_TS_COMMON (UPC_FORALL_STMT);
+ MARK_TS_COMMON (UPC_SYNC_STMT);
}
/* Build a user-defined numeric literal out of an integer constant type VALUE
===================================================================
@@ -62,6 +62,24 @@ DEFTREECODE (SIZEOF_EXPR, "sizeof_expr",
Operand 3 is the stride. */
DEFTREECODE (ARRAY_NOTATION_REF, "array_notation_ref", tcc_reference, 4)
+/* Used to represent a `upc_forall' statement. The operands are
+ UPC_FORALL_INIT_STMT, UPC_FORALL_COND, UPC_FORALL_EXPR,
+ UPC_FORALL_BODY, and UPC_FORALL_AFFINITY respectively. */
+
+DEFTREECODE (UPC_FORALL_STMT, "upc_forall_stmt", tcc_statement, 5)
+
+/* Used to represent a UPC synchronization statement. The first
+ operand is the synchronization operation, UPC_SYNC_OP:
+ UPC_SYNC_NOTIFY_OP 1 Notify operation
+ UPC_SYNC_WAIT_OP 2 Wait operation
+ UPC_SYNC_BARRIER_OP 3 Barrier operation
+
+ The second operand, UPC_SYNC_ID is the (optional) expression
+ whose value specifies the barrier identifier which is checked
+ by the various synchronization operations. */
+
+DEFTREECODE (UPC_SYNC_STMT, "upc_sync_stmt", tcc_statement, 2)
+
/*
Local variables:
mode:c
===================================================================
@@ -54,9 +54,9 @@ never after.
*/
/* Reserved identifiers. This is the union of all the keywords for C,
- C++, and Objective-C. All the type modifiers have to be in one
+ C++, Objective-C, and UPC. All the type modifiers have to be in one
block at the beginning, because they are used as mask bits. There
- are 28 type modifiers; if we add many more we will have to redesign
+ are 31 type modifiers; if we add many more we will have to redesign
the mask mechanism. */
enum rid
@@ -69,6 +69,9 @@ enum rid
RID_VOLATILE, RID_SIGNED, RID_AUTO, RID_RESTRICT,
RID_NORETURN, RID_ATOMIC,
+ /* UPC type qualifiers */
+ RID_SHARED, RID_RELAXED, RID_STRICT,
+
/* C extensions */
RID_COMPLEX, RID_THREAD, RID_SAT,
@@ -173,6 +176,11 @@ enum rid
RID_AT_INTERFACE,
RID_AT_IMPLEMENTATION,
+ /* UPC */
+ RID_UPC_BARRIER, RID_UPC_BLOCKSIZEOF, RID_UPC_ELEMSIZEOF,
+ RID_UPC_FORALL, RID_UPC_LOCALSIZEOF,
+ RID_UPC_NOTIFY, RID_UPC_WAIT,
+
/* Named address support, mapping the keyword to a particular named address
number. Named address space 0 is reserved for the generic address. If
there are more than 254 named addresses, the addr_space_t type will need
@@ -221,6 +229,10 @@ enum rid
RID_FIRST_CXX11 = RID_CONSTEXPR,
RID_LAST_CXX11 = RID_STATIC_ASSERT,
+ RID_FIRST_UPC_QUAL = RID_SHARED,
+ RID_LAST_UPC_QUAL = RID_STRICT,
+ RID_FIRST_UPC_KW = RID_UPC_BARRIER,
+ RID_LAST_UPC_KW = RID_UPC_WAIT,
RID_FIRST_AT = RID_AT_ENCODE,
RID_LAST_AT = RID_AT_IMPLEMENTATION,
RID_FIRST_PQ = RID_IN,
@@ -253,6 +265,13 @@ enum rid
|| rid == RID_PUBLIC || rid == RID_PROTECTED || rid == RID_PRIVATE \
|| rid == RID_TRY || rid == RID_THROW || rid == RID_CATCH)
+/* Test whether a reserved ID designates a UPC keyword. */
+#define UPC_IS_KEYWORD(rid) \
+ (((unsigned int) (rid) >= (unsigned int) RID_FIRST_UPC_QUAL && \
+ (unsigned int) (rid) <= (unsigned int) RID_LAST_UPC_QUAL) || \
+ ((unsigned int) (rid) >= (unsigned int) RID_FIRST_UPC_KW && \
+ (unsigned int) (rid) <= (unsigned int) RID_LAST_UPC_KW))
+
/* The elements of `ridpointers' are identifier nodes for the reserved
type names and storage classes. It is indexed by a RID_... value. */
extern GTY ((length ("(int) RID_MAX"))) tree *ridpointers;
@@ -395,6 +414,7 @@ extern machine_mode c_default_pointer_mo
#define D_CXXWARN 0x200 /* In C warn with -Wcxx-compat. */
#define D_CXX_CONCEPTS 0x400 /* In C++, only with concepts. */
#define D_TRANSMEM 0X800 /* C++ transactional memory TS. */
+#define D_UPC 0x1000 /* In UPC, and neither C nor C++. */
#define D_CXX_CONCEPTS_FLAGS D_CXXONLY | D_CXX_CONCEPTS
@@ -612,6 +632,25 @@ extern const char *pch_file;
extern int flag_iso;
+/* Nonzero whenever UPC -fupc-threads=N is asserted.
+ The value N gives the number of UPC threads to be
+ defined at compile-time. */
+extern int flag_upc_threads;
+
+/* Nonzero whenever UPC -fupc-pthreads-model-* is asserted. */
+extern int flag_upc_pthreads;
+
+typedef enum
+ {
+ upc_pthreads_no_model = 0,
+ upc_pthreads_tls_model = 1
+ } upc_pthreads_model_kind;
+
+/* The implementation model for UPC threads that
+ are mapped to POSIX threads, specified at compilation
+ time by the -fupc-pthreads-model-* switch. */
+extern upc_pthreads_model_kind upc_pthreads_model;
+
/* C/ObjC language option variables. */
@@ -866,7 +905,8 @@ extern tree pointer_int_sum (location_t,
bool = true);
/* Add qualifiers to a type, in the fashion for C. */
-extern tree c_build_qualified_type (tree, int);
+extern tree c_build_qualified_type_1 (tree, int, tree);
+#define c_build_qualified_type(TYPE, QUALS) c_build_qualified_type_1 (TYPE, QUALS, 0)
/* Build tree nodes and builtin functions common to both C and C++ language
frontends. */
@@ -896,6 +936,7 @@ extern int self_promoting_args_p (const_
extern tree strip_pointer_operator (tree);
extern tree strip_pointer_or_array_types (tree);
extern HOST_WIDE_INT c_common_to_target_charset (HOST_WIDE_INT);
+extern tree upc_num_threads (void);
/* This is the basic parsing function. */
extern void c_parse_file (void);
@@ -1112,6 +1153,9 @@ extern void c_stddef_cpp_builtins (void)
extern void fe_file_change (const line_map_ordinary *);
extern void c_parse_error (const char *, enum cpp_ttype, tree, unsigned char);
+/* In c-lex.c */
+extern int c_header_level; /* In system header, if > 0. */
+
/* In c-ppoutput.c */
extern void init_pp_output (FILE *);
extern void preprocess_file (cpp_reader *);
@@ -1295,6 +1339,25 @@ c_tree_chain_next (tree t)
return NULL;
}
+/* Used to represent a UPC synchronization statement.
+ The first operand is the synchronization operation, UPC_SYNC_OP:
+ UPC_SYNC_NOTIFY_OP 1 Notify operation
+ UPC_SYNC_WAIT_OP 2 Wait operation
+ UPC_SYNC_BARRIER_OP 3 Barrier operation
+
+ The second operand, UPC_SYNC_ID is the (optional) expression
+ whose value specifies the barrier identifier which is checked
+ by the various synchronization operations. */
+
+#define UPC_SYNC_OP(NODE) TREE_OPERAND (UPC_SYNC_STMT_CHECK (NODE), 0)
+#define UPC_SYNC_ID(NODE) TREE_OPERAND (UPC_SYNC_STMT_CHECK (NODE), 1)
+
+/* Values of the first operand in a UPC_SYNC_STMT */
+
+#define UPC_SYNC_NOTIFY_OP 1 /* Notify operation */
+#define UPC_SYNC_WAIT_OP 2 /* Wait operation */
+#define UPC_SYNC_BARRIER_OP 3 /* Barrier operation */
+
/* Mask used by tm_stmt_attr. */
#define TM_STMT_ATTR_OUTER 2
#define TM_STMT_ATTR_ATOMIC 4
===================================================================
@@ -27,6 +27,7 @@ along with GCC; see the file COPYING3.
#include "stor-layout.h"
#include "flags.h"
#include "c-pragma.h"
+#include "c-upc-pts.h"
#include "output.h" /* For user_label_prefix. */
#include "debug.h" /* For dwarf2out_do_cfi_asm. */
#include "common/common-target.h"
@@ -766,6 +767,92 @@ cpp_iec_559_complex_value (void)
return ret;
}
+/* Return the section name with any leading "__DATA," or "__TEXT," removed.
+ (Darwin adds them to the section name). */
+static const char *
+strip_section_prefix (const char *section_name)
+{
+ const char *name = section_name;
+ if ((strncmp (name, "__DATA,", 7) == 0)
+ || (strncmp (name, "__TEXT,", 7) == 0))
+ name += 7;
+ return name;
+}
+
+/* Generate UPC specific pre-defined macros. */
+
+static void
+upc_cpp_builtins (cpp_reader * pfile)
+{
+ char def_buf[256];
+ cpp_define (pfile, "__UPC__=1");
+ cpp_define (pfile, "__GUPC__=1");
+ /* Define __GCC_UPC__ for backward compatibility. */
+ cpp_define (pfile, "__GCC_UPC__=1");
+ cpp_define (pfile, "__UPC_VERSION__=201311L");
+ (void) sprintf (def_buf, "UPC_MAX_BLOCK_SIZE=%lu",
+ (unsigned long) UPC_MAX_BLOCK_SIZE);
+ cpp_define (pfile, def_buf);
+ cpp_define (pfile, "__UPC_PTS_STRUCT_REP__=1");
+ (void) sprintf (def_buf, "__UPC_VADDR_TYPE__=%s", UPC_PTS_VADDR_TYPE);
+ cpp_define (pfile, def_buf);
+ (void) sprintf (def_buf, "__UPC_THREAD_TYPE__=%s", UPC_PTS_THREAD_TYPE);
+ cpp_define (pfile, def_buf);
+ (void) sprintf (def_buf, "__UPC_PHASE_TYPE__=%s", UPC_PTS_PHASE_TYPE);
+ cpp_define (pfile, def_buf);
+ (void) sprintf (def_buf, "__UPC_PTS_ALIGN__=%d",
+ (2 * POINTER_SIZE) / BITS_PER_UNIT);
+ cpp_define (pfile, def_buf);
+ cpp_define (pfile, "__UPC_VADDR_FIRST__=1");
+ (void) sprintf (def_buf, "__UPC_PTS_SIZE__=%d", UPC_PTS_SIZE);
+ cpp_define (pfile, def_buf);
+ (void) sprintf (def_buf, "__UPC_VADDR_SIZE__=%d", UPC_PTS_VADDR_SIZE);
+ cpp_define (pfile, def_buf);
+ (void) sprintf (def_buf, "__UPC_THREAD_SIZE__=%d", UPC_PTS_THREAD_SIZE);
+ cpp_define (pfile, def_buf);
+ (void) sprintf (def_buf, "__UPC_PHASE_SIZE__=%d", UPC_PTS_PHASE_SIZE);
+ cpp_define (pfile, def_buf);
+ if (flag_upc_threads)
+ {
+ cpp_define (pfile, "__UPC_STATIC_THREADS__=1");
+ (void) sprintf (def_buf, "THREADS=%d", flag_upc_threads);
+ cpp_define (pfile, def_buf);
+ }
+ else
+ {
+ cpp_define (pfile, "__UPC_DYNAMIC_THREADS__=1");
+ }
+ if (flag_upc_pthreads && (upc_pthreads_model == upc_pthreads_tls_model))
+ {
+ cpp_define (pfile, "__UPC_PTHREADS_MODEL_TLS__=1");
+ }
+ /* If debugging or instrumentation is enabled,
+ then disable inlining of the runtime. */
+ if (flag_upc_debug || flag_upc_instrument)
+ flag_upc_inline_lib = 0;
+ /* If -f[no-]upc-inline-lib hasn't been asserted, force inlining of the
+ runtime library if optimization is enabled. */
+ if (flag_upc_inline_lib < 0)
+ flag_upc_inline_lib = (optimize >= 1);
+ if (flag_upc_inline_lib)
+ cpp_define (parse_in, "__UPC_INLINE_LIB__=1");
+ /* UPC profiling instrumentation code will be generated. */
+ if (flag_upc_instrument)
+ {
+ cpp_define (parse_in, "__UPC_PUPC_INST__=1");
+ }
+ if (targetm.upc.link_script_p ())
+ {
+ cpp_define (parse_in, "__UPC_LINK_SCRIPT__=1");
+ }
+ builtin_define_with_value ("__UPC_SHARED_SECTION_NAME__",
+ strip_section_prefix (targetm.upc.shared_section_name ()), 0);
+ builtin_define_with_value ("__UPC_PGM_INFO_SECTION_NAME__",
+ strip_section_prefix (targetm.upc.pgm_info_section_name ()), 0);
+ builtin_define_with_value ("__UPC_INIT_ARRAY_SECTION_NAME__",
+ strip_section_prefix (targetm.upc.init_array_section_name ()), 0);
+}
+
/* Hook that registers front end and target-specific built-ins. */
void
c_cpp_builtins (cpp_reader *pfile)
@@ -1226,6 +1313,10 @@ c_cpp_builtins (cpp_reader *pfile)
if (flag_openmp)
cpp_define (pfile, "_OPENMP=201511");
+ /* Add UPC defines */
+ if (flag_upc)
+ upc_cpp_builtins (pfile);
+
for (i = 0; i < NUM_INT_N_ENTS; i ++)
if (int_n_enabled_p[i])
{
===================================================================
@@ -35,7 +35,7 @@ static int header_time, body_time;
static splay_tree file_info_tree;
int pending_lang_change; /* If we need to switch languages - C++ only */
-int c_header_level; /* depth in C headers - C++ only */
+int c_header_level; /* depth in C headers - C++ and UPC */
static tree interpret_integer (const cpp_token *, unsigned int,
enum overflow_type *);
@@ -202,27 +202,27 @@ fe_file_change (const line_map_ordinary
input_location = new_map->start_location;
(*debug_hooks->start_source_file) (line, LINEMAP_FILE (new_map));
-#ifndef NO_IMPLICIT_EXTERN_C
if (c_header_level)
++c_header_level;
else if (LINEMAP_SYSP (new_map) == 2)
{
c_header_level = 1;
+#ifndef NO_IMPLICIT_EXTERN_C
++pending_lang_change;
- }
#endif
+ }
}
}
else if (new_map->reason == LC_LEAVE)
{
-#ifndef NO_IMPLICIT_EXTERN_C
if (c_header_level && --c_header_level == 0)
{
if (LINEMAP_SYSP (new_map) == 2)
warning (0, "badly nested C headers from preprocessor");
+#ifndef NO_IMPLICIT_EXTERN_C
--pending_lang_change;
- }
#endif
+ }
input_location = new_map->start_location;
(*debug_hooks->end_source_file) (LINEMAP_LINE (new_map));
===================================================================
@@ -30,6 +30,7 @@ along with GCC; see the file COPYING3.
#include "attribs.h"
#include "varasm.h"
#include "c-pragma.h"
+#include "langhooks.h"
#include "opts.h"
#include "plugin.h"
@@ -553,6 +554,237 @@ add_to_renaming_pragma_list (tree oldnam
/* The current prefix set by #pragma extern_prefix. */
GTY(()) tree pragma_extern_prefix;
+/* variables used to implement #pragma upc semantics */
+#ifndef UPC_CMODE_STACK_INCREMENT
+#define UPC_CMODE_STACK_INCREMENT 32
+#endif
+static int pragma_upc_permitted;
+static int upc_cmode;
+static int *upc_cmode_stack;
+static int upc_cmode_stack_in_use;
+static int upc_cmode_stack_allocated;
+
+static void init_pragma_upc (void);
+static void handle_pragma_upc (cpp_reader * ARG_UNUSED (dummy));
+
+/* Initialize the variables used to manage the current UPC consistency
+ mode (strict/relaxed). */
+
+static void
+init_pragma_upc (void)
+{
+ pragma_upc_permitted = 0;
+ upc_cmode = 0;
+ upc_cmode_stack = (int *) xcalloc (UPC_CMODE_STACK_INCREMENT,
+ sizeof (int));
+ upc_cmode_stack_allocated = UPC_CMODE_STACK_INCREMENT;
+ upc_cmode_stack_in_use = 0;
+}
+
+/*
+ * #pragma upc strict
+ * #pragma upc relaxed
+ * #pragma upc upc_code
+ * #pragma upc c_code
+ */
+static void
+handle_pragma_upc (cpp_reader * ARG_UNUSED (dummy))
+{
+ tree x;
+ enum cpp_ttype t;
+ enum upc_pragma_op {p_strict, p_relaxed, p_upc_code,
+ p_c_code, p_detect_upc, p_unknown};
+ enum upc_pragma_op upc_pragma = p_unknown;
+
+ t = pragma_lex (&x);
+ if (t == CPP_NAME)
+ {
+ const char *op = IDENTIFIER_POINTER (x);
+ if (!strcmp (op, "strict"))
+ upc_pragma = p_strict;
+ else if (!strcmp (op, "relaxed"))
+ upc_pragma = p_relaxed;
+ else if (!strcmp (op, "upc_code"))
+ upc_pragma = p_upc_code;
+ else if (!strcmp (op, "c_code"))
+ upc_pragma = p_c_code;
+ else if (!strcmp (op, "detect_upc"))
+ {
+ const char *detect_op;
+ upc_pragma = p_detect_upc;
+ t = pragma_lex (&x);
+ if (t != CPP_NAME)
+ GCC_BAD ("missing [suspend_insertion|resume_insertion]"
+ " after %<#pragma UPC detect_upc%>");
+ detect_op = IDENTIFIER_POINTER (x);
+ if (strcmp (detect_op, "suspend_insertion") == 0)
+ /* no action */;
+ else if (strcmp (detect_op, "resume_insertion") == 0)
+ /* no action */;
+ else
+ GCC_BAD ("expected [suspend_insertion|resume_insertion]"
+ " after %<#pragma UPC detect_upc%>");
+ }
+ else
+ GCC_BAD2 ("unknown action '%s' for '#pragma upc' - ignored", op);
+ }
+ else
+ warning (OPT_Wpragmas, "missing parameter after #pragma upc");
+
+ t = pragma_lex (&x);
+ if (t != CPP_EOF)
+ warning (OPT_Wpragmas, "junk at end of #pragma upc");
+
+ if ((upc_pragma == p_strict) || (upc_pragma == p_relaxed))
+ {
+ if (pragma_upc_permitted_p ())
+ {
+ int consistency_mode = (upc_pragma == p_strict);
+ set_upc_consistency_mode (consistency_mode);
+ }
+ else
+ warning (OPT_Wpragmas, "#pragma upc not allowed in this context");
+ }
+ else if ((upc_pragma == p_upc_code) || (upc_pragma == p_c_code))
+ {
+ flag_upc = (upc_pragma == p_upc_code);
+ lang_hooks.upc.toggle_keywords (flag_upc);
+ }
+ else if (upc_pragma == p_detect_upc)
+ {
+ /* Skip: This is a Berkeley-specific pragma that requires no action. */
+ }
+}
+
+/* Set the current setting of the UPC consistency mode
+ that is in effect. */
+
+void
+set_upc_consistency_mode (int mode)
+{
+ upc_cmode = mode;
+}
+
+/* Return the current setting of the UPC consistency mode. */
+
+int
+get_upc_consistency_mode (void)
+{
+ return upc_cmode;
+}
+
+/* Called from the parser just after the bracket that opens a compound
+ statement has been parsed. Set the flag that allows the pragma
+ in this context. */
+
+void
+permit_pragma_upc (void)
+{
+ pragma_upc_permitted = 1;
+}
+
+/* Called just before the body of a compound statement is parsed.
+ Clear the flag that allows the pragma. */
+
+void
+deny_pragma_upc (void)
+{
+ pragma_upc_permitted = 0;
+}
+
+/* A #pragma upc is permitted either at the outermost scope,
+ or directly after the bracket that opens a compound statement. */
+
+int
+pragma_upc_permitted_p (void)
+{
+ return !current_function_decl || pragma_upc_permitted;
+}
+
+/* Called at the beginning of every compound statement.
+ Pushes the old value of the current UPC consistency mode
+ onto the stack. */
+
+void
+push_upc_consistency_mode (void)
+{
+ if (upc_cmode_stack_in_use == upc_cmode_stack_allocated)
+ {
+ upc_cmode_stack_allocated += UPC_CMODE_STACK_INCREMENT;
+ upc_cmode_stack = (int *) xrealloc (upc_cmode_stack,
+ upc_cmode_stack_allocated * sizeof (int));
+ }
+ upc_cmode_stack[upc_cmode_stack_in_use++] = upc_cmode;
+}
+
+/* Called at the end of every compound statement.
+ Sets the current consistency mode to the previously saved value. */
+
+void
+pop_upc_consistency_mode (void)
+{
+ if (upc_cmode_stack_in_use <= 0)
+ abort ();
+ upc_cmode = upc_cmode_stack[--upc_cmode_stack_in_use];
+}
+
+static int pragma_pupc_on;
+static void init_pragma_pupc (void);
+static void handle_pragma_pupc (cpp_reader *);
+
+/* Pragma pupc defaults to being on */
+static void
+init_pragma_pupc (void)
+{
+ pragma_pupc_on = 1;
+}
+
+int
+get_upc_pupc_mode (void)
+{
+ return pragma_pupc_on;
+}
+
+int
+disable_pupc_mode (void)
+{
+ int old_pupc = pragma_pupc_on;
+ pragma_pupc_on = 0;
+ return old_pupc;
+}
+
+void
+set_pupc_mode (int new_pupc)
+{
+ pragma_pupc_on = new_pupc;
+}
+
+/*
+ * #pragma pupc on
+ * #pragma pupc off
+ */
+static void
+handle_pragma_pupc (cpp_reader *dummy ATTRIBUTE_UNUSED)
+{
+ tree x;
+ enum cpp_ttype t;
+
+ t = pragma_lex(&x);
+ if (t == CPP_NAME) {
+ const char *op = IDENTIFIER_POINTER (x);
+ if (!strcmp (op, "on"))
+ pragma_pupc_on = 1;
+ else if (!strcmp (op, "off"))
+ pragma_pupc_on = 0;
+ else
+ GCC_BAD2 ("unknown action '%s' for '#pragma pupc' - ignored", op);
+ }
+
+ t = pragma_lex (&x);
+ if (t != CPP_EOF)
+ warning (OPT_Wpragmas, "junk at end of #pragma pupc");
+}
+
/* Hook from the front ends to apply the results of one of the preceding
pragmas that rename variables. */
@@ -1542,6 +1774,14 @@ init_pragma (void)
c_register_pragma_with_expansion (0, "message", handle_pragma_message);
+ if (flag_upc)
+ {
+ c_register_pragma (0, "upc", handle_pragma_upc);
+ init_pragma_upc ();
+ c_register_pragma (0, "pupc", handle_pragma_pupc);
+ init_pragma_pupc ();
+ }
+
#ifdef REGISTER_TARGET_PRAGMAS
REGISTER_TARGET_PRAGMAS ();
#endif
===================================================================
@@ -236,6 +236,15 @@ extern void add_to_renaming_pragma_list
extern enum cpp_ttype pragma_lex (tree *, location_t *loc = NULL);
+/* UPC-related pragma handling. */
+extern void deny_pragma_upc (void);
+extern int get_upc_consistency_mode (void);
+extern void permit_pragma_upc (void);
+extern void pop_upc_consistency_mode (void);
+extern int pragma_upc_permitted_p (void);
+extern void push_upc_consistency_mode (void);
+extern void set_upc_consistency_mode (int);
+
/* Flags for use with c_lex_with_flags. The values here were picked
so that 0 means to translate and join strings. */
#define C_LEX_STRING_NO_TRANSLATE 1 /* Do not lex strings into
===================================================================
@@ -186,6 +186,13 @@ pp_c_cv_qualifiers (c_pretty_printer *pp
if (qualifiers & TYPE_QUAL_RESTRICT)
pp_c_ws_string (pp, (flag_isoc99 && !c_dialect_cxx ()
? "restrict" : "__restrict__"));
+ if (qualifiers & TYPE_QUAL_RELAXED)
+ pp_c_ws_string (pp, "relaxed");
+ if (qualifiers & TYPE_QUAL_STRICT)
+ pp_c_ws_string (pp, "strict");
+ if (qualifiers & TYPE_QUAL_SHARED)
+ pp_c_ws_string (pp, "shared");
+
}
/* Pretty-print T using the type-cast notation '( type-name )'. */
===================================================================
@@ -29,6 +29,7 @@ along with GCC; see the file COPYING3.
#include "target.h"
#include "c-tree.h"
#include "convert.h"
+#include "c-upc.h"
#include "langhooks.h"
#include "ubsan.h"
@@ -87,6 +88,11 @@ convert (tree type, tree expr)
STRIP_TYPE_NOPS (e);
+ /* Drop 'shared' qualifier when considering conversions
+ of expression values. */
+ if (SHARED_TYPE_P (type))
+ type = build_unshared_type(type);
+
if (TYPE_MAIN_VARIANT (type) == TYPE_MAIN_VARIANT (TREE_TYPE (expr))
&& (TREE_CODE (TREE_TYPE (expr)) != COMPLEX_TYPE
|| TREE_CODE (e) == COMPLEX_EXPR))
===================================================================
@@ -38,6 +38,8 @@ along with GCC; see the file COPYING3.
#include "stor-layout.h"
#include "varasm.h"
#include "attribs.h"
+#include "c-upc.h"
+#include "c-upc-low.h"
#include "toplev.h"
#include "debug.h"
#include "c-family/c-objc.h"
@@ -635,6 +637,8 @@ c_build_pointer_type (tree to_type)
: TYPE_ADDR_SPACE (to_type);
machine_mode pointer_mode;
+ if (SHARED_TYPE_P (to_type))
+ return build_pointer_type (to_type);
if (as != ADDR_SPACE_GENERIC || c_default_pointer_mode == VOIDmode)
pointer_mode = targetm.addr_space.pointer_mode (as);
else
@@ -2397,6 +2401,13 @@ merge_decls (tree newdecl, tree olddecl,
if (TREE_THIS_VOLATILE (newdecl))
TREE_THIS_VOLATILE (olddecl) = 1;
+ if (TREE_SHARED (newdecl))
+ {
+ TREE_SHARED (olddecl) = 1;
+ if (TREE_CODE (newdecl) == VAR_DECL)
+ TREE_THIS_VOLATILE (olddecl) = 1;
+ }
+
/* Merge deprecatedness. */
if (TREE_DEPRECATED (newdecl))
TREE_DEPRECATED (olddecl) = 1;
@@ -3089,6 +3100,8 @@ pushdecl_top_level (tree x)
static void
implicit_decl_warning (location_t loc, tree id, tree olddecl)
{
+ if (upc_diagnose_deprecated_stmt (input_location, id))
+ return;
if (warn_implicit_function_declaration)
{
bool warned;
@@ -3419,6 +3432,8 @@ undeclared_variable (location_t loc, tre
}
else
{
+ if (upc_diagnose_deprecated_stmt (loc, id))
+ return;
if (!objc_diagnose_private_ivar (id))
error_at (loc, "%qE undeclared (first use in this function)", id);
if (!already)
@@ -4252,6 +4267,9 @@ quals_from_declspecs (const struct c_dec
| (specs->volatile_p ? TYPE_QUAL_VOLATILE : 0)
| (specs->restrict_p ? TYPE_QUAL_RESTRICT : 0)
| (specs->atomic_p ? TYPE_QUAL_ATOMIC : 0)
+ | (specs->shared_p ? TYPE_QUAL_SHARED : 0)
+ | (specs->strict_p ? TYPE_QUAL_STRICT : 0)
+ | (specs->relaxed_p ? TYPE_QUAL_RELAXED : 0)
| (ENCODE_QUAL_ADDR_SPACE (specs->address_space)));
gcc_assert (!specs->type
&& !specs->decl_attr
@@ -4797,7 +4815,24 @@ finish_decl (tree decl, location_t init_
constant_expression_warning (DECL_SIZE (decl));
else
{
- error ("storage size of %q+D isn%'t constant", decl);
+ if (SHARED_TYPE_P (TREE_TYPE (decl)))
+ {
+ gcc_assert (!flag_upc_threads);
+ if (TYPE_HAS_THREADS_FACTOR (TREE_TYPE (decl)))
+ error ("in the UPC dynamic translation environment, "
+ "THREADS may not appear in declarations "
+ "of shared arrays with indefinite block size; "
+ "the storage size of %q+D cannot be calculated",
+ decl);
+ else
+ error ("in the UPC dynamic translation environment, "
+ "THREADS must appear exactly once in "
+ "declarations of shared arrays; "
+ "the storage size of %q+D cannot be calculated",
+ decl);
+ }
+ else
+ error ("storage size of %q+D isn%'t constant", decl);
TREE_TYPE (decl) = error_mark_node;
}
}
@@ -4836,6 +4871,10 @@ finish_decl (tree decl, location_t init_
if (c_dialect_objc ())
objc_check_decl (decl);
+ /* Give UPC a chance to check the declaration. */
+ if (flag_upc)
+ upc_check_decl (decl);
+
if (asmspec)
{
/* If this is not a static variable, issue a warning.
@@ -5338,6 +5377,9 @@ grokdeclarator (const struct c_declarato
int restrictp;
int volatilep;
int atomicp;
+ int sharedp;
+ int strictp;
+ int relaxedp;
int type_quals = TYPE_UNQUALIFIED;
tree name = NULL_TREE;
bool funcdef_flag = false;
@@ -5349,6 +5391,10 @@ grokdeclarator (const struct c_declarato
int array_parm_static = 0;
bool array_parm_vla_unspec_p = false;
tree returned_attrs = NULL_TREE;
+ int upc_threads_ref = 0; /* for static declarations of shared arrays */
+ tree upc_layout_qualifier;
+ tree upc_elem_block_factor;
+ tree upc_block_factor = NULL;
bool bitfield = width != NULL;
tree element_type;
struct c_arg_info *arg_info = 0;
@@ -5448,6 +5494,8 @@ grokdeclarator (const struct c_declarato
size_varies = C_TYPE_VARIABLE_SIZE (type) != 0;
+ upc_threads_ref = TYPE_HAS_THREADS_FACTOR (type);
+
/* Diagnose defaulting to "int". */
if (declspecs->default_int_p && !in_system_header_at (input_location))
@@ -5493,6 +5541,11 @@ grokdeclarator (const struct c_declarato
restrictp = declspecs->restrict_p + TYPE_RESTRICT (element_type);
volatilep = declspecs->volatile_p + TYPE_VOLATILE (element_type);
atomicp = declspecs->atomic_p + TYPE_ATOMIC (element_type);
+ sharedp = declspecs->shared_p + SHARED_TYPE_P (element_type);
+ strictp = declspecs->strict_p + TYPE_STRICT (element_type);
+ relaxedp = declspecs->relaxed_p + TYPE_RELAXED (element_type);
+ upc_elem_block_factor = TYPE_BLOCK_FACTOR (element_type);
+ upc_layout_qualifier = declspecs->upc_layout_qualifier;
as1 = declspecs->address_space;
as2 = TYPE_ADDR_SPACE (element_type);
address_space = ADDR_SPACE_GENERIC_P (as1)? as2 : as1;
@@ -5505,6 +5558,21 @@ grokdeclarator (const struct c_declarato
pedwarn_c90 (loc, OPT_Wpedantic, "duplicate %<volatile%>");
if (atomicp > 1)
pedwarn_c90 (loc, OPT_Wpedantic, "duplicate %<_Atomic%>");
+ if (sharedp > 1)
+ pedwarn_c90 (loc, OPT_Wpedantic, "duplicate %<shared%>");
+ if (strictp > 1)
+ pedwarn_c90 (loc, OPT_Wpedantic, "duplicate %<strict%>");
+ if (relaxedp > 1)
+ pedwarn_c90 (loc, OPT_Wpedantic, "duplicate %<relaxed%>");
+ if (strictp && relaxedp)
+ error_at (loc, "UPC shared variable %qE is declared "
+ "both strict and relaxed", name);
+ if (strictp && !sharedp)
+ error_at (loc, "%qE is declared with UPC strict qualifier "
+ "but not shared", name);
+ if (relaxedp && !sharedp)
+ error_at (loc, "%qE is declared with UPC relaxed qualifier "
+ "but not shared", name);
if (!ADDR_SPACE_GENERIC_P (as1) && !ADDR_SPACE_GENERIC_P (as2) && as1 != as2)
error_at (loc, "conflicting named address spaces (%s vs %s)",
@@ -5518,6 +5586,9 @@ grokdeclarator (const struct c_declarato
| (restrictp ? TYPE_QUAL_RESTRICT : 0)
| (volatilep ? TYPE_QUAL_VOLATILE : 0)
| (atomicp ? TYPE_QUAL_ATOMIC : 0)
+ | (sharedp ? TYPE_QUAL_SHARED : 0)
+ | (strictp ? TYPE_QUAL_STRICT : 0)
+ | (relaxedp ? TYPE_QUAL_RELAXED : 0)
| ENCODE_QUAL_ADDR_SPACE (address_space));
/* Applying the _Atomic qualifier to an array type (through the use
@@ -5805,6 +5876,40 @@ grokdeclarator (const struct c_declarato
warn_variable_length_array (name, size);
}
}
+ else if (sharedp && count_upc_threads_refs (size))
+ {
+ /* We have a shared array with a non-constant
+ dimension. If the expression is a factor of
+ THREADS, then we'll need to set the flag
+ in the result type. Otherwise, it is an error. */
+ int n_thread_refs = count_upc_threads_refs (size);
+ if (upc_threads_ref || n_thread_refs > 1)
+ {
+ error_at (loc, "UPC shared array declaration references THREADS "
+ "more than once; the size of %qE "
+ "cannot be calculated", name);
+ size = integer_one_node;
+ }
+ else if (!is_multiple_of_upc_threads (size))
+ {
+ error_at (loc, "UPC shared array dimension is not a simple multiple "
+ "of THREADS; the size of %qE "
+ "cannot be calculated.", name);
+ size = integer_one_node;
+ }
+ else
+ {
+ upc_threads_ref = 1;
+ set_upc_threads_refs_to_one (&size);
+ size = fold (size);
+ if (TREE_CODE (size) != INTEGER_CST)
+ {
+ error_at (loc, "UPC forbids variable-size shared array %qE",
+ name);
+ size = integer_one_node;
+ }
+ }
+ }
else if ((decl_context == NORMAL || decl_context == FIELD)
&& current_scope == file_scope)
{
@@ -5977,6 +6082,18 @@ grokdeclarator (const struct c_declarato
C_TYPE_VARIABLE_SIZE (type) = 1;
}
+ if (upc_threads_ref)
+ {
+ /* We need a unique type copy here for UPC shared
+ array types compiled in a dynamic threads environment
+ that reference THREADS as a multiplier; to avoid
+ setting the "has threads factor" bit in
+ a re-used non- UPC shared array type node. */
+ if (size && TREE_CODE (size) == INTEGER_CST)
+ type = build_distinct_type_copy (TYPE_MAIN_VARIANT (type));
+ TYPE_HAS_THREADS_FACTOR (type) = 1;
+ }
+
/* The GCC extension for zero-length arrays differs from
ISO flexible array members in that sizeof yields
zero. */
@@ -6036,6 +6153,8 @@ grokdeclarator (const struct c_declarato
continue;
size_varies = false;
+ upc_threads_ref = 0;
+ upc_layout_qualifier = 0;
/* Warn about some types functions can't return. */
if (TREE_CODE (type) == FUNCTION_TYPE)
@@ -6083,6 +6202,12 @@ grokdeclarator (const struct c_declarato
if (VOID_TYPE_P (type) && really_funcdef)
pedwarn (loc, 0,
"function definition has qualified void return type");
+ else if (type_quals & TYPE_QUAL_SHARED)
+ {
+ error_at (loc, "function definition has UPC shared qualified return type");
+ type_quals &= ~(TYPE_QUAL_SHARED | TYPE_QUAL_STRICT
+ | TYPE_QUAL_RELAXED);
+ }
else
warning_at (loc, OPT_Wignored_qualifiers,
"type qualifiers ignored on function return type");
@@ -6121,9 +6246,19 @@ grokdeclarator (const struct c_declarato
&& type_quals)
pedwarn (loc, OPT_Wpedantic,
"ISO C forbids qualified function types");
+
+ if (upc_layout_qualifier)
+ upc_block_factor = upc_grok_layout_qualifier (
+ loc, POINTER_TYPE, type,
+ NULL_TREE, upc_layout_qualifier);
+
if (type_quals)
- type = c_build_qualified_type (type, type_quals);
+ type = c_build_qualified_type_1 (type, type_quals,
+ upc_block_factor);
+
size_varies = false;
+ upc_threads_ref = 0;
+ upc_block_factor = 0;
/* When the pointed-to type involves components of variable size,
care must be taken to ensure that the size evaluation code is
@@ -6163,7 +6298,9 @@ grokdeclarator (const struct c_declarato
/* Process type qualifiers (such as const or volatile)
that were given inside the `*'. */
- type_quals = declarator->u.pointer_quals;
+ type_quals = declarator->u.pointer.quals;
+ upc_layout_qualifier = declarator->u.pointer.upc_layout_qual;
+ sharedp = ((type_quals & TYPE_QUAL_SHARED) != 0);
declarator = declarator->declarator;
break;
@@ -6247,6 +6384,14 @@ grokdeclarator (const struct c_declarato
}
}
+ /* Check for UPC's layout qualifier. */
+ if (upc_layout_qualifier || upc_elem_block_factor)
+ {
+ upc_block_factor = upc_grok_layout_qualifier (loc, TREE_CODE (type), type,
+ upc_elem_block_factor, upc_layout_qualifier);
+ upc_layout_qualifier = 0;
+ }
+
/* Reject invalid uses of _Alignas. */
if (declspecs->alignas_p)
{
@@ -6304,7 +6449,8 @@ grokdeclarator (const struct c_declarato
pedwarn (loc, OPT_Wpedantic,
"ISO C forbids qualified function types");
if (type_quals)
- type = c_build_qualified_type (type, type_quals);
+ type = c_build_qualified_type_1 (type, type_quals, upc_block_factor);
+
decl = build_decl (declarator->id_loc,
TYPE_DECL, declarator->u.id, type);
if (declspecs->explicit_signed_p)
@@ -6357,7 +6503,7 @@ grokdeclarator (const struct c_declarato
pedwarn (loc, OPT_Wpedantic,
"ISO C forbids const or volatile function types");
if (type_quals)
- type = c_build_qualified_type (type, type_quals);
+ type = c_build_qualified_type_1 (type, type_quals, upc_block_factor);
return type;
}
@@ -6405,7 +6551,8 @@ grokdeclarator (const struct c_declarato
/* Transfer const-ness of array into that of type pointed to. */
type = TREE_TYPE (type);
if (type_quals)
- type = c_build_qualified_type (type, type_quals);
+ type = c_build_qualified_type_1 (type, type_quals,
+ upc_block_factor);
type = c_build_pointer_type (type);
type_quals = array_ptr_quals;
if (type_quals)
@@ -6435,6 +6582,12 @@ grokdeclarator (const struct c_declarato
type = c_build_pointer_type (type);
type_quals = TYPE_UNQUALIFIED;
}
+ else if (type_quals & TYPE_QUAL_SHARED)
+ {
+ error ("parameter declared with UPC shared qualifier");
+ type_quals &= ~(TYPE_QUAL_SHARED | TYPE_QUAL_STRICT
+ | TYPE_QUAL_RELAXED);
+ }
else if (type_quals)
type = c_build_qualified_type (type, type_quals);
@@ -6496,6 +6649,13 @@ grokdeclarator (const struct c_declarato
TYPE_DOMAIN (type) = build_range_type (sizetype, size_zero_node,
NULL_TREE);
}
+ else if (type_quals & TYPE_QUAL_SHARED)
+ {
+ error_at (loc, "field %qE declared with UPC shared qualifier",
+ name);
+ type_quals &= ~(TYPE_QUAL_SHARED | TYPE_QUAL_STRICT
+ | TYPE_QUAL_RELAXED);
+ }
type = c_build_qualified_type (type, type_quals);
decl = build_decl (declarator->id_loc,
FIELD_DECL, declarator->u.id, type);
@@ -6608,7 +6768,16 @@ grokdeclarator (const struct c_declarato
/* An uninitialized decl with `extern' is a reference. */
int extern_ref = !initialized && storage_class == csc_extern;
- type = c_build_qualified_type (type, type_quals);
+ if ((type_quals & TYPE_QUAL_SHARED)
+ && !extern_ref
+ && !((current_scope == file_scope)
+ || (storage_class == csc_static)))
+ {
+ error_at (loc, "UPC does not support shared auto variables");
+ type = error_mark_node;
+ }
+
+ type = c_build_qualified_type_1 (type, type_quals, upc_block_factor);
/* C99 6.2.2p7: It is invalid (compile-time undefined
behavior) to create an 'extern' declaration for a
@@ -6657,6 +6826,10 @@ grokdeclarator (const struct c_declarato
else
{
TREE_STATIC (decl) = (storage_class == csc_static);
+ /* UPC's 'shared' attribute implies that the storage
+ is 'static' to the extent it is stored in memory. */
+ if (type_quals & TYPE_QUAL_SHARED)
+ TREE_STATIC (decl) = 1;
TREE_PUBLIC (decl) = extern_ref;
}
@@ -6731,6 +6904,13 @@ grokdeclarator (const struct c_declarato
"questionable in C++"),
decl);
+ /* Shared variables are given their own link section on
+ most target platforms, and if compiling in pthreads mode
+ regular local file scope variables are made thread local. */
+ if ((TREE_CODE(decl) == VAR_DECL)
+ && !threadp && (TREE_SHARED (decl) || flag_upc_pthreads))
+ upc_set_decl_section (decl);
+
return decl;
}
}
@@ -9061,6 +9241,8 @@ finish_function (void)
if (!decl_function_context (fndecl))
{
invoke_plugin_callbacks (PLUGIN_PRE_GENERICIZE, fndecl);
+ if (flag_upc)
+ upc_genericize (fndecl);
c_genericize (fndecl);
/* ??? Objc emits functions after finalizing the compilation unit.
@@ -9390,18 +9572,21 @@ make_pointer_declarator (struct c_declsp
{
tree attrs;
int quals = 0;
+ tree upc_layout_qual = 0;
struct c_declarator *itarget = target;
struct c_declarator *ret = XOBNEW (&parser_obstack, struct c_declarator);
if (type_quals_attrs)
{
attrs = type_quals_attrs->attrs;
quals = quals_from_declspecs (type_quals_attrs);
+ upc_layout_qual = type_quals_attrs->upc_layout_qualifier;
if (attrs != NULL_TREE)
itarget = build_attrs_declarator (attrs, target);
}
ret->kind = cdk_pointer;
ret->declarator = itarget;
- ret->u.pointer_quals = quals;
+ ret->u.pointer.quals = quals;
+ ret->u.pointer.upc_layout_qual = upc_layout_qual;
return ret;
}
@@ -9417,6 +9602,7 @@ build_null_declspecs (void)
ret->expr = 0;
ret->decl_attr = 0;
ret->attrs = 0;
+ ret->upc_layout_qualifier = 0;
ret->align_log = -1;
ret->typespec_word = cts_none;
ret->storage_class = csc_none;
@@ -9442,6 +9628,9 @@ build_null_declspecs (void)
ret->volatile_p = false;
ret->atomic_p = false;
ret->restrict_p = false;
+ ret->shared_p = false;
+ ret->strict_p = false;
+ ret->relaxed_p = false;
ret->saturating_p = false;
ret->alignas_p = false;
ret->address_space = ADDR_SPACE_GENERIC;
@@ -9482,6 +9671,23 @@ declspecs_add_qual (source_location loc,
bool dupe = false;
specs->non_sc_seen_p = true;
specs->declspecs_seen_p = true;
+
+ /* A UPC layout qualifier is encoded as an ARRAY_REF,
+ further, it implies the presence of the 'shared' keyword. */
+ if (TREE_CODE (qual) == ARRAY_REF)
+ {
+ if (specs->upc_layout_qualifier)
+ {
+ error ("two or more layout qualifiers specified");
+ return specs;
+ }
+ else
+ {
+ specs->upc_layout_qualifier = qual;
+ qual = ridpointers[RID_SHARED];
+ }
+ }
+
gcc_assert (TREE_CODE (qual) == IDENTIFIER_NODE
&& C_IS_RESERVED_WORD (qual));
i = C_RID_CODE (qual);
@@ -9506,6 +9712,18 @@ declspecs_add_qual (source_location loc,
dupe = specs->atomic_p;
specs->atomic_p = true;
break;
+ case RID_SHARED:
+ dupe = specs->shared_p;
+ specs->shared_p = true;
+ break;
+ case RID_STRICT:
+ dupe = specs->strict_p;
+ specs->strict_p = true;
+ break;
+ case RID_RELAXED:
+ dupe = specs->relaxed_p;
+ specs->relaxed_p = true;
+ break;
default:
gcc_unreachable ();
}
===================================================================
@@ -21,11 +21,14 @@ along with GCC; see the file COPYING3.
#include "system.h"
#include "coretypes.h"
#include "c-tree.h"
+#include "options.h"
#include "intl.h"
#include "c-family/c-pretty-print.h"
#include "tree-pretty-print.h"
#include "langhooks.h"
#include "c-objc-common.h"
+#include "c-upc-lang.h"
+#include "c-upc.h"
#include <new> // For placement new.
@@ -59,7 +62,14 @@ c_objc_common_init (void)
{
c_init_decl_processing ();
- return c_common_init ();
+ if (c_common_init () == false)
+ return false;
+
+ if (flag_upc)
+ upc_lang_init ();
+
+ return true;
+
}
/* Called during diagnostic message formatting process to print a
@@ -212,10 +222,87 @@ c_initialize_diagnostics (diagnostic_con
diagnostic_format_decoder (context) = &c_tree_printer;
}
+/* Check for the possible need to convert UPC-specific types. */
+
+static int
+upc_types_compatible_p (tree x, tree y)
+{
+ if (POINTER_TYPE_P (x) && POINTER_TYPE_P (y))
+ {
+ const tree ttx = TREE_TYPE (x);
+ const tree tty = TREE_TYPE (y);
+ if (SHARED_TYPE_P (ttx) && SHARED_TYPE_P (tty))
+ {
+ tree bx, by, sx, sy;
+ int x_has_zero_phase, y_has_zero_phase;
+ int result;
+ /* If both types are generic UPC pointers-to-shared,
+ then they're compatible. */
+ if (VOID_TYPE_P (ttx) && VOID_TYPE_P (tty))
+ return 1;
+ /* Intermediate conversions to (shared void *) (defined
+ to be a "generic pointer-to-shared" in the UPC
+ specification) cannot always be optimized away.
+ For example,
+ p1 = (shared void *) p2;
+ preserves the phase of p2, when assigning to p1.
+ We need to be conservative, and not consider conversions
+ involving a generic UPC pointer-to-shared value to be
+ equivalent. */
+ if (VOID_TYPE_P (ttx) != VOID_TYPE_P (tty))
+ return 0;
+ bx = get_block_factor (ttx);
+ by = get_block_factor (tty);
+ sx = TYPE_SIZE (ttx);
+ sy = TYPE_SIZE (tty);
+ x_has_zero_phase = (integer_zerop (bx) || integer_onep (bx));
+ y_has_zero_phase = (integer_zerop (by) || integer_onep (by));
+ /* Normalize type size so that 0 => NULL. */
+ if (sx && integer_zerop (sx))
+ sx = NULL_TREE;
+ if (sy && integer_zerop (sy))
+ sy = NULL_TREE;
+ /* If the target types have the same UPC block size
+ (or they both have a phase value of zero)
+ and the same size and the target types are
+ otherwise compatible, then the pointer-to-shared
+ types are compatible. */
+ result = (tree_int_cst_equal (bx, by)
+ || (x_has_zero_phase && y_has_zero_phase))
+ && tree_int_cst_equal (sx, sy);
+ return result;
+ }
+ /* If one operand has a UPC shared type,
+ and the other operand's type is not a UPC shared type,
+ then they aren't equivalent. */
+ else if (SHARED_TYPE_P (ttx) != SHARED_TYPE_P (tty))
+ return 0;
+ }
+ else if (SHARED_TYPE_P (x) || SHARED_TYPE_P (y))
+ {
+ /* In UPC, blocking factors can be applied to
+ non-pointer objects/types. They're compatible
+ if the block sizes are equal. */
+ const tree bx = get_block_factor (x);
+ const tree by = get_block_factor (y);
+ return tree_int_cst_equal (bx, by)
+ && c_types_compatible_p (TYPE_MAIN_VARIANT (x),
+ TYPE_MAIN_VARIANT (y));
+ }
+ /* Otherwise, they're not compatible.
+ comptypes() should be called before this function
+ in order to implement a full "C" compatibility check. */
+ return 0;
+}
+
int
c_types_compatible_p (tree x, tree y)
{
- return comptypes (TYPE_MAIN_VARIANT (x), TYPE_MAIN_VARIANT (y));
+ int result;
+ result = comptypes (TYPE_MAIN_VARIANT (x), TYPE_MAIN_VARIANT (y));
+ if (!result && flag_upc)
+ result = upc_types_compatible_p (x, y);
+ return result;
}
/* Determine if the type is a vla type for the backend. */
===================================================================
@@ -51,6 +51,9 @@ along with GCC; see the file COPYING3.
#include "c-family/c-pragma.h"
#include "c-lang.h"
#include "c-family/c-objc.h"
+#include "c-upc.h"
+#include "c-upc-gasp.h"
+#include "c-upc-pts-ops.h"
#include "plugin.h"
#include "omp-low.h"
#include "builtins.h"
@@ -106,6 +109,9 @@ c_parse_init (void)
if (!c_dialect_objc ())
mask |= D_OBJC | D_CXX_OBJC;
+ if (!flag_upc)
+ mask |= D_UPC;
+
ridpointers = ggc_cleared_vec_alloc<tree> ((int) RID_MAX);
for (i = 0; i < num_c_common_reswords; i++)
{
@@ -545,6 +551,11 @@ c_token_starts_typename (c_token *token)
case RID_SAT:
case RID_AUTO_TYPE:
return true;
+ /* UPC qualifiers */
+ case RID_SHARED:
+ case RID_STRICT:
+ case RID_RELAXED:
+ return true;
default:
if (token->keyword >= RID_FIRST_INT_N
&& token->keyword < RID_FIRST_INT_N + NUM_INT_N_ENTS
@@ -626,6 +637,11 @@ c_token_is_qualifier (c_token *token)
case RID_ATTRIBUTE:
case RID_ATOMIC:
return true;
+ case RID_SHARED:
+ case RID_STRICT:
+ case RID_RELAXED:
+ /* UPC qualifiers */
+ return true;
default:
return false;
}
@@ -707,6 +723,11 @@ c_token_starts_declspecs (c_token *token
case RID_ATOMIC:
case RID_AUTO_TYPE:
return true;
+ /* UPC qualifiers */
+ case RID_SHARED:
+ case RID_STRICT:
+ case RID_RELAXED:
+ return true;
default:
if (token->keyword >= RID_FIRST_INT_N
&& token->keyword < RID_FIRST_INT_N + NUM_INT_N_ENTS
@@ -1315,6 +1336,14 @@ static tree c_parser_array_notation (loc
static tree c_parser_cilk_clause_vectorlength (c_parser *, tree, bool);
static void c_parser_cilk_grainsize (c_parser *);
+/* These UPC parser functions are only ever called when
+ compiling UPC. */
+static void c_parser_upc_forall_statement (c_parser *);
+static void c_parser_upc_sync_statement (c_parser *, int);
+static void c_parser_upc_shared_qual (source_location,
+ c_parser *,
+ struct c_declspecs *);
+
/* Parse a translation unit (C90 6.7, C99 6.9).
translation-unit:
@@ -2512,6 +2541,17 @@ c_parser_declspecs (c_parser *parser, st
declspecs_add_qual (loc, specs, c_parser_peek_token (parser)->value);
c_parser_consume_token (parser);
break;
+ /* UPC qualifiers */
+ case RID_SHARED:
+ attrs_ok = true;
+ c_parser_upc_shared_qual (loc, parser, specs);
+ break;
+ case RID_STRICT:
+ case RID_RELAXED:
+ attrs_ok = true;
+ declspecs_add_qual (loc, specs, c_parser_peek_token (parser)->value);
+ c_parser_consume_token (parser);
+ break;
case RID_ATTRIBUTE:
if (!attrs_ok)
goto out;
@@ -4662,6 +4702,19 @@ c_parser_compound_statement_nostart (c_p
c_parser_consume_token (parser);
return;
}
+ /* Process all #pragma's just after the opening brace. This
+ handles #pragma upc, which can only appear just after
+ the opening brace, when it appears within a function body. */
+ push_upc_consistency_mode ();
+ permit_pragma_upc ();
+ while (c_parser_next_token_is (parser, CPP_PRAGMA))
+ {
+ location_t loc ATTRIBUTE_UNUSED = c_parser_peek_token (parser)->location;
+ if (c_parser_pragma (parser, pragma_compound))
+ last_label = false, last_stmt = true;
+ parser->error = false;
+ }
+ deny_pragma_upc ();
while (c_parser_next_token_is_not (parser, CPP_CLOSE_BRACE))
{
location_t loc = c_parser_peek_token (parser)->location;
@@ -4768,6 +4821,7 @@ c_parser_compound_statement_nostart (c_p
if (last_label)
error_at (label_loc, "label at end of compound statement");
c_parser_consume_token (parser);
+ pop_upc_consistency_mode ();
/* Restore the value we started with. */
mark_valid_location_for_stdc_pragma (save_valid_for_pragma);
}
@@ -5154,6 +5208,22 @@ c_parser_statement_after_labels (c_parse
gcc_assert (c_dialect_objc ());
c_parser_objc_synchronized_statement (parser);
break;
+ case RID_UPC_FORALL:
+ gcc_assert (flag_upc);
+ c_parser_upc_forall_statement (parser);
+ break;
+ case RID_UPC_NOTIFY:
+ gcc_assert (flag_upc);
+ c_parser_upc_sync_statement (parser, UPC_SYNC_NOTIFY_OP);
+ goto expect_semicolon;
+ case RID_UPC_WAIT:
+ gcc_assert (flag_upc);
+ c_parser_upc_sync_statement (parser, UPC_SYNC_WAIT_OP);
+ goto expect_semicolon;
+ case RID_UPC_BARRIER:
+ gcc_assert (flag_upc);
+ c_parser_upc_sync_statement (parser, UPC_SYNC_BARRIER_OP);
+ goto expect_semicolon;
default:
goto expr_stmt;
}
@@ -6744,6 +6814,11 @@ c_parser_unary_expression (c_parser *par
{
case RID_SIZEOF:
return c_parser_sizeof_expression (parser);
+ case RID_UPC_BLOCKSIZEOF:
+ case RID_UPC_ELEMSIZEOF:
+ case RID_UPC_LOCALSIZEOF:
+ gcc_assert (flag_upc);
+ return c_parser_sizeof_expression (parser);
case RID_ALIGNOF:
return c_parser_alignof_expression (parser);
case RID_EXTENSION:
@@ -6776,6 +6851,147 @@ c_parser_unary_expression (c_parser *par
}
}
+/* Return the result of upc_blocksizeof applied to EXPR. */
+
+static
+struct c_expr
+upc_blocksizeof_expr (location_t loc, struct c_expr expr)
+{
+ struct c_expr ret;
+ ret.original_code = ERROR_MARK;
+ ret.original_type = NULL_TREE;
+ if (expr.value == error_mark_node)
+ {
+ ret.value = error_mark_node;
+ pop_maybe_used (false);
+ }
+ else
+ {
+ ret.value = upc_blocksizeof (loc, TREE_TYPE (expr.value));
+ pop_maybe_used (C_TYPE_VARIABLE_SIZE (TREE_TYPE (expr.value)));
+ }
+ return ret;
+}
+
+/* Return the result of upc_blocksizeof applied to T, a structure
+ for the type name passed to sizeof (rather than the type itself). */
+
+static
+struct c_expr
+upc_blocksizeof_type (location_t loc, struct c_type_name *t)
+{
+ tree type;
+ struct c_expr ret;
+ ret.original_code = ERROR_MARK;
+ ret.original_type = NULL_TREE;
+ type = groktypename (t, NULL, NULL);
+ if (type == error_mark_node)
+ {
+ ret.value = error_mark_node;
+ pop_maybe_used (false);
+ }
+ else
+ {
+ ret.value = upc_blocksizeof (loc, type);
+ pop_maybe_used (C_TYPE_VARIABLE_SIZE (type));
+ }
+ return ret;
+}
+
+/* Return the result of upc_elemsizeof applied to EXPR. */
+
+static
+struct c_expr
+upc_elemsizeof_expr (location_t loc, struct c_expr expr)
+{
+ struct c_expr ret;
+ ret.original_code = ERROR_MARK;
+ ret.original_type = NULL_TREE;
+ if (expr.value == error_mark_node)
+ {
+ ret.value = error_mark_node;
+ pop_maybe_used (false);
+ }
+ else
+ {
+ ret.value = upc_elemsizeof (loc, TREE_TYPE (expr.value));
+ pop_maybe_used (C_TYPE_VARIABLE_SIZE (TREE_TYPE (expr.value)));
+ }
+ return ret;
+}
+
+/* Return the result of upc_elemsizeof applied to T, a structure
+ for the type name passed to sizeof (rather than the type itself). */
+
+static
+struct c_expr
+upc_elemsizeof_type (location_t loc, struct c_type_name *t)
+{
+ tree type;
+ struct c_expr ret;
+ ret.original_code = ERROR_MARK;
+ ret.original_type = NULL_TREE;
+ type = groktypename (t, NULL, NULL);
+ if (type == error_mark_node)
+ {
+ ret.value = error_mark_node;
+ pop_maybe_used (false);
+ }
+ else
+ {
+ ret.value = upc_elemsizeof (loc, type);
+ pop_maybe_used (C_TYPE_VARIABLE_SIZE (type));
+ }
+ return ret;
+}
+
+/* Return the result of upc_localsizeof applied to EXPR. */
+
+static
+struct c_expr
+upc_localsizeof_expr (location_t loc, struct c_expr expr)
+{
+ struct c_expr ret;
+ ret.original_code = ERROR_MARK;
+ ret.original_type = NULL_TREE;
+ if (expr.value == error_mark_node)
+ {
+ ret.value = error_mark_node;
+ pop_maybe_used (false);
+ }
+ else
+ {
+ ret.value = upc_localsizeof (loc, TREE_TYPE (expr.value));
+ pop_maybe_used (C_TYPE_VARIABLE_SIZE (TREE_TYPE (expr.value)));
+ }
+ return ret;
+}
+
+/* Return the result of upc_localsizeof applied to T, a structure
+ for the type name passed to sizeof (rather than the type itself). */
+
+static
+struct c_expr
+upc_localsizeof_type (location_t loc, struct c_type_name *t)
+{
+ tree type;
+ struct c_expr ret;
+ ret.original_code = ERROR_MARK;
+ ret.original_type = NULL_TREE;
+ type = groktypename (t, NULL, NULL);
+ if (type == error_mark_node)
+ {
+ ret.value = error_mark_node;
+ pop_maybe_used (false);
+ }
+ else
+ {
+ ret.value = upc_localsizeof (loc, type);
+ pop_maybe_used (C_TYPE_VARIABLE_SIZE (type));
+ }
+ return ret;
+}
+
/* Parse a sizeof expression. */
static struct c_expr
@@ -6784,7 +7000,7 @@ c_parser_sizeof_expression (c_parser *pa
struct c_expr expr;
struct c_expr result;
location_t expr_loc;
- gcc_assert (c_parser_next_token_is_keyword (parser, RID_SIZEOF));
+ enum rid keyword = c_parser_peek_token (parser)->keyword;
location_t start;
location_t finish = UNKNOWN_LOCATION;
@@ -6826,7 +7042,23 @@ c_parser_sizeof_expression (c_parser *pa
/* sizeof ( type-name ). */
c_inhibit_evaluation_warnings--;
in_sizeof--;
- result = c_expr_sizeof_type (expr_loc, type_name);
+ /* Handle sizeof (type) and upc_*_sizeof (type) operations. */
+ switch (keyword)
+ {
+ case RID_SIZEOF:
+ result = c_expr_sizeof_type (expr_loc, type_name);
+ break;
+ case RID_UPC_BLOCKSIZEOF:
+ result = upc_blocksizeof_type (expr_loc, type_name);
+ break;
+ case RID_UPC_ELEMSIZEOF:
+ result = upc_elemsizeof_type (expr_loc, type_name);
+ break;
+ case RID_UPC_LOCALSIZEOF:
+ result = upc_localsizeof_type (expr_loc, type_name);
+ break;
+ default: gcc_unreachable ();
+ }
}
else
{
@@ -6840,7 +7072,23 @@ c_parser_sizeof_expression (c_parser *pa
if (TREE_CODE (expr.value) == COMPONENT_REF
&& DECL_C_BIT_FIELD (TREE_OPERAND (expr.value, 1)))
error_at (expr_loc, "%<sizeof%> applied to a bit-field");
- result = c_expr_sizeof_expr (expr_loc, expr);
+ /* Handle sizeof (expr) and upc_*_sizeof (expr) operations. */
+ switch (keyword)
+ {
+ case RID_SIZEOF:
+ result = c_expr_sizeof_expr (expr_loc, expr);
+ break;
+ case RID_UPC_BLOCKSIZEOF:
+ result = upc_blocksizeof_expr (expr_loc, expr);
+ break;
+ case RID_UPC_ELEMSIZEOF:
+ result = upc_elemsizeof_expr (expr_loc, expr);
+ break;
+ case RID_UPC_LOCALSIZEOF:
+ result = upc_localsizeof_expr (expr_loc, expr);
+ break;
+ default: gcc_unreachable ();
+ }
}
if (finish != UNKNOWN_LOCATION)
set_c_expr_source_range (&result, start, finish);
@@ -9832,6 +10080,316 @@ c_parser_objc_at_dynamic_declaration (c_
objc_add_dynamic_declaration (loc, list);
}
+/* Parse UPC shared qualifier
+
+ shared-type-qualifier: shared layout-qualifier-opt
+ layout-qualifier: [ constant-expression-opt ] | [ * ]
+
+*/
+static void
+c_parser_upc_shared_qual (source_location loc,
+ c_parser *parser,
+ struct c_declspecs *specs)
+{
+ tree array_qual, arg1;
+
+ /* consume "shared" part */
+ c_parser_consume_token (parser);
+
+ /* check for shared array layout specifier */
+ if (!c_parser_next_token_is (parser, CPP_OPEN_SQUARE))
+ {
+ declspecs_add_qual (loc, specs, ridpointers[RID_SHARED]);
+ return;
+ }
+ c_parser_consume_token (parser);
+ if (c_parser_next_token_is (parser, CPP_CLOSE_SQUARE))
+ {
+ /* [] layout specifier */
+ arg1 = size_zero_node;
+ }
+ else if (c_parser_next_token_is (parser, CPP_MULT))
+ {
+ /* [*] layout specifier */
+ arg1 = build1 (INDIRECT_REF, NULL_TREE, NULL_TREE);
+ c_parser_consume_token (parser);
+ }
+ else
+ {
+ /* [ expression ] layout specifier */
+ arg1 = c_parser_expression (parser).value;
+ }
+ array_qual = build4 (ARRAY_REF, NULL_TREE, NULL_TREE,
+ arg1, NULL_TREE, NULL_TREE);
+ declspecs_add_qual (loc, specs, array_qual);
+
+ if (!c_parser_next_token_is (parser, CPP_CLOSE_SQUARE))
+ {
+ c_parser_error (parser, "expected ]");
+ }
+ c_parser_consume_token (parser);
+}
+
+/* Implement UPC's upc_forall 'affinity' test.
+ If the type of AFFINITY is a UPC pointer-to-shared type,
+ rewrite it into:
+ upc_threadof (AFFINITY) == MYTHREAD
+ If AFFINITY is an integer expression, then
+ rewrite it into:
+ (AFFINITY % THREADS) == MYTHREAD */
+
+static tree
+upc_affinity_test (location_t loc, tree affinity)
+{
+ tree mythread;
+ tree affinity_test;
+
+ gcc_assert (affinity != NULL_TREE);
+
+ if (TREE_CODE (TREE_TYPE (affinity)) == POINTER_TYPE
+ && SHARED_TYPE_P (TREE_TYPE (TREE_TYPE (affinity))))
+ {
+ /* We have a pointer to a UPC shared object and the affinity is
+ determined by the thread component of the address. */
+ const tree pts_rep = build1 (VIEW_CONVERT_EXPR, upc_pts_rep_type_node,
+ save_expr (affinity));
+ affinity = upc_pts_build_threadof (loc, pts_rep);
+ }
+ else if (TREE_CODE (TREE_TYPE (affinity)) == INTEGER_TYPE)
+ {
+ tree n_threads = upc_num_threads ();
+ affinity =
+ build_binary_op (loc, FLOOR_MOD_EXPR, affinity, n_threads, 0);
+ }
+ else
+ {
+ error
+ ("UPC affinity expression is neither an integer nor the address of "
+ "a shared object");
+ return error_mark_node;
+ }
+
+ /* Generate an external reference to the "MYTHREAD" identifier. */
+
+ mythread = lookup_name (get_identifier ("MYTHREAD"));
+ gcc_assert (mythread != NULL_TREE);
+ TREE_USED (mythread) = 1;
+
+ /* AFFINITY now contains an integer value that can be compared to MY_THREAD.
+ Create an expression that tests if AFFINITY is equal to MYTHREAD. */
+
+ if (!c_types_compatible_p (TREE_TYPE (affinity), TREE_TYPE (mythread)))
+ affinity = convert (TREE_TYPE (mythread), affinity);
+ affinity_test = c_objc_common_truthvalue_conversion (loc,
+ build_binary_op (loc, EQ_EXPR,
+ affinity, mythread, 1));
+ /* Remove any MAYBE_CONST_EXPR's. */
+
+ affinity_test = c_fully_fold (affinity_test, false, NULL);
+
+ return affinity_test;
+}
+
+/* Parse a UPC upc_forall statement
+
+ upc_forall-statement:
+ upc_forall ( expression[opt] ; expression[opt] ;
+ expression[opt] ; affinity[opt] ) statement
+ affinity: expression | continue */
+
+static void
+c_parser_upc_forall_statement (c_parser *parser)
+{
+ tree block, cond, incr, save_break, save_cont, body;
+ tree affinity;
+ location_t loc = c_parser_peek_token (parser)->location;
+ location_t affinity_loc = UNKNOWN_LOCATION;
+ const int profile_upc_forall = flag_upc_instrument && get_upc_pupc_mode();
+ gcc_assert (c_parser_next_token_is_keyword (parser, RID_UPC_FORALL));
+ c_parser_consume_token (parser);
+ block = c_begin_compound_stmt (flag_isoc99);
+ if (c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>"))
+ {
+ /* Parse the initialization declaration or expression. */
+ if (c_parser_next_token_is (parser, CPP_SEMICOLON))
+ {
+ c_parser_consume_token (parser);
+ c_finish_expr_stmt (loc, NULL_TREE);
+ }
+ else if (c_parser_next_token_starts_declspecs (parser))
+ {
+ c_parser_declaration_or_fndef (parser, true, true, true,
+ true, true, NULL, vNULL);
+ check_for_loop_decls (loc, true);
+ }
+ else if (c_parser_next_token_is_keyword (parser, RID_EXTENSION))
+ {
+ /* __extension__ can start a declaration, but is also an
+ unary operator that can start an expression. Consume all
+ but the last of a possible series of __extension__ to
+ determine which. */
+ while (c_parser_peek_2nd_token (parser)->type == CPP_KEYWORD
+ && (c_parser_peek_2nd_token (parser)->keyword
+ == RID_EXTENSION))
+ c_parser_consume_token (parser);
+ if (c_token_starts_declspecs (c_parser_peek_2nd_token (parser)))
+ {
+ int ext;
+ ext = disable_extension_diagnostics ();
+ c_parser_consume_token (parser);
+ c_parser_declaration_or_fndef (parser, true, true, true, true, true,
+ NULL, vNULL);
+ restore_extension_diagnostics (ext);
+ check_for_loop_decls (loc, true);
+ }
+ else
+ goto init_expr;
+ }
+ else
+ {
+ init_expr:
+ c_finish_expr_stmt (loc, c_parser_expression (parser).value);
+ c_parser_skip_until_found (parser, CPP_SEMICOLON, "expected %<;%>");
+ }
+ /* Parse the loop condition. */
+ if (c_parser_next_token_is (parser, CPP_SEMICOLON))
+ {
+ c_parser_consume_token (parser);
+ cond = NULL_TREE;
+ }
+ else
+ {
+ cond = c_parser_condition (parser);
+ c_parser_skip_until_found (parser, CPP_SEMICOLON, "expected %<;%>");
+ }
+ /* Parse the increment expression. */
+ if (c_parser_next_token_is (parser, CPP_SEMICOLON))
+ incr = c_process_expr_stmt (loc, NULL_TREE);
+ else
+ incr = c_process_expr_stmt (loc, c_parser_expression (parser).value);
+ c_parser_skip_until_found (parser, CPP_SEMICOLON, "expected %<;%>");
+ /* Parse the UPC affinity expression. */
+ affinity_loc = c_parser_peek_token (parser)->location;
+ if (c_parser_next_token_is (parser, CPP_CLOSE_PAREN))
+ {
+ affinity = NULL_TREE;
+ }
+ else if (c_parser_peek_token (parser)->type == CPP_KEYWORD
+ && c_parser_peek_token (parser)->keyword == RID_CONTINUE)
+ {
+ affinity = NULL_TREE;
+ c_parser_consume_token (parser);
+ }
+ else
+ {
+ affinity = c_parser_expression_conv (parser).value;
+ affinity = c_fully_fold (affinity, false, NULL);
+ }
+ c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>");
+ if (affinity)
+ affinity = upc_affinity_test (affinity_loc, affinity);
+ }
+ else
+ {
+ cond = error_mark_node;
+ incr = error_mark_node;
+ affinity = error_mark_node;
+ }
+ save_break = c_break_label;
+ c_break_label = NULL_TREE;
+ save_cont = c_cont_label;
+ c_cont_label = NULL_TREE;
+ body = c_parser_c99_block_statement (parser);
+ if (profile_upc_forall)
+ {
+ const tree gasp_start = upc_instrument_forall (loc, 1 /* start */);
+ add_stmt (gasp_start);
+ }
+ loc = c_parser_peek_token (parser)->location;
+ if (affinity != NULL_TREE && affinity != error_mark_node)
+ {
+ tree upc_forall_depth = upc_rts_forall_depth_var ();
+ tree inc_depth, depth_gt_one;
+ inc_depth = build_unary_op (loc, PREINCREMENT_EXPR, upc_forall_depth, 0);
+ c_finish_expr_stmt (loc, inc_depth);
+ depth_gt_one = build_binary_op (affinity_loc,
+ GT_EXPR, upc_forall_depth, integer_one_node, 0);
+ depth_gt_one = c_objc_common_truthvalue_conversion (affinity_loc, depth_gt_one);
+ depth_gt_one = c_fully_fold (depth_gt_one, false, NULL);
+ affinity = build_binary_op (affinity_loc, TRUTH_OR_EXPR,
+ depth_gt_one, affinity, 0);
+ body = build3 (COND_EXPR, void_type_node, affinity,
+ body, NULL_TREE);
+ c_finish_loop (loc, cond, incr, body, c_break_label, c_cont_label, true);
+ c_finish_expr_stmt (loc,
+ build_unary_op (loc, PREDECREMENT_EXPR, upc_forall_depth, 0));
+ }
+ else
+ c_finish_loop (loc, cond, incr, body, c_break_label, c_cont_label, true);
+ if (profile_upc_forall)
+ {
+ const tree gasp_end = upc_instrument_forall (loc, 0 /* start */);
+ add_stmt (gasp_end);
+ }
+ add_stmt (c_end_compound_stmt (loc, block, flag_isoc99));
+ c_break_label = save_break;
+ c_cont_label = save_cont;
+}
+
+/* For the given kind of UPC synchronization statement given
+ by SYNC_KIND (UPC_SYNC_NOTIFY_OP, UPC_SYNC_WAIT_OP,
+ or UPC_SYNC_BARRIER_OP), build a UPC_SYNC_STMT tree node,
+ and add it to the current statement list. The value of
+ SYNC_EXPR will be non-null if an expression is present
+ in the UPC statement being compiled.
+
+ If SYNC_EXPR is supplied, it must be assignment compatible
+ with type 'int'. */
+
+static tree
+upc_build_sync_stmt (location_t loc, tree sync_kind, tree sync_expr)
+{
+ if (sync_expr != NULL_TREE)
+ {
+ mark_exp_read (sync_expr);
+ sync_expr = c_cvt_expr_for_assign (loc, integer_type_node, sync_expr);
+ if (sync_expr == error_mark_node)
+ {
+ inform (loc, "UPC synchronization statement expressions "
+ "must be assignment compatible with type `int'");
+ sync_expr = NULL_TREE;
+ }
+ }
+ return add_stmt (build_stmt (loc, UPC_SYNC_STMT, sync_kind, sync_expr));
+}
+
+/* Parse an upc-sync-statement.
+
+ upc_barrier, upc_wait, upc_notify
+*/
+
+static void
+c_parser_upc_sync_statement (c_parser *parser, int sync_kind)
+{
+ location_t loc;
+ tree expr = NULL_TREE;
+ tree stmt;
+ gcc_assert (c_parser_next_token_is_keyword (parser, RID_UPC_BARRIER) ||
+ c_parser_next_token_is_keyword (parser, RID_UPC_NOTIFY) ||
+ c_parser_next_token_is_keyword (parser, RID_UPC_WAIT));
+ loc = c_parser_peek_token (parser)->location;
+ c_parser_consume_token (parser);
+ if (c_parser_peek_token (parser)->type != CPP_SEMICOLON)
+ {
+ loc = c_parser_peek_token (parser)->location;
+ expr = c_parser_expression (parser).value;
+ if (expr == error_mark_node)
+ expr = NULL;
+ }
+ stmt = size_int (sync_kind);
+ (void) upc_build_sync_stmt (loc, stmt, expr);
+}
+
/* Handle pragmas. Some OpenMP pragmas are associated with, and therefore
should be considered, statements. ALLOW_STMT is true if we're within
===================================================================
@@ -279,6 +279,9 @@ struct c_declspecs {
NULL; attributes (possibly from multiple lists) will be passed
separately. */
tree attrs;
+ /* For UPC, this is the blocking factor (layout qualifier).
+ For example, shared [10] int x; */
+ tree upc_layout_qualifier;
/* The base-2 log of the greatest alignment required by an _Alignas
specifier, in bytes, or -1 if no such specifiers with nonzero
alignment. */
@@ -345,6 +348,12 @@ struct c_declspecs {
BOOL_BITFIELD atomic_p : 1;
/* Whether "_Sat" was specified. */
BOOL_BITFIELD saturating_p : 1;
+ /* Whether "shared" was specified. */
+ BOOL_BITFIELD shared_p : 1;
+ /* Whether "strict" was specified. */
+ BOOL_BITFIELD strict_p : 1;
+ /* Whether "relaxed" was specified. */
+ BOOL_BITFIELD relaxed_p : 1;
/* Whether any alignment specifier (even with zero alignment) was
specified. */
BOOL_BITFIELD alignas_p : 1;
@@ -422,7 +431,10 @@ struct c_declarator {
BOOL_BITFIELD vla_unspec_p : 1;
} array;
/* For pointers, the qualifiers on the pointer type. */
- int pointer_quals;
+ struct {
+ int quals;
+ tree upc_layout_qual;
+ } pointer;
/* For attributes. */
tree attrs;
} u;
@@ -662,6 +674,7 @@ extern void c_finish_omp_cancellation_po
extern tree c_finish_omp_clauses (tree, bool, bool = false);
extern tree c_build_va_arg (location_t, tree, tree);
extern tree c_finish_transaction (location_t, tree, int);
+extern tree c_cvt_expr_for_assign (location_t, tree, tree);
extern bool c_tree_equal (tree, tree);
extern tree c_build_function_call_vec (location_t, vec<location_t>, tree,
vec<tree, va_gc> *, vec<tree, va_gc> *);
===================================================================
@@ -43,6 +43,8 @@ along with GCC; see the file COPYING3.
#include "gimplify.h"
#include "tree-inline.h"
#include "omp-low.h"
+#include "c-upc.h"
+#include "c-upc-low.h"
#include "c-family/c-objc.h"
#include "c-family/c-ubsan.h"
#include "cilk.h"
@@ -90,6 +92,7 @@ static tree lookup_field (tree, tree);
static int convert_arguments (location_t, vec<location_t>, tree,
vec<tree, va_gc> *, vec<tree, va_gc> *, tree,
tree);
+static tree c_pointer_int_sum (location_t, enum tree_code, tree, tree);
static tree pointer_diff (location_t, tree, tree);
static tree convert_for_assignment (location_t, location_t, tree, tree, tree,
enum impl_conv, bool, tree, tree, int);
@@ -316,9 +319,12 @@ addr_space_superset (addr_space_t as1, a
static tree
qualify_type (tree type, tree like)
{
+ tree result_type;
addr_space_t as_type = TYPE_ADDR_SPACE (type);
addr_space_t as_like = TYPE_ADDR_SPACE (like);
addr_space_t as_common;
+ int result_quals;
+ tree result_block_factor = NULL_TREE;
/* If the two named address spaces are different, determine the common
superset address space. If there isn't one, raise an error. */
@@ -329,10 +335,31 @@ qualify_type (tree type, tree like)
type, like);
}
- return c_build_qualified_type (type,
- TYPE_QUALS_NO_ADDR_SPACE (type)
- | TYPE_QUALS_NO_ADDR_SPACE_NO_ATOMIC (like)
- | ENCODE_QUAL_ADDR_SPACE (as_common));
+ result_quals = TYPE_QUALS_NO_ADDR_SPACE (type)
+ | TYPE_QUALS_NO_ADDR_SPACE_NO_ATOMIC (like)
+ | ENCODE_QUAL_ADDR_SPACE (as_common);
+
+ if (result_quals & TYPE_QUAL_SHARED)
+ {
+ tree b1 = TYPE_BLOCK_FACTOR (type);
+ tree b2 = TYPE_BLOCK_FACTOR (like);
+ /* We can merge in a new UPC blocking factor only
+ if one/other is NULL. Otherwise, they must match. */
+ if (b1 != b2)
+ {
+ if (b1 && !b2)
+ result_block_factor = b1;
+ else if (!b1 && b2)
+ result_block_factor = b2;
+ else
+ gcc_unreachable ();
+ }
+ }
+
+ result_type = c_build_qualified_type_1 (type, result_quals,
+ result_block_factor);
+
+ return result_type;
}
/* Return true iff the given tree T is a variable length array. */
@@ -623,6 +650,7 @@ common_pointer_type (tree t1, tree t2)
tree pointed_to_2, mv2;
tree target;
unsigned target_quals;
+ tree target_block_factor = NULL_TREE;
addr_space_t as1, as2, as_common;
int quals1, quals2;
@@ -665,6 +693,10 @@ common_pointer_type (tree t1, tree t2)
else
target_quals = (quals1 | quals2);
+ if (target_quals & TYPE_QUAL_SHARED)
+ target_block_factor = TYPE_BLOCK_FACTOR (
+ strip_array_types (pointed_to_1));
+
/* If the two named address spaces are different, determine the common
superset address space. This is guaranteed to exist due to the
assumption that comp_target_type returned non-zero. */
@@ -674,8 +706,9 @@ common_pointer_type (tree t1, tree t2)
gcc_unreachable ();
target_quals |= ENCODE_QUAL_ADDR_SPACE (as_common);
+ t2 = c_build_qualified_type_1 (target, target_quals, target_block_factor);
- t1 = build_pointer_type (c_build_qualified_type (target, target_quals));
+ t1 = build_pointer_type (t2);
return build_type_attribute_variant (t1, attributes);
}
@@ -1083,6 +1116,13 @@ comptypes_internal (const_tree type1, co
if (TYPE_QUALS (t1) != TYPE_QUALS (t2))
return 0;
+ /* If the type is UPC qualified, the block sizes have
+ to be equal. The block sizes are either NULL
+ or are the same integer constant. */
+ if ((TYPE_QUALS (t1) & TYPE_QUAL_SHARED)
+ && (TYPE_BLOCK_FACTOR (t1) != TYPE_BLOCK_FACTOR (t2)))
+ return 0;
+
/* Allow for two different type nodes which have essentially the same
definition. Note that we already checked for equality of the type
qualifiers (just above). */
@@ -2093,6 +2133,10 @@ default_conversion (tree exp)
/* Functions and arrays have been converted during parsing. */
gcc_assert (code != FUNCTION_TYPE);
+
+ if (code == ARRAY_TYPE && SHARED_TYPE_P (type))
+ return array_to_pointer_conversion (input_location, exp);
+
if (code == ARRAY_TYPE)
return exp;
@@ -2347,6 +2391,7 @@ build_component_ref (location_t loc, tre
error_at (loc, "%qT has no member named %qE", type, component);
return error_mark_node;
}
+ gcc_assert (!TREE_SHARED (field));
/* Chain the COMPONENT_REFs if necessary down to the FIELD.
This might be better solved in future the way the C++ front
@@ -2356,6 +2401,8 @@ build_component_ref (location_t loc, tre
do
{
tree subdatum = TREE_VALUE (field);
+ tree sub_elem_type = strip_array_types (TREE_TYPE (subdatum));
+ tree upc_block_factor = NULL_TREE;
int quals;
tree subtype;
bool use_datum_quals;
@@ -2370,10 +2417,15 @@ build_component_ref (location_t loc, tre
use_datum_quals = (datum_lvalue
|| TREE_CODE (TREE_TYPE (subdatum)) != ARRAY_TYPE);
- quals = TYPE_QUALS (strip_array_types (TREE_TYPE (subdatum)));
+ quals = TYPE_QUALS (sub_elem_type);
if (use_datum_quals)
quals |= TYPE_QUALS (TREE_TYPE (datum));
- subtype = c_build_qualified_type (TREE_TYPE (subdatum), quals);
+ /* All references to UPC shared struct components
+ are defined to have an indefinite (zero) blocking factor. */
+ if (quals & TYPE_QUAL_SHARED)
+ upc_block_factor = size_zero_node;
+ subtype = c_build_qualified_type_1 (TREE_TYPE (subdatum),
+ quals, upc_block_factor);
ref = build3 (COMPONENT_REF, subtype, datum, subdatum,
NULL_TREE);
@@ -2384,6 +2436,8 @@ build_component_ref (location_t loc, tre
if (TREE_THIS_VOLATILE (subdatum)
|| (use_datum_quals && TREE_THIS_VOLATILE (datum)))
TREE_THIS_VOLATILE (ref) = 1;
+ if (TREE_SHARED (datum))
+ TREE_SHARED (ref) = 1;
if (TREE_DEPRECATED (subdatum))
warn_deprecated_use (subdatum, NULL_TREE);
@@ -2481,6 +2535,7 @@ build_indirect_ref (location_t loc, tree
TREE_SIDE_EFFECTS (ref)
= TYPE_VOLATILE (t) || TREE_SIDE_EFFECTS (pointer);
TREE_THIS_VOLATILE (ref) = TYPE_VOLATILE (t);
+ TREE_SHARED (ref) = SHARED_TYPE_P (t);
protected_set_expr_location (ref, loc);
return ref;
}
@@ -2569,7 +2624,8 @@ build_array_ref (location_t loc, tree ar
bool non_lvalue
= convert_vector_to_pointer_for_subscript (loc, &array, index);
- if (TREE_CODE (TREE_TYPE (array)) == ARRAY_TYPE)
+ if (TREE_CODE (TREE_TYPE (array)) == ARRAY_TYPE
+ && !SHARED_TYPE_P (TREE_TYPE (array)))
{
tree rval, type;
@@ -3612,6 +3668,23 @@ parser_build_binary_op (location_t locat
return result;
}
+/* Return a tree for the sum or difference (RESULTCODE says which)
+ of pointer PTROP and integer INTOP. */
+
+static
+tree
+c_pointer_int_sum (location_t location, enum tree_code resultcode,
+ tree ptrop, tree intop)
+{
+ /* The result is a pointer of the same type that is being added. */
+ tree result_type = TREE_TYPE (ptrop);
+
+ if (SHARED_TYPE_P (TREE_TYPE (result_type)))
+ return upc_pts_int_sum (location, resultcode, ptrop, intop);
+
+ return pointer_int_sum (location, resultcode, ptrop, intop);
+}
+
/* Return a tree for the difference of pointers OP0 and OP1.
The resulting tree has type int. */
@@ -3624,6 +3697,7 @@ pointer_diff (location_t loc, tree op0,
addr_space_t as0 = TYPE_ADDR_SPACE (TREE_TYPE (TREE_TYPE (op0)));
addr_space_t as1 = TYPE_ADDR_SPACE (TREE_TYPE (TREE_TYPE (op1)));
tree target_type = TREE_TYPE (TREE_TYPE (op0));
+ tree subtrahend_type = TREE_TYPE (TREE_TYPE (op1));
tree orig_op1 = op1;
/* If the operands point into different address spaces, we need to
@@ -3660,6 +3734,9 @@ pointer_diff (location_t loc, tree op0,
pedwarn (loc, OPT_Wpointer_arith,
"pointer to a function used in subtraction");
+ if (SHARED_TYPE_P (target_type) || SHARED_TYPE_P (subtrahend_type))
+ return upc_pts_diff (op0, op1);
+
/* First do the subtraction as integers;
then drop through to build the divide operator.
Do not do default conversions on the minus operator
@@ -4174,6 +4251,11 @@ build_unary_op (location_t location,
"wrong type argument to decrement");
}
+ /* UPC pointer-to-shared types cannot be
+ incremented/decremented directly. */
+ if (SHARED_TYPE_P (TREE_TYPE (argtype)))
+ return upc_pts_increment (location, code, arg);
+
inc = c_size_in_bytes (TREE_TYPE (argtype));
inc = convert_to_ptrofftype_loc (location, inc);
}
@@ -4387,6 +4469,10 @@ build_unary_op (location_t location,
ret = build1 (code, argtype, arg);
return_build_unary_op:
gcc_assert (ret != error_mark_node);
+ /* The result of an operation on objects that
+ are UPC shared qualified, must not be shared qualified. */
+ if (SHARED_TYPE_P (TREE_TYPE (ret)))
+ TREE_TYPE (ret) = build_unshared_type (TREE_TYPE (ret));
if (TREE_CODE (ret) == INTEGER_CST && !TREE_OVERFLOW (ret)
&& !(TREE_CODE (xarg) == INTEGER_CST && !TREE_OVERFLOW (xarg)))
ret = build1 (NOP_EXPR, TREE_TYPE (ret), ret);
@@ -4830,7 +4916,8 @@ build_conditional_expr (location_t colon
"pointer/integer type mismatch in conditional expression");
else
{
- op2 = null_pointer_node;
+ op2 = !SHARED_TYPE_P (TREE_TYPE (type1))
+ ? null_pointer_node : upc_null_pts_node;
}
result_type = type1;
}
@@ -4841,7 +4928,8 @@ build_conditional_expr (location_t colon
"pointer/integer type mismatch in conditional expression");
else
{
- op1 = null_pointer_node;
+ op1 = !SHARED_TYPE_P (TREE_TYPE (type2))
+ ? null_pointer_node : upc_null_pts_node;
}
result_type = type2;
}
@@ -5136,6 +5224,12 @@ build_c_cast (location_t loc, tree type,
if (objc_is_object_ptr (type) && objc_is_object_ptr (TREE_TYPE (expr)))
return build1 (NOP_EXPR, type, expr);
+ if (SHARED_TYPE_P (type))
+ {
+ error ("UPC does not allow casts to a shared type");
+ return error_mark_node;
+ }
+
type = TYPE_MAIN_VARIANT (type);
if (TREE_CODE (type) == ARRAY_TYPE)
@@ -5157,6 +5251,22 @@ build_c_cast (location_t loc, tree type,
return error_mark_node;
}
+ if (integer_zerop (value)
+ && POINTER_TYPE_P (type)
+ && SHARED_TYPE_P (TREE_TYPE (type))
+ && POINTER_TYPE_P (TREE_TYPE (expr))
+ && ! SHARED_TYPE_P (TREE_TYPE (TREE_TYPE (expr))))
+ {
+ value = upc_null_pts_node;
+ }
+
+ if (!SHARED_TYPE_P (type) && SHARED_TYPE_P (TREE_TYPE (expr)))
+ {
+ /* UPC disallows things like:
+ (int)p = <expr>; (where p is a shared int) */
+ value = non_lvalue (value);
+ }
+
if (type == TYPE_MAIN_VARIANT (TREE_TYPE (value)))
{
if (RECORD_OR_UNION_TYPE_P (type))
@@ -5207,6 +5317,17 @@ build_c_cast (location_t loc, tree type,
otype = TREE_TYPE (value);
+ if (TREE_CODE (type) == POINTER_TYPE
+ && TREE_CODE (otype) == POINTER_TYPE)
+ {
+ int t_shared = SHARED_TYPE_P (TREE_TYPE (type));
+ int o_shared = SHARED_TYPE_P (TREE_TYPE (otype));
+ if ((!t_shared && o_shared)
+ || (t_shared && o_shared
+ && !lang_hooks.types_compatible_p (type, otype)))
+ return build1 (CONVERT_EXPR, type, value);
+ }
+
/* Optionally warn about potentially worrisome casts. */
if (warn_cast_qual
&& TREE_CODE (type) == POINTER_TYPE
@@ -5257,6 +5378,33 @@ build_c_cast (location_t loc, tree type,
warning_at (loc, OPT_Wcast_align,
"cast increases required alignment of target type");
+ if (POINTER_TYPE_P (type)
+ && SHARED_TYPE_P (TREE_TYPE (type))
+ && POINTER_TYPE_P (otype)
+ && !SHARED_TYPE_P (TREE_TYPE (otype)))
+ {
+ error_at (loc, "UPC does not allow casts from a local pointer to a pointer-to-shared");
+ return error_mark_node;
+ }
+
+ if (TREE_CODE (type) == POINTER_TYPE
+ && TREE_CODE (otype) == INTEGER_TYPE
+ && SHARED_TYPE_P (TREE_TYPE (type))
+ && !integer_zerop (value))
+ {
+ error_at (loc, "UPC does not allow casts from an integer to a pointer-to-shared");
+ return error_mark_node;
+ }
+
+ if (TREE_CODE (type) == INTEGER_TYPE
+ && TREE_CODE (otype) == POINTER_TYPE
+ && SHARED_TYPE_P (TREE_TYPE (otype)))
+ {
+ /* UPC pointer-to-shared -> integer
+ This will be lowered by the genericize pass. */
+ return build1 (CONVERT_EXPR, type, value);
+ }
+
if (TREE_CODE (type) == INTEGER_TYPE
&& TREE_CODE (otype) == POINTER_TYPE
&& TYPE_PRECISION (type) != TYPE_PRECISION (otype))
@@ -5579,6 +5727,12 @@ build_modify_expr (location_t location,
newrhs = c_fully_fold (newrhs, false, NULL);
if (rhs_semantic_type)
newrhs = build1 (EXCESS_PRECISION_EXPR, rhs_semantic_type, newrhs);
+ /* If the lhs is UPC 'shared' qualified, we drop the qualifier
+ for the purposes of conversions from rhstype to lhstype.
+ This will prevent the inadvertent creation of temporaries
+ with "shared" asserted. */
+ if (SHARED_TYPE_P (lhstype))
+ lhstype = build_unshared_type (lhstype);
newrhs = convert_for_assignment (location, rhs_loc, lhstype, newrhs,
rhs_origtype, ic_assign, npc,
NULL_TREE, NULL_TREE, 0);
@@ -5892,6 +6046,34 @@ convert_for_assignment (location_t locat
} \
} while (0)
+ /* Similar to WARN_FOR_ASSIGNMENT, but used to diagnose certain
+ error conditions defined by the UPC language specification
+ when converting between pointer-to-shared types and other types. */
+#define ERROR_FOR_ASSIGNMENT(LOCATION, OPT, AR, AS, IN, RE) \
+ do { \
+ switch (errtype) \
+ { \
+ case ic_argpass: \
+ error_at (LOCATION, AR, parmnum, rname); \
+ inform ((fundecl && !DECL_IS_BUILTIN (fundecl)) \
+ ? DECL_SOURCE_LOCATION (fundecl) : LOCATION, \
+ "expected %qT but argument is of type %qT", \
+ type, rhstype); \
+ break; \
+ case ic_assign: \
+ error_at (LOCATION, AS); \
+ break; \
+ case ic_init: \
+ error_at (LOCATION, IN); \
+ break; \
+ case ic_return: \
+ error_at (LOCATION, RE); \
+ break; \
+ default: \
+ gcc_unreachable (); \
+ } \
+ } while (0)
+
/* This macro is used to emit diagnostics to ensure that all format
strings are complete sentences, visible to gettext and checked at
compile time. It is the same as PEDWARN_FOR_ASSIGNMENT but with an
@@ -6135,7 +6317,9 @@ convert_for_assignment (location_t locat
/* Can convert integer zero to any pointer type. */
if (null_pointer_constant)
{
- rhs = null_pointer_node;
+ tree ttl = TREE_TYPE (memb_type);
+ rhs = !SHARED_TYPE_P (ttl)
+ ? null_pointer_node : upc_null_pts_node;
break;
}
}
@@ -6225,6 +6409,43 @@ convert_for_assignment (location_t locat
? c_build_qualified_type (TYPE_MAIN_VARIANT (mvr),
TYPE_QUAL_ATOMIC)
: TYPE_MAIN_VARIANT (mvr));
+ if ((SHARED_TYPE_P (ttl) && !SHARED_TYPE_P (ttr))
+ && !integer_zerop (rhs))
+ {
+ error_at (location, "UPC does not allow assignments from a local pointer "
+ "to a pointer-to-shared");
+ return error_mark_node;
+ }
+ if (!SHARED_TYPE_P (ttl) && SHARED_TYPE_P (ttr))
+ {
+ if (upc_is_null_pts_p (rhs))
+ {
+ return null_pointer_node;
+ }
+ else
+ {
+ error_at (location, "UPC does not allow assignments "
+ "from a pointer-to-shared to a local pointer");
+ return error_mark_node;
+ }
+ }
+ if (SHARED_TYPE_P (ttl) && SHARED_TYPE_P (ttr) && (ttl != ttr)
+ && !(VOID_TYPE_P (ttl) || VOID_TYPE_P (ttr)))
+ {
+ const tree bs_l = get_block_factor (ttl);
+ const tree bs_r = get_block_factor (ttr);
+ /* Both source and destination are non-void pointers to shared,
+ whose target types are not equal.
+ UPC dictates that their blocking factors must be equal. */
+ if (!tree_int_cst_equal (bs_l, bs_r))
+ {
+ error_at (location, "UPC does not allow assignment "
+ "between pointers to shared with "
+ "differing block sizes without a cast");
+ return error_mark_node;
+ }
+ }
+
/* Opaque pointers are treated like void pointers. */
is_opaque_pointer = vector_targets_convertible_p (ttl, ttr);
@@ -6463,6 +6684,19 @@ convert_for_assignment (location_t locat
}
else if (codel == POINTER_TYPE && coder == INTEGER_TYPE)
{
+ if (!null_pointer_constant && SHARED_TYPE_P (TREE_TYPE (type)))
+ {
+ ERROR_FOR_ASSIGNMENT (location, 0,
+ G_("passing argument %d of %qE attempts to make "
+ "a UPC pointer-to-shared value from an integer"),
+ G_("assignment attempts to make a UPC pointer-to-shared "
+ "value from an integer"),
+ G_("initialization attempts to make a UPC pointer-to-shared "
+ "value from an integer without a cast"),
+ G_("return makes a UPC pointer-to-shared value from an "
+ "integer"));
+ return error_mark_node;
+ }
/* An explicit constant 0 can convert to a pointer,
or one that results from arithmetic, even including
a cast to integer type. */
@@ -6568,21 +6802,31 @@ valid_compound_expr_initializer (tree va
void
store_init_value (location_t init_loc, tree decl, tree init, tree origtype)
{
- tree value, type;
- bool npc = false;
+ const bool npc = init && null_pointer_constant_p (init);
+ const bool is_upc_decl_init = upc_check_decl_init (decl, init);
+ const bool require_constant = TREE_STATIC (decl) && !is_upc_decl_init;
+ tree type = TREE_TYPE (decl);
+ tree value;
/* If variable's type was invalidly declared, just ignore it. */
- type = TREE_TYPE (decl);
if (TREE_CODE (type) == ERROR_MARK)
return;
/* Digest the specified initializer into an expression. */
- if (init)
- npc = null_pointer_constant_p (init);
value = digest_init (init_loc, type, init, origtype, npc,
- true, TREE_STATIC (decl));
+ true, require_constant);
+
+ /* UPC cannot initialize certain values at compile time.
+ For example, the address of a UPC 'shared' variable must
+ be evaluated at runtime. */
+
+ if (is_upc_decl_init)
+ {
+ upc_decl_init (decl, value);
+ return;
+ }
/* Store the expression if valid; else report error. */
@@ -7388,6 +7632,9 @@ really_start_incremental_init (tree type
designator_depth = 0;
designator_erroneous = 0;
+ /* The result of the constructor must not be UPC shared qualified */
+ if (SHARED_TYPE_P (constructor_type))
+ constructor_type = build_unshared_type (constructor_type);
if (RECORD_OR_UNION_TYPE_P (constructor_type))
{
constructor_fields = TYPE_FIELDS (constructor_type);
@@ -9662,6 +9909,20 @@ c_finish_return (location_t loc, tree re
TREE_NO_WARNING (ret_stmt) |= no_warning;
return add_stmt (ret_stmt);
}
+
+/* Convert EXPR to TYPE if the type of EXPR is
+ assignment compatible with TYPE.
+ Otherwise, issue an error (or warning) as appropriate. */
+
+tree
+c_cvt_expr_for_assign (location_t loc, tree type, tree expr)
+{
+ if (expr == NULL_TREE || expr == error_mark_node)
+ return expr;
+ return convert_for_assignment (loc, UNKNOWN_LOCATION, type,
+ expr, TREE_TYPE (expr),
+ ic_assign, false, NULL_TREE, NULL_TREE, 0);
+}
struct c_switch {
/* The SWITCH_EXPR being built. */
@@ -10639,12 +10900,12 @@ build_binary_op (location_t location, en
/* Handle the pointer + int case. */
if (code0 == POINTER_TYPE && code1 == INTEGER_TYPE)
{
- ret = pointer_int_sum (location, PLUS_EXPR, op0, op1);
+ ret = c_pointer_int_sum (location, PLUS_EXPR, op0, op1);
goto return_build_binary_op;
}
else if (code1 == POINTER_TYPE && code0 == INTEGER_TYPE)
{
- ret = pointer_int_sum (location, PLUS_EXPR, op1, op0);
+ ret = c_pointer_int_sum (location, PLUS_EXPR, op1, op0);
goto return_build_binary_op;
}
else
@@ -10663,7 +10924,7 @@ build_binary_op (location_t location, en
/* Handle pointer minus int. Just like pointer plus int. */
else if (code0 == POINTER_TYPE && code1 == INTEGER_TYPE)
{
- ret = pointer_int_sum (location, MINUS_EXPR, op0, op1);
+ ret = c_pointer_int_sum (location, MINUS_EXPR, op0, op1);
goto return_build_binary_op;
}
else
@@ -11015,6 +11276,33 @@ build_binary_op (location_t location, en
addr_space_t as1 = TYPE_ADDR_SPACE (tt1);
addr_space_t as_common = ADDR_SPACE_GENERIC;
+ if ((SHARED_TYPE_P (tt0)
+ && !(SHARED_TYPE_P (tt1) || integer_zerop(op1)))
+ || (SHARED_TYPE_P (tt1)
+ && !(SHARED_TYPE_P (tt0) || integer_zerop(op0))))
+ {
+ error_at (location, "UPC does not allow comparisons "
+ "between pointers to shared and "
+ "local pointers");
+ return error_mark_node;
+ }
+ if (SHARED_TYPE_P (tt0)
+ && SHARED_TYPE_P (tt1) && (tt0 != tt1)
+ && !(VOID_TYPE_P (tt0) || VOID_TYPE_P (tt1)))
+ {
+ const tree bs_0 = get_block_factor (tt0);
+ const tree bs_1 = get_block_factor (tt1);
+ /* Both source and destination are non-void pointers to shared,
+ whose target types are not equal.
+ UPC dictates that their blocking factors must be equal. */
+ if (!tree_int_cst_equal (bs_0, bs_1))
+ {
+ error_at (location, "UPC does not allow comparison "
+ "between pointers to shared with "
+ "differing block sizes without a cast");
+ return error_mark_node;
+ }
+ }
/* Anything compares with void *. void * compares with anything.
Otherwise, the targets must be compatible
and both must be object or both incomplete. */
@@ -11046,9 +11334,17 @@ build_binary_op (location_t location, en
if (result_type == NULL_TREE)
{
- int qual = ENCODE_QUAL_ADDR_SPACE (as_common);
- result_type = build_pointer_type
- (build_qualified_type (void_type_node, qual));
+ if (SHARED_TYPE_P(tt0) || SHARED_TYPE_P(tt1))
+ {
+ result_type = upc_pts_type_node;
+ }
+ else
+ {
+ int qual = ENCODE_QUAL_ADDR_SPACE (as_common);
+ result_type = build_pointer_type
+ (build_qualified_type (void_type_node,
+ qual));
+ }
}
}
else if (code0 == POINTER_TYPE && code1 == INTEGER_TYPE)
@@ -11106,10 +11402,35 @@ build_binary_op (location_t location, en
short_compare = 1;
else if (code0 == POINTER_TYPE && code1 == POINTER_TYPE)
{
- addr_space_t as0 = TYPE_ADDR_SPACE (TREE_TYPE (type0));
- addr_space_t as1 = TYPE_ADDR_SPACE (TREE_TYPE (type1));
+ const tree tt0 = TREE_TYPE (type0);
+ const tree tt1 = TREE_TYPE (type1);
+ addr_space_t as0 = TYPE_ADDR_SPACE (tt0);
+ addr_space_t as1 = TYPE_ADDR_SPACE (tt1);
addr_space_t as_common;
+ if (SHARED_TYPE_P (tt0) != SHARED_TYPE_P (tt1))
+ {
+ error_at (location, "UPC does not allow comparisons between "
+ "pointers to shared and local pointers");
+ return error_mark_node;
+ }
+ if (SHARED_TYPE_P (tt0)
+ && SHARED_TYPE_P (tt1) && (tt0 != tt1)
+ && !(VOID_TYPE_P (tt0) || VOID_TYPE_P (tt1)))
+ {
+ const tree bs_0 = get_block_factor (tt0);
+ const tree bs_1 = get_block_factor (tt1);
+ /* Both source and destination are non-void pointers to shared,
+ whose target types are not equal.
+ UPC dictates that their blocking factors must be equal. */
+ if (!tree_int_cst_equal (bs_0, bs_1))
+ {
+ error_at (location, "UPC does not allow comparison "
+ "between pointers to shared with "
+ "differing block sizes without a cast");
+ return error_mark_node;
+ }
+ }
if (comp_target_types (location, type0, type1))
{
result_type = common_pointer_type (type0, type1);
@@ -11132,6 +11453,11 @@ build_binary_op (location_t location, en
"disjoint address spaces");
return error_mark_node;
}
+ else if (SHARED_TYPE_P (TREE_TYPE (type0))
+ || SHARED_TYPE_P (TREE_TYPE (type1)))
+ {
+ result_type = upc_pts_type_node;
+ }
else
{
int qual = ENCODE_QUAL_ADDR_SPACE (as_common);
@@ -13320,7 +13646,7 @@ c_finish_transaction (location_t loc, tr
down to the element type of an array. */
tree
-c_build_qualified_type (tree type, int type_quals)
+c_build_qualified_type_1 (tree type, int type_quals, tree layout_qualifier)
{
if (type == error_mark_node)
return type;
@@ -13328,13 +13654,17 @@ c_build_qualified_type (tree type, int t
if (TREE_CODE (type) == ARRAY_TYPE)
{
tree t;
- tree element_type = c_build_qualified_type (TREE_TYPE (type),
- type_quals);
+ tree element_type = c_build_qualified_type_1 (TREE_TYPE (type),
+ type_quals,
+ layout_qualifier);
/* See if we already have an identically qualified type. */
for (t = TYPE_MAIN_VARIANT (type); t; t = TYPE_NEXT_VARIANT (t))
{
- if (TYPE_QUALS (strip_array_types (t)) == type_quals
+ const tree t_elem_type = strip_array_types (t);
+ tree t_elem_block_factor = TYPE_BLOCK_FACTOR (t_elem_type);
+ if (TYPE_QUALS (t_elem_type) == type_quals
+ && t_elem_block_factor == layout_qualifier
&& TYPE_NAME (t) == TYPE_NAME (type)
&& TYPE_CONTEXT (t) == TYPE_CONTEXT (type)
&& attribute_list_equal (TYPE_ATTRIBUTES (t),
@@ -13365,7 +13695,8 @@ c_build_qualified_type (tree type, int t
TYPE_REVERSE_STORAGE_ORDER (unqualified_canon) = 1;
}
TYPE_CANONICAL (t)
- = c_build_qualified_type (unqualified_canon, type_quals);
+ = c_build_qualified_type_1 (unqualified_canon, type_quals,
+ layout_qualifier);
}
else
TYPE_CANONICAL (t) = t;
@@ -13384,7 +13715,7 @@ c_build_qualified_type (tree type, int t
type_quals &= ~TYPE_QUAL_RESTRICT;
}
- tree var_type = build_qualified_type (type, type_quals);
+ tree var_type = build_qualified_type_1 (type, type_quals, layout_qualifier);
/* A variant type does not inherit the list of incomplete vars from the
type main variant. */
if (RECORD_OR_UNION_TYPE_P (var_type))
===================================================================
@@ -0,0 +1,130 @@
+/* c-upc-gasp.c: UPC GASP (GAS Performance) instrumentation support
+ Copyright (C) 2005-2015 Free Software Foundation, Inc.
+ Contributed by Gary Funck <gary@intrepid.com>
+ and Nenad Vukicevic <nenad@intrepid.com>.
+ Based on original Implementation by Adam Leko <leko@hcs.ufl.edu>.
+
+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/>. */
+
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "stringpool.h"
+#include "c-tree.h"
+#include "tree-iterator.h"
+#include "c-upc-gasp.h"
+#include "c-upc-rts-names.h"
+
+static tree build_string_ref (const char *string);
+
+/* Build a reference to a literal string.
+ (cribbed from mf_build_string in tree-mudflap.c) */
+
+static tree
+build_string_ref (const char *string)
+{
+ size_t len = strlen (string);
+ tree result = build_string (len + 1, string);
+ TREE_TYPE (result) = build_array_type
+ (char_type_node, build_index_type (build_int_cst (NULL_TREE, len)));
+ TREE_CONSTANT (result) = 1;
+ TREE_READONLY (result) = 1;
+ TREE_STATIC (result) = 1;
+ result = build1 (ADDR_EXPR, build_pointer_type (char_type_node), result);
+ return result;
+}
+
+/* Add source args to the argument list. */
+
+tree
+upc_gasp_add_src_args (tree args, const char *filename, int lineno)
+{
+ return chainon (args,
+ tree_cons (NULL_TREE, build_string_ref (filename),
+ tree_cons (NULL_TREE,
+ build_int_cst (NULL_TREE, lineno),
+ NULL_TREE)));
+}
+
+/* Instrument `upc_forall' statement begin/end.
+ Return a call to the profiling function. */
+
+tree
+upc_instrument_forall (location_t loc, int start)
+{
+ const char *filename = LOCATION_FILE (loc);
+ const int lineno = LOCATION_LINE (loc);
+ tree pfunc;
+
+ pfunc = lookup_name (get_identifier (UPC_INSTRUMENT_FORALL));
+ if (!pfunc)
+ internal_error ("UPC profiling function `%s' not found",
+ UPC_INSTRUMENT_FORALL);
+
+ return build_call_expr (pfunc, 3,
+ build_int_cst (NULL_TREE, start),
+ build_string_ref (filename),
+ build_int_cst (NULL_TREE, lineno));
+}
+
+/* If UPC function profiling has been enabled, rewrite the
+ body of FNDECL so that the GASP instrumentation function
+ is called before the body of the function is executed,
+ and then after it is executed (as a TRY_FINALLY_EXPR). */
+
+void
+upc_instrument_func (tree fndecl)
+{
+ tree tf, x, pfunc, bind;
+ const char *filename, *funcname;
+ int lineno;
+
+ /* Skip, if profiling disabled via #pragma pupc. */
+ if (!get_upc_pupc_mode ())
+ return;
+
+ pfunc = lookup_name (get_identifier (UPC_INSTRUMENT_FUNC));
+ if (!pfunc)
+ internal_error ("UPC profiling function `%s' not found",
+ UPC_INSTRUMENT_FUNC);
+ funcname = "<unknown>";
+ if (DECL_NAME (fndecl))
+ funcname = IDENTIFIER_POINTER (DECL_NAME (fndecl));
+ lineno = DECL_SOURCE_LINE (fndecl);
+ filename = DECL_SOURCE_FILE (fndecl);
+ tf = build2 (TRY_FINALLY_EXPR, void_type_node, NULL, NULL);
+ TREE_SIDE_EFFECTS (tf) = 1;
+ x = DECL_SAVED_TREE (fndecl);
+ append_to_statement_list (x, &TREE_OPERAND (tf, 0));
+ x = build_call_expr (pfunc, 4, integer_zero_node, /* start == 0 */
+ build_string_ref (funcname),
+ build_string_ref (filename),
+ build_int_cst (NULL_TREE, lineno));
+ append_to_statement_list (x, &TREE_OPERAND (tf, 1));
+
+ bind = build3 (BIND_EXPR, void_type_node, NULL, NULL, NULL);
+ TREE_SIDE_EFFECTS (bind) = 1;
+ x = build_call_expr (pfunc, 4, integer_one_node, /* start == 1 */
+ build_string_ref (funcname),
+ build_string_ref (filename),
+ build_int_cst (NULL_TREE, lineno));
+ append_to_statement_list (x, &BIND_EXPR_BODY (bind));
+ append_to_statement_list (tf, &BIND_EXPR_BODY (bind));
+
+ DECL_SAVED_TREE (fndecl) = bind;
+
+}
===================================================================
@@ -0,0 +1,32 @@
+/* c-upc-gasp.h: GASP instrumentation API.
+ Copyright (C) 2009-2015 Free Software Foundation, Inc.
+ Contributed by Gary Funck <gary@intrepid.com>
+ and Nenad Vukicevic <nenad@intrepid.com>.
+
+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_C_UPC_GASP_H
+#define GCC_C_UPC_GASP_H 1
+
+extern int disable_pupc_mode(void);
+extern int get_upc_pupc_mode(void);
+extern tree upc_gasp_add_src_args (tree, const char *, int);
+extern tree upc_instrument_forall (location_t, int);
+extern void set_pupc_mode(int);
+extern void upc_instrument_func (tree);
+
+#endif /* !GCC_C_UPC_GASP_H */
===================================================================
@@ -0,0 +1,798 @@
+/* c-upc.c: implement UPC-related actions
+ Copyright (C) 2001-2015 Free Software Foundation, Inc.
+ Contributed by Gary Funck <gary@intrepid.com>
+ and Nenad Vukicevic <nenad@intrepid.com>.
+ Based on original implementation
+ by Jesse M. Draper <jdraper@super.org>
+ and William W. Carlson <wwc@super.org>.
+
+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/>. */
+
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "c-family/c-common.h"
+#include "langhooks.h"
+#include "tree.h"
+#include "alias.h"
+#include "fold-const.h"
+#include "stringpool.h"
+#include "stor-layout.h"
+#include "output.h"
+#include "attribs.h"
+#include "target.h"
+#include "varasm.h"
+#include "c-upc.h"
+#include "c-family/c-upc-pts.h"
+#include "c-upc-pts-ops.h"
+#include "c-upc-rts-names.h"
+
+
+static int recursive_count_upc_threads_refs (tree);
+static int upc_sizeof_type_check (const char *, tree);
+
+
+/* Return a UPC pointer-to-shared type with target type, TO_TYPE.
+ If the UPC pointer-to-shared representation has a "register mode",
+ then build a pointer type with that mode. If the UPC pointer-to-shared
+ representation type has BLKmode, then calculate its size based
+ upon the representation type. */
+
+tree
+upc_build_pointer_type (tree to_type)
+{
+ machine_mode pointer_mode;
+ tree ptr_type;
+ if (to_type == NULL_TREE || TREE_CODE (to_type) == ERROR_MARK)
+ return error_mark_node;
+ pointer_mode = TYPE_MODE (upc_pts_rep_type_node);
+ ptr_type = build_pointer_type_for_mode (to_type, pointer_mode, false);
+ if (!integer_zerop (TYPE_SIZE (ptr_type)))
+ return ptr_type;
+ /* If the UPC pointer-to-shared representation has a size of zero,
+ then it must have BLKmode. In that case, calculate the sizes
+ and alignment from the underlying representation type. This
+ situation may arise when the 'struct PTS' representation is
+ configured on targets that do not assign TImode to aligned
+ 128 bit structs. */
+ gcc_assert (pointer_mode == BLKmode);
+ TYPE_SIZE (ptr_type) = TYPE_SIZE (upc_pts_rep_type_node);
+ TYPE_SIZE_UNIT (ptr_type) = TYPE_SIZE_UNIT (upc_pts_rep_type_node);
+ TYPE_ALIGN (ptr_type) = TYPE_ALIGN (upc_pts_rep_type_node);
+ TYPE_UNSIGNED (ptr_type) = TYPE_UNSIGNED (upc_pts_rep_type_node);
+ TYPE_PRECISION (ptr_type) = TYPE_PRECISION (upc_pts_rep_type_node);
+ return ptr_type;
+}
+
+/* Check the type of the operand passed to a
+ upc_*sizeof () operator.
+
+ The type must *not* be:
+ - an error mark node
+ - an incomplete type
+ - a function type
+ - a void type
+
+ The type *must* be a UPC 'shared' type.
+
+ UPC defines the following flavors of sizeof operators:
+ upc_blocksizeof, upc_elemsizeof, and upc_localsizeof.
+ These operations have similar syntax and constraints
+ as the "C" language sizeof operator. */
+
+static int
+upc_sizeof_type_check (const char *op_name, tree type)
+{
+ enum tree_code code = TREE_CODE (type);
+ if (code == ERROR_MARK)
+ {
+ return 0;
+ }
+ else if (!COMPLETE_TYPE_P (type))
+ {
+ lang_hooks.types.incomplete_type_error (NULL_TREE, type);
+ return 0;
+ }
+ else if (code == FUNCTION_TYPE)
+ {
+ error ("UPC operator %s applied to a function type", op_name);
+ return 0;
+ }
+ else if (code == VOID_TYPE)
+ {
+ error ("UPC operator %s applied to a void type", op_name);
+ return 0;
+ }
+ else if (!SHARED_TYPE_P (type))
+ {
+ error ("UPC operator %s applied to a non-shared type", op_name);
+ return 0;
+ }
+ return 1;
+}
+
+/* Compute the value of the `upc_blocksizeof' operator.
+ The UPC block size is the value of UPC's "layout qualifier".
+ For example:
+
+ Declaration upc_blocksizeof()
+ ----------- ----------------
+ shared int A[5*THREADS]; 1 (default)
+ shared [5] int A[5*THREADS]; 5
+ shared [] int A[5*100]; 0 (indefinite)
+ shared [*] int A[5*THREADS]; 5 (distributed by compiler) */
+
+tree
+upc_blocksizeof (location_t ARG_UNUSED (loc), tree type)
+{
+ tree block_factor = size_one_node;
+ if (!type || TREE_CODE (type) == ERROR_MARK)
+ return error_mark_node;
+ if (upc_sizeof_type_check ("upc_blocksizeof", type))
+ block_factor = get_block_factor (type);
+ return block_factor;
+}
+
+/* Compute the value of the `upc_elemsizeof' operator. */
+
+tree
+upc_elemsizeof (location_t loc, tree type)
+{
+ tree elem_size;
+
+ if (!(type && upc_sizeof_type_check ("upc_elemsizeof", type)))
+ return size_int (1);
+ elem_size = c_sizeof (loc, strip_array_types (type));
+ return elem_size;
+}
+
+/* Compute the value of the `upc_localsizeof' operator.
+ Per the language spec:
+ The upc_localsizeof operator returns the size, in bytes, of the
+ local portion of its operand, which may be a shared object or a
+ shared-qualified type. It returns the same value on all threads; the
+ value is an upper bound of the size allocated with affinity to any
+ single thread and may include an unspecified amount of padding.
+ The result of upc_localsizeof is an integer constant. */
+
+tree
+upc_localsizeof (location_t loc, tree type)
+{
+ tree block_factor, local_size, total_size;
+
+ if (!(type && upc_sizeof_type_check ("upc_localsizeof", type)))
+ return size_one_node;
+
+ /* for scalars, return sizeof */
+
+ if (TREE_CODE (type) != ARRAY_TYPE)
+ return c_sizeof (loc, type);
+
+ block_factor = upc_blocksizeof (loc, type);
+ block_factor = convert (bitsizetype, block_factor);
+ total_size = TYPE_SIZE (type);
+
+ if (integer_zerop (block_factor))
+ {
+ /* local size is total size, because the entire
+ object lives on a single thread. This is the
+ case for declarations of types with an "indefinite"
+ layout qualifier. For example, given:
+ shared [] int A[100];
+ the value returned for upc_localsizeof (A)
+ will be: 100 * sizeof (int). */
+ local_size = total_size;
+ }
+ else
+ {
+ tree elt_type, elt_size, n_elts;
+ tree t_factor, n_full_blocks;
+ tree n_full_blocks_per_thread, n_elts_in_full_blocks;
+ tree n_rem_elts, n_local_elts;
+ elt_type = strip_array_types (type);
+ if (!elt_type || TREE_CODE (elt_type) == ERROR_MARK)
+ return size_one_node;
+ elt_size = TYPE_SIZE (elt_type);
+ n_elts = size_binop (EXACT_DIV_EXPR, total_size, elt_size);
+ /* Use the worst case size, if compiling in a dynamic
+ threads environment. The worst case size can
+ be derived by setting T_FACTOR to 1 in the calculations
+ that follow. Otherwise T_FACTOR is equal to THREADS. */
+ t_factor = flag_upc_threads ? upc_num_threads () : size_one_node;
+ t_factor = convert (bitsizetype, t_factor);
+ n_full_blocks = size_binop (FLOOR_DIV_EXPR, n_elts, block_factor);
+ n_full_blocks_per_thread = size_binop (FLOOR_DIV_EXPR,
+ n_full_blocks, t_factor);
+ n_elts_in_full_blocks = size_binop (MULT_EXPR,
+ size_binop (MULT_EXPR,
+ n_full_blocks_per_thread,
+ t_factor),
+ block_factor);
+ n_rem_elts = size_binop (MINUS_EXPR, n_elts, n_elts_in_full_blocks);
+ n_local_elts = size_binop (MULT_EXPR,
+ n_full_blocks_per_thread, block_factor);
+ /* If any elements remain, add a full block size. */
+ if (!integer_zerop (n_rem_elts))
+ n_local_elts = size_binop (PLUS_EXPR, n_local_elts, block_factor);
+ local_size = size_binop (MULT_EXPR, n_local_elts, elt_size);
+ }
+
+ /* Convert local size into bytes, and return result. */
+
+ local_size = convert (sizetype, local_size);
+ local_size = size_binop (CEIL_DIV_EXPR, local_size,
+ size_int (BITS_PER_UNIT));
+ return local_size;
+}
+
+/* Traverse the expression and return the number of times
+ THREADS is referenced. This is used to check the restriction
+ on UPC shared array declarations, that the predefined THREADS
+ variable can be mentioned only once. */
+
+static int
+recursive_count_upc_threads_refs (tree expr)
+{
+ enum tree_code code;
+ int i;
+ int count = 0;
+ if (expr == NULL_TREE)
+ return 0;
+ code = TREE_CODE (expr);
+ switch (TREE_CODE_CLASS (code))
+ {
+ case tcc_unary:
+ case tcc_binary:
+ case tcc_comparison:
+ case tcc_expression:
+ case tcc_reference:
+ case tcc_statement:
+ for (i = 0; i < TREE_CODE_LENGTH (code); i++)
+ count += recursive_count_upc_threads_refs (TREE_OPERAND (expr, i));
+ break;
+ case tcc_declaration:
+ if (expr == lookup_name (get_identifier ("THREADS")))
+ count = 1;
+ break;
+ default:
+ break;
+ }
+ return count;
+}
+
+/* Count the number of references to THREADS inside `expr'. */
+
+int
+count_upc_threads_refs (tree expr)
+{
+ return recursive_count_upc_threads_refs (expr);
+}
+
+/* Test that EXPR is an expression tree where THREADS appears on
+ the left or the right hand side of a multiply, in a series
+ of zero or more multiplies. For proper operation, the caller
+ should ensure that THREADS is referenced only once,
+ by calling count_upc_threads_refs () prior to calling this routine. */
+
+int
+is_multiple_of_upc_threads (tree expr)
+{
+ enum tree_code code;
+ if (expr == NULL_TREE)
+ return 0;
+ if (expr == lookup_name (get_identifier ("THREADS")))
+ return 1;
+ code = TREE_CODE (expr);
+ if (code == MULT_EXPR)
+ return is_multiple_of_upc_threads (TREE_OPERAND (expr, 0))
+ | is_multiple_of_upc_threads (TREE_OPERAND (expr, 1));
+ if ((code == NOP_EXPR) || (code == NON_LVALUE_EXPR)
+ || (code == CONVERT_EXPR))
+ return is_multiple_of_upc_threads (TREE_OPERAND (expr, 0));
+ return 0;
+}
+
+/* Find all references to THREADS and change them into the constant `1'.
+ This is done so that fold () when applied to the dimension of a
+ UPC shared array will yield the local size of the array. */
+
+void
+set_upc_threads_refs_to_one (tree *expr)
+{
+ enum tree_code code;
+ int i;
+ if (*expr == NULL_TREE)
+ return;
+ code = TREE_CODE (*expr);
+ switch (TREE_CODE_CLASS (code))
+ {
+ case tcc_unary:
+ case tcc_binary:
+ case tcc_comparison:
+ case tcc_expression:
+ case tcc_reference:
+ case tcc_statement:
+ for (i = 0; i < TREE_CODE_LENGTH (code); i++)
+ set_upc_threads_refs_to_one (&TREE_OPERAND (*expr, i));
+ break;
+ case tcc_declaration:
+ if (*expr == lookup_name (get_identifier ("THREADS")))
+ *expr = integer_one_node;
+ break;
+ default:
+ break;
+ }
+ return;
+}
+
+/* As part of declaration processing, for a particular kind
+ of declaration, DECL_KIND, and a given LAYOUT_QUALIFIER, calculate
+ the resulting blocking factor and return it. Issue an error
+ diagnostic if the LAYOUT_QUALIFIER specification is invalid.
+ For array types, the TYPE parameter may be the MAIN_VARIANT,
+ and not shared qualified; in that case - ELEM_BLOCK_FACTOR
+ is the blocking factor derived from the original element type.
+ If LAYOUT_QUALIFIER is NULL and ELEM_BLOCK_FACTOR is non-null,
+ then the ELEM_BLOCK_FACTOR will be used. This situation occurs
+ when the element type is a typedef, for example. If both
+ LAYOUT_QUALIFIER and ELEM_BLOCK_FACTOR are non-NULL, then they
+ must be equal. */
+
+tree
+upc_grok_layout_qualifier (location_t loc, const enum tree_code decl_kind,
+ tree type, tree elem_block_factor,
+ tree layout_qualifier)
+{
+ tree block_factor = NULL_TREE;
+
+ if (!type || (TREE_CODE (type) == ERROR_MARK))
+ return error_mark_node;
+
+ if (TREE_CODE (type) == VOID_TYPE)
+ {
+ error_at (loc, "UPC layout qualifier cannot be applied to a void type");
+ return NULL_TREE;
+ }
+
+ /* If no explicit layout qualifier was supplied, then
+ use the blocking factor derived from the element type. */
+ if (!layout_qualifier && elem_block_factor)
+ return elem_block_factor;
+
+ /* The layout qualifier is given as the subscript operand
+ of an array ref. */
+ gcc_assert (layout_qualifier);
+ gcc_assert (TREE_CODE (layout_qualifier) == ARRAY_REF);
+ layout_qualifier = TREE_OPERAND (layout_qualifier, 1);
+
+ if (layout_qualifier == NULL_TREE)
+ {
+ /* The layout qualifier is [], which is
+ equivalent to specifying [0]. */
+ block_factor = size_zero_node;
+ }
+ else if ((TREE_CODE (layout_qualifier) == INDIRECT_REF)
+ && ((TREE_OPERAND (layout_qualifier, 0)) == NULL_TREE))
+ {
+ tree elt_size, elt_type, n_threads;
+ /* The layout qualifier is [*]. The compiler must calculate
+ a blocking factor that evenly distributes the array's
+ elements over all the UPC threads. */
+ if (!COMPLETE_TYPE_P (type))
+ {
+ error_at (loc, "UPC layout qualifier of the form [*] cannot be "
+ "applied to an incomplete type");
+ return NULL_TREE;
+ }
+ if (decl_kind == POINTER_TYPE)
+ {
+ error_at (loc, "UPC [*] qualifier may not be used in "
+ "declaration of pointers");
+ return NULL_TREE;
+ }
+ /* The blocking factor is given by this expression:
+ (sizeof (a) / upc_elemsizeof (a) + (THREADS - 1)) / THREADS,
+ where 'a' is the array being distributed. */
+ elt_type = strip_array_types (type);
+ elt_size = TYPE_SIZE (elt_type);
+ if (TYPE_HAS_THREADS_FACTOR (type))
+ block_factor =
+ size_binop (FLOOR_DIV_EXPR, TYPE_SIZE (type), elt_size);
+ else
+ {
+ n_threads = convert (bitsizetype, upc_num_threads ());
+ if (TREE_CODE (n_threads) != INTEGER_CST)
+ {
+ error_at (loc, "a UPC layout qualifier of '[*]' requires that "
+ "the array size is either an integral constant "
+ "or an integral multiple of THREADS");
+ block_factor = size_one_node;
+ }
+ else
+ {
+ block_factor = size_binop (CEIL_DIV_EXPR,
+ size_binop (FLOOR_DIV_EXPR,
+ TYPE_SIZE (type),
+ elt_size),
+ n_threads);
+ }
+ }
+ }
+ else
+ {
+ STRIP_NOPS (layout_qualifier);
+ if (TREE_CODE (layout_qualifier) != INTEGER_CST)
+ {
+ error_at (loc, "UPC layout qualifier is not an integral constant");
+ block_factor = size_one_node;
+ }
+ else if (tree_to_shwi (layout_qualifier) < 0)
+ {
+ error_at (loc, "UPC layout qualifier must be a non-negative "
+ "integral constant");
+ block_factor = size_one_node;
+ }
+ else
+ block_factor = fold (layout_qualifier);
+ }
+
+ if (TREE_OVERFLOW_P (block_factor)
+ || tree_to_shwi (block_factor) > UPC_MAX_BLOCK_SIZE)
+ {
+ error_at (loc, "the maximum UPC block size in this implementation "
+ "is %ld", (long int) UPC_MAX_BLOCK_SIZE);
+ return NULL_TREE;
+ }
+
+ if (tree_int_cst_compare (block_factor, integer_zero_node) < 0)
+ {
+ error_at (loc, "UPC layout qualifier must be a "
+ "non-negative integral constant");
+ return NULL_TREE;
+ }
+
+ /* Make sure that the UPC blocking factors are of type
+ 'size_t' so that a compare of the tree pointers
+ is sufficient to match block sizes. */
+ if (block_factor)
+ block_factor = convert (sizetype, block_factor);
+
+ if ((block_factor && elem_block_factor)
+ && block_factor != elem_block_factor)
+ {
+ error_at (loc, "UPC layout qualifier is incompatible with "
+ "the referenced type");
+ return elem_block_factor;
+ }
+
+ /* A block size of [1] is the same as specifying no
+ block size at all. */
+ if (block_factor == size_one_node)
+ block_factor = NULL_TREE;
+
+ return block_factor;
+}
+
+/* If DECL is a UPC shared variable, make sure that it ends up
+ in the executable file. */
+
+void
+upc_check_decl (tree decl)
+{
+ if (decl
+ && TREE_CODE (decl) == VAR_DECL
+ && TREE_TYPE (decl) && SHARED_TYPE_P (TREE_TYPE (decl)))
+ {
+ TREE_USED (decl) = 1;
+ TREE_ADDRESSABLE (decl) = 1;
+ TREE_STATIC (decl) = 1;
+ /* Work-around a problem where the front-end doesn't
+ properly process the used flags set above, on
+ static variables when flag_unit_at_a_time isn't set. */
+ if ((TREE_STATIC (decl) && !DECL_EXTERNAL (decl))
+ && !flag_unit_at_a_time
+ && !lookup_attribute ("used", DECL_ATTRIBUTES (decl)))
+ {
+ tree used_id = get_identifier ("used");
+ tree used_attrib = tree_cons (used_id, NULL_TREE, NULL_TREE);
+ decl_attributes (&decl, used_attrib, 0);
+ }
+ }
+}
+
+/* Return TRUE if TYPE contains any references to UPC pointers-to-shared. */
+
+int
+upc_contains_pts_refs_p (tree type)
+{
+ switch (TREE_CODE (type))
+ {
+ case POINTER_TYPE:
+ case REFERENCE_TYPE:
+ return SHARED_TYPE_P (TREE_TYPE (type));
+
+ case RECORD_TYPE:
+ case UNION_TYPE:
+ case QUAL_UNION_TYPE:
+ {
+ tree fields;
+ /* For a type that has fields, see if the fields have pointers. */
+ for (fields = TYPE_FIELDS (type); fields;
+ fields = TREE_CHAIN (fields))
+ if (TREE_CODE (fields) == FIELD_DECL
+ && upc_contains_pts_refs_p (TREE_TYPE (fields)))
+ return 1;
+ return 0;
+ }
+
+ case ARRAY_TYPE:
+ /* An array type contains pointers if its element type does. */
+ return upc_contains_pts_refs_p (TREE_TYPE (type));
+
+ default:
+ return 0;
+ }
+}
+
+/* Assign DECL to a specific linker section, if required.
+ UPC shared variables are given their own link section on
+ most target platforms, and if compiling in "pthreads mode"
+ regular local file scope variables are made thread local. */
+
+void
+upc_set_decl_section (tree decl)
+{
+ if (TREE_SHARED (decl)
+ && targetm.upc.shared_section_name ())
+ {
+ /* UPC shared variables are placed in their own shared section */
+ set_decl_section_name (decl, targetm.upc.shared_section_name ());
+ }
+ else if (flag_upc_pthreads
+ && ((TREE_STATIC (decl)
+ && (DECL_SECTION_NAME (decl) == NULL))
+ || DECL_EXTERNAL (decl)))
+ {
+ /* If we're compiling with -fupc-pthreads-model-tls asserted
+ and this is a regular "C" static scoped object which
+ is either not declared in a system header file,
+ or is being compiled in a UPC setting,
+ then assign the object to the thread local storage
+ (TLS) section. */
+ if (flag_upc && (c_header_level <= 0))
+ {
+ if (upc_pthreads_model == upc_pthreads_tls_model)
+ {
+ set_decl_tls_model (decl, decl_default_tls_model (decl));
+ DECL_COMMON (decl) = 0;
+ }
+ else
+ /* Only the TLS model is currently implemented. */
+ gcc_unreachable ();
+ }
+ }
+}
+
+/* Return an external reference to an integer variable maintained
+ by the compiler and runtime to track the dynamic nesting
+ of 'upc_forall' statements. The variable's name is given by
+ UPC_FORALL_DEPTH_NAME. */
+
+tree
+upc_rts_forall_depth_var (void)
+{
+ tree upc_forall_depth = lookup_name (
+ get_identifier (UPC_FORALL_DEPTH_NAME));
+ if (upc_forall_depth == NULL_TREE)
+ internal_error ("the UPC runtime variable '" UPC_FORALL_DEPTH_NAME "' "
+ "cannot be located; this variable should be defined "
+ "in a compiler-supplied include file");
+ assemble_external (upc_forall_depth);
+ TREE_USED (upc_forall_depth) = 1;
+ return upc_forall_depth;
+}
+
+/* Diagnose instances of UPC statements that were
+ defined in very early UPC language specifications and that
+ have since been deprecated. */
+
+int
+upc_diagnose_deprecated_stmt (location_t loc, tree id)
+{
+ const char *name = IDENTIFIER_POINTER (id);
+ struct deprecated_stmt_entry
+ {
+ const char *deprecated_id;
+ const char *correct_id;
+ };
+ static const struct deprecated_stmt_entry deprecated_stmts[] =
+ { {"barrier", "upc_barrier"},
+ {"barrier_wait", "upc_wait"},
+ {"barrier_notify", "upc_notify"},
+ {"fence", "upc_fence"},
+ {"forall", "upc_forall"} };
+ const int n_deprecated_stmts = sizeof (deprecated_stmts)
+ / sizeof (struct deprecated_stmt_entry);
+ int i;
+ for (i = 0; i < n_deprecated_stmts; ++i)
+ {
+ if (!strcmp (name, deprecated_stmts[i].deprecated_id))
+ {
+ error_at (loc, "%qs was supported in version 1.0 of the UPC "
+ "specification, it has been deprecated, "
+ "use %qs instead",
+ name, deprecated_stmts[i].correct_id);
+ return 1;
+ }
+ }
+ return 0;
+}
+
+/* Expand the pre/post increment/decrement of UPC pointer-to-shared
+ into its equivalent expression tree. */
+
+tree
+upc_pts_increment (location_t location ATTRIBUTE_UNUSED,
+ enum tree_code code, tree arg)
+{
+ /* The result type is a pointer of the same type as the argument
+ type after dropping the shared qualifier (for PTS's that happen
+ to live in shared memory). */
+ tree stable_arg = stabilize_reference (arg);
+ tree val = (code == PREINCREMENT_EXPR || code == PREDECREMENT_EXPR)
+ ? stable_arg : save_expr (stable_arg);
+ enum tree_code incr_op = (code == PREINCREMENT_EXPR
+ || code == POSTINCREMENT_EXPR)
+ ? PLUS_EXPR : MINUS_EXPR;
+ tree incr_val, result;
+ incr_val = upc_pts_int_sum (location, incr_op, val, integer_one_node);
+ TREE_SIDE_EFFECTS (incr_val) = 1;
+ result = build_modify_expr (location, arg, NULL_TREE, NOP_EXPR,
+ location, incr_val, NULL_TREE);
+ if (code == POSTINCREMENT_EXPR || code == POSTDECREMENT_EXPR)
+ result = build2 (COMPOUND_EXPR, TREE_TYPE (incr_val), result, val);
+ return result;
+}
+
+/* Return an expression that calculates the sum of a UPC
+ pointer-to-shared value and an integer value. The sum
+ operator may be PLUS_EXPR or MINUS_EXPR. The result is a
+ POINTER_PLUS_EXPR with a properly scaled integer operand.
+ This POINTER_PLUS_EXPR will be translated by the UPC lowering
+ pass into the sequence of operations dictated both by the
+ properties of the UPC pointer-to-shared type, and the UPC
+ pointer-to-shared representation. */
+
+tree
+upc_pts_int_sum (location_t loc,
+ enum tree_code resultcode, tree ptrop, tree intop)
+{
+
+ /* The result type is a pointer of the same type that is being added,
+ after dropping the UPC shared qualifier. For example, this would
+ apply to UPC pointers-to-shared that happen to live in shared memory;
+ the result of the expression must not be UPC shared qualified. */
+
+ const tree ttype = TREE_TYPE (ptrop);
+ const int shared_quals =
+ (TYPE_QUAL_SHARED | TYPE_QUAL_STRICT | TYPE_QUAL_RELAXED);
+ const int quals_minus_shared = TYPE_QUALS (ttype) & ~shared_quals;
+ const tree result_type = c_build_qualified_type (ttype, quals_minus_shared);
+ const tree result_targ_type = TREE_TYPE (result_type);
+ const tree base_type = strip_array_types (result_targ_type);
+ tree result;
+
+ if (TREE_CODE (result_targ_type) == VOID_TYPE)
+ error_at (loc, "UPC does not allow a pointer of type %<shared void *%> "
+ "to be used in arithmetic");
+
+ /* We have a pointer to a UPC shared object. For pointers to
+ simple objects, just build a "resultcode" tree with the intop and
+ let upc_genericize() handle the arithmetic correctly. For pointers to
+ arrays, compute the number of elements represented by the intop
+ and build a "resultcode" tree with the ptrop and that number. */
+
+ if (result_targ_type != base_type)
+ {
+ tree elt_cnt;
+ gcc_assert (TREE_CODE (result_targ_type) == ARRAY_TYPE);
+ if (TREE_CODE (TYPE_SIZE (result_targ_type)) == INTEGER_CST)
+ {
+ tree n_threads = convert (sizetype, upc_num_threads ());
+ int size = TREE_INT_CST_LOW (TYPE_SIZE (result_targ_type));
+ int elt_size = TREE_INT_CST_LOW (TYPE_SIZE (base_type));
+ elt_cnt = size_int (size / elt_size);
+ if (TYPE_HAS_THREADS_FACTOR (result_targ_type))
+ elt_cnt = size_binop (MULT_EXPR, n_threads, elt_cnt);
+ }
+ else
+ {
+ tree size = TYPE_SIZE (result_targ_type);
+ tree elt_size = TYPE_SIZE (base_type);
+ elt_cnt = build2 (EXACT_DIV_EXPR, sizetype, size, elt_size);
+ }
+ intop = convert (sizetype, intop);
+ intop = size_binop (MULT_EXPR, intop, elt_cnt);
+ }
+ gcc_assert (resultcode == PLUS_EXPR || resultcode == MINUS_EXPR);
+ if (resultcode == MINUS_EXPR)
+ intop = build1 (NEGATE_EXPR, TREE_TYPE (intop), intop);
+ intop = fold (intop);
+
+ /* POINTER_PLUS expects the operand to be sizetype, which
+ is potentially unsigned. This will have to be dealt
+ with later, when expanding the UPC pointer-to-shared arithmetic. */
+
+ intop = convert (sizetype, intop);
+ result = build2 (POINTER_PLUS_EXPR, result_type, ptrop, intop);
+
+ /* Although there may be some specific cases where the
+ addition of a constant integer to a UPC pointer-to-shared can
+ be calculated at compile-time, in the more general
+ cases the calculation must be made at runtime, so
+ we mark the resulting sum as non-constant. This will
+ avoid situations where the compiler attempts to convert
+ things like &A[14] where A is a shared array into a
+ compile-time constant. */
+
+ TREE_CONSTANT (result) = 0;
+ return result;
+}
+
+/* Return an expression that calculates the difference between
+ two UPC pointers-to-shared values. */
+
+tree
+upc_pts_diff (tree op0, tree op1)
+{
+ const tree target_type = TREE_TYPE (TREE_TYPE (op0));
+ tree result;
+
+ /* The two pointers must both point to shared objects. */
+
+ if ((SHARED_TYPE_P (target_type)
+ && !SHARED_TYPE_P (TREE_TYPE (TREE_TYPE (op1))))
+ || (SHARED_TYPE_P (TREE_TYPE (TREE_TYPE (op1)))
+ && !SHARED_TYPE_P (target_type)))
+ {
+ error ("attempt to take the difference of a UPC pointer-to-shared "
+ "and a local pointer");
+ return size_one_node;
+ }
+ result = build2 (MINUS_EXPR, ptrdiff_type_node, op0, op1);
+ return result;
+}
+
+/* Return TRUE if EXP is a null UPC pointer-to-shared value.
+ (Call the representation-specific hook routine to
+ perform the check.) */
+
+int
+upc_is_null_pts_p (tree exp)
+{
+ return upc_pts_is_null_p (exp);
+}
+
+/* Return TRUE if the type of EXP is a UPC pointer-to-shared type. */
+
+int
+upc_pts_is_valid_p (tree exp)
+{
+ tree type = TREE_TYPE (exp);
+ return (TREE_CODE (type) == POINTER_TYPE)
+ && SHARED_TYPE_P (TREE_TYPE (type));
+}
===================================================================
@@ -0,0 +1,50 @@
+/* Definitions of UPC front-end entry points used for C and C++.
+ that are called from within the C front end.
+ respectively.
+ Copyright (C) 2001-2015 Free Software Foundation, Inc.
+ Contributed by Gary Funck <gary@intrepid.com>
+ and Nenad Vukicevic <nenad@intrepid.com>.
+
+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 2, 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 COPYING. If not, write to the Free
+Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301, USA. */
+
+#ifndef GCC_C_UPC_H
+#define GCC_C_UPC_H
+
+/* UPC-related functions called by the C front-end. */
+
+extern int count_upc_threads_refs (tree);
+extern int is_multiple_of_upc_threads (tree);
+extern void set_upc_threads_refs_to_one (tree *);
+extern tree upc_build_pointer_type (tree);
+extern tree upc_blocksizeof (location_t, tree);
+extern void upc_check_decl (tree);
+extern int upc_contains_pts_refs_p (tree);
+extern int upc_diagnose_deprecated_stmt (location_t, tree);
+extern tree upc_elemsizeof (location_t, tree);
+extern tree upc_grok_layout_qualifier (location_t, enum tree_code,
+ tree, tree, tree);
+extern int upc_is_null_pts_p (tree);
+extern tree upc_localsizeof (location_t, tree);
+extern tree upc_pts_diff (tree, tree);
+extern tree upc_pts_increment (location_t, enum tree_code, tree);
+extern tree upc_pts_int_sum (location_t, enum tree_code, tree, tree);
+extern int upc_pts_is_valid_p (tree);
+extern tree upc_rts_forall_depth_var (void);
+extern void upc_set_decl_section (tree);
+
+#endif /* ! GCC_C_UPC_H */