diff options
Diffstat (limited to 'gcc/c/c-upc-pts-ops.c')
-rw-r--r-- | gcc/c/c-upc-pts-ops.c | 655 |
1 files changed, 655 insertions, 0 deletions
diff --git a/gcc/c/c-upc-pts-ops.c b/gcc/c/c-upc-pts-ops.c new file mode 100644 index 00000000000..ca845ca7d3d --- /dev/null +++ b/gcc/c/c-upc-pts-ops.c @@ -0,0 +1,655 @@ +/* c-upc-pts-ops.c: implement UPC pointer-to-shared-operations. + Copyright (C) 2001-2016 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 "tm.h" +#include "tree.h" +#include "alias.h" +#include "fold-const.h" +#include "stringpool.h" +#include "stor-layout.h" +#include "c-tree.h" +#include "langhooks.h" +#include "gimplify.h" +#include "c-upc.h" +#include "c-family/c-upc-pts.h" +#include "c-upc-gasp.h" +#include "c-upc-pts-ops.h" +#include "c-upc-rts-names.h" + + +/* Build the internal representation of UPC's pointer-to-shared type. */ + +static void +upc_pts_init_type (void) +{ + tree fields = NULL_TREE; + tree name = NULL_TREE; + tree ref; + machine_mode pts_mode; + const location_t loc = UNKNOWN_LOCATION; + struct c_struct_parse_info *null_struct_parse_info = NULL; + int save_pedantic = pedantic; + ref = start_struct (loc, RECORD_TYPE, name, &null_struct_parse_info); + /* Ensure that shared pointers have twice the alignment of a pointer. */ + TYPE_ALIGN (ref) = 2 * TYPE_ALIGN (ptr_type_node); + TYPE_USER_ALIGN (ref) = 1; + name = get_identifier ("vaddr"); + upc_vaddr_field_node = build_decl (loc, FIELD_DECL, name, + build_pointer_type (char_type_node)); + fields = chainon (fields, upc_vaddr_field_node); + DECL_NONADDRESSABLE_P (upc_vaddr_field_node) = 0; + DECL_INITIAL (upc_vaddr_field_node) = NULL_TREE; + upc_thread_field_node = + build_decl (loc, FIELD_DECL, get_identifier ("thread"), + c_common_type_for_size (UPC_PTS_THREAD_SIZE, 1)); + fields = chainon (fields, upc_thread_field_node); + if (!(UPC_PTS_THREAD_SIZE % 8)) + { + DECL_NONADDRESSABLE_P (upc_thread_field_node) = 0; + DECL_INITIAL (upc_thread_field_node) = NULL_TREE; + } + else + { + DECL_NONADDRESSABLE_P (upc_thread_field_node) = 1; + DECL_INITIAL (upc_thread_field_node) = size_int (UPC_PTS_THREAD_SIZE); + } + upc_phase_field_node = + build_decl (loc, FIELD_DECL, get_identifier ("phase"), + c_common_type_for_size (UPC_PTS_PHASE_SIZE, 1)); + fields = chainon (fields, upc_phase_field_node); + if (!(UPC_PTS_PHASE_SIZE % 8)) + { + DECL_NONADDRESSABLE_P (upc_phase_field_node) = 0; + DECL_INITIAL (upc_phase_field_node) = NULL_TREE; + } + else + { + DECL_NONADDRESSABLE_P (upc_phase_field_node) = 1; + DECL_INITIAL (upc_phase_field_node) = size_int (UPC_PTS_PHASE_SIZE); + } + /* Avoid spurious complaints regarding the definition of + `phase' and `thread'. */ + pedantic = 0; + upc_pts_rep_type_node = finish_struct (loc, ref, fields, NULL_TREE, + null_struct_parse_info); + pedantic = save_pedantic; + gcc_assert (TYPE_SIZE (upc_pts_rep_type_node)); + gcc_assert (tree_fits_uhwi_p (TYPE_SIZE (upc_pts_rep_type_node))); + gcc_assert (tree_to_uhwi (TYPE_SIZE (upc_pts_rep_type_node)) + == 2 * POINTER_SIZE); + pts_mode = mode_for_size_tree (TYPE_SIZE (upc_pts_rep_type_node), + MODE_INT, 0); + gcc_assert (pts_mode != BLKmode); + SET_TYPE_MODE(upc_pts_rep_type_node, pts_mode); + record_builtin_type (RID_SHARED, "upc_shared_ptr_t", + upc_pts_rep_type_node); +} +/* Build the internal representation of UPC's pointer-to-shared type. */ + +void +upc_pts_init (void) +{ + tree shared_void_type, shared_char_type; + upc_pts_init_type (); + shared_void_type = c_build_qualified_type (void_type_node, + TYPE_QUAL_SHARED, + NULL_TREE); + upc_pts_type_node = build_pointer_type (shared_void_type); + shared_char_type = c_build_qualified_type (char_type_node, + TYPE_QUAL_SHARED, + size_zero_node); + upc_char_pts_type_node = build_pointer_type (shared_char_type); + upc_null_pts_node = upc_pts_build_value (UNKNOWN_LOCATION, + upc_pts_type_node, + integer_zero_node, + integer_zero_node, + integer_zero_node); +} + +/* Called to expand a UPC specific constant into something the + backend can handle. Upon return a UPC pointer-to-shared will be + seen as the representation type of a UPC pointer-to-shared, with + individual (thread, phase, and virtual address) fields. */ + +tree +upc_pts_build_constant (location_t loc, tree c) +{ + tree result = c; + if (upc_pts_is_valid_p (c)) + { + const enum tree_code code = TREE_CODE (c); + if (!((code == VIEW_CONVERT_EXPR || code == NOP_EXPR) + && (TREE_CODE (TREE_OPERAND (c, 0)) == CONSTRUCTOR) + && (TREE_TYPE (TREE_OPERAND (c, 0)) == upc_pts_rep_type_node))) + { + const tree val = build1 (VIEW_CONVERT_EXPR, upc_pts_rep_type_node, + save_expr (c)); + const tree p_t = TREE_TYPE (upc_phase_field_node); + const tree t_t = TREE_TYPE (upc_thread_field_node); + const tree v_t = TREE_TYPE (upc_vaddr_field_node); + const tree vaddr = build3 (COMPONENT_REF, v_t, val, + upc_vaddr_field_node, NULL_TREE); + const tree thread = build3 (COMPONENT_REF, t_t, val, + upc_thread_field_node, NULL_TREE); + const tree phase = build3 (COMPONENT_REF, p_t, val, + upc_phase_field_node, NULL_TREE); + result = upc_pts_build_value (loc, TREE_TYPE (c), + vaddr, thread, phase); + + } + } + return result; +} + +/* Build a constructor of the form {phase, thread, vaddr}. */ + +tree +upc_pts_build_value (location_t loc ATTRIBUTE_UNUSED, tree type, + tree vaddr, tree thread, tree phase) +{ + tree elts, result; + const int is_const = TREE_CONSTANT (vaddr) + && TREE_CONSTANT (thread) && TREE_CONSTANT (phase); + vaddr = fold_convert (TREE_TYPE (upc_vaddr_field_node), vaddr); + thread = fold_convert (TREE_TYPE (upc_thread_field_node), thread); + phase = fold_convert (TREE_TYPE (upc_phase_field_node), phase); + elts = tree_cons (upc_phase_field_node, phase, NULL_TREE); + elts = tree_cons (upc_thread_field_node, thread, elts); + elts = tree_cons (upc_vaddr_field_node, vaddr, elts); + result = build_constructor_from_list (upc_pts_rep_type_node, elts); + TREE_CONSTANT (result) = is_const; + + /* Wrap the constructor into the specified pointer to shared type. */ + result = build1 (VIEW_CONVERT_EXPR, type, result); + result = fold (result); + TREE_CONSTANT (result) = is_const; + /* Force all shared constant pointer values to memory. */ + TREE_STATIC (result) = is_const; + return result; +} + +/* Return TRUE if EXP is a null UPC pointer-to-shared. */ + +int +upc_pts_is_null_p (tree exp) +{ + int result = 0; + if (exp && upc_pts_is_valid_p (exp)) + { + tree value; + for (value = exp; + TREE_CODE (value) == NOP_EXPR + || TREE_CODE (value) == CONVERT_EXPR + || TREE_CODE (value) == VIEW_CONVERT_EXPR + || TREE_CODE (value) == NON_LVALUE_EXPR; + value = TREE_OPERAND (value, 0)) /* loop */ ; + if ((TREE_CODE (value) == CONSTRUCTOR) + && (TREE_TYPE (value) == upc_pts_rep_type_node) + && TREE_CONSTANT (value)) + { + vec<constructor_elt, va_gc> *c = CONSTRUCTOR_ELTS (value); + /* Check that all the fields are zero, independent + of whether vaddr comes first/last. */ + const tree phase_or_vaddr = (*c)[0].value; + const tree thread = (*c)[1].value; + const tree vaddr_or_phase = (*c)[2].value; + result = integer_zerop (phase_or_vaddr) && integer_zerop (thread) + && integer_zerop (vaddr_or_phase); + } + } + return result; +} + +/* Given, EXP, whose type must be the UPC pointer-to-shared + representation type, isolate the thread field, + and return it. Caller must insure that EXP is a + stable reference, if required. */ + +tree +upc_pts_build_threadof (location_t loc ATTRIBUTE_UNUSED, tree exp) +{ + tree affinity; + tree type = TREE_TYPE (upc_thread_field_node); + gcc_assert (TREE_TYPE (exp) == upc_pts_rep_type_node); + affinity = build3 (COMPONENT_REF, type, exp, + upc_thread_field_node, NULL_TREE); + affinity = fold_convert (sizetype, affinity); + return affinity; +} + +/* Rewrite EXP, an expression involving addition of an + integer to a UPC pointer-to-shared, into representation-specific + lower level operations. */ + +tree +upc_pts_build_sum (location_t loc, tree exp) +{ + const tree op0 = TREE_OPERAND (exp, 0); + const tree op1 = TREE_OPERAND (exp, 1); + const enum tree_code op0_code = TREE_CODE (TREE_TYPE (op0)); + const tree targ_type = TREE_TYPE (TREE_TYPE (exp)); + const tree elem_type = strip_array_types (targ_type); + const tree elem_size = !VOID_TYPE_P (elem_type) + ? size_in_bytes (elem_type) : integer_one_node; + const tree block_factor = get_block_factor (elem_type); + const int has_phase = !(integer_zerop (block_factor) + || integer_onep (block_factor)); + const tree elem_per_block = block_factor; + const tree ptrop = (op0_code == POINTER_TYPE) ? op0 : op1; + const tree intop = (op0_code == POINTER_TYPE) ? op1 : op0; + const tree index = save_expr (intop); + const tree ptrop_as_pts_rep = fold (build1 (VIEW_CONVERT_EXPR, + upc_pts_rep_type_node, + ptrop)); + const tree sptrop = save_expr (ptrop_as_pts_rep); + const tree p_t = TREE_TYPE (upc_phase_field_node); + const tree t_t = TREE_TYPE (upc_thread_field_node); + const tree v_t = TREE_TYPE (upc_vaddr_field_node); + tree n_threads = upc_num_threads (); + tree old_phase, old_thread, old_vaddr; + tree phase, thread, vaddr; + tree tincr, t1, t2; + tree result; + + old_phase = build3 (COMPONENT_REF, p_t, sptrop, + upc_phase_field_node, NULL_TREE); + old_thread = build3 (COMPONENT_REF, t_t, sptrop, + upc_thread_field_node, NULL_TREE); + old_vaddr = build3 (COMPONENT_REF, v_t, sptrop, + upc_vaddr_field_node, NULL_TREE); + thread = old_thread; + phase = old_phase; + if (VOID_TYPE_P (targ_type) || integer_zerop (block_factor)) + { + vaddr = build_binary_op (loc, PLUS_EXPR, old_vaddr, + build_binary_op (loc, MULT_EXPR, + index, elem_size, 0), 0); + } + else + { + /* Make sure n_threads is a signed integer to ensure + that the FLOOR_MOD and FLOOR_DIV operations below are performed + with signed operations. */ + if (TYPE_UNSIGNED (TREE_TYPE (n_threads))) + n_threads = convert (integer_type_node, n_threads); + if (has_phase) + { + tree nt_elems; + tree phase_diff; + old_phase = save_expr (old_phase); + /* tincr = old_thread * elem_per_block + old_phase + index; */ + tincr = build_binary_op (loc, PLUS_EXPR, + build_binary_op (loc, PLUS_EXPR, + build_binary_op (loc, MULT_EXPR, + old_thread, elem_per_block, 0), + old_phase, 0), + index, 0); + if (TYPE_UNSIGNED (TREE_TYPE (tincr))) + tincr = convert (integer_type_node, tincr); + /* nt_elems = n_threads * elem_per_block; */ + nt_elems = build_binary_op (loc, MULT_EXPR, n_threads, + elem_per_block, 0); + if (TYPE_UNSIGNED (TREE_TYPE (nt_elems))) + nt_elems = convert (integer_type_node, nt_elems); + /* floor_divmod (tincr, nt_elems, &t1, &t2); */ + t1 = build_binary_op (loc, FLOOR_DIV_EXPR, tincr, nt_elems, 0); + t2 = build_binary_op (loc, FLOOR_MOD_EXPR, tincr, nt_elems, 0); + t2 = save_expr (t2); + /* thread = t2 / elem_per_block; */ + thread = build_binary_op (loc, TRUNC_DIV_EXPR, t2, + elem_per_block, 0); + /* phase = t2 % elem_per_block; */ + phase = build_binary_op (loc, TRUNC_MOD_EXPR, t2, + elem_per_block, 0); + phase_diff = + build_binary_op (loc, MINUS_EXPR, phase, old_phase, 0); + /* vaddr = old_vaddr + (t1 * elem_per_block + phase_diff) + * elem_size; */ + vaddr = build_binary_op (loc, PLUS_EXPR, + old_vaddr, + build_binary_op (loc, MULT_EXPR, + build_binary_op (loc, PLUS_EXPR, + build_binary_op (loc, MULT_EXPR, + t1, elem_per_block, 0), + phase_diff, 0), + elem_size, 0), 0); + } + else + { + /* tincr = old_thread * elem_per_block + index; */ + tincr = build_binary_op (loc, PLUS_EXPR, + build_binary_op (loc, MULT_EXPR, + old_thread, + elem_per_block, 0), + index, 0); + if (TYPE_UNSIGNED (TREE_TYPE (tincr))) + tincr = convert (integer_type_node, tincr); + /* floor_divmod (tincr, n_threads, &t1, &t2); */ + t1 = build_binary_op (loc, FLOOR_DIV_EXPR, tincr, n_threads, 0); + t2 = build_binary_op (loc, FLOOR_MOD_EXPR, tincr, n_threads, 0); + /* vaddr = old_vaddr + t1 * elem_size; */ + vaddr = build_binary_op (loc, PLUS_EXPR, old_vaddr, + build_binary_op (loc, MULT_EXPR, t1, + elem_size, 0), 0); + /* thread = t2; */ + thread = t2; + } + } + result = + upc_pts_build_value (loc, TREE_TYPE (exp), vaddr, thread, phase); + return result; +} + +/* Expand the expression EXP, which calculates the difference + between two UPC pointers-to-shared. */ + +tree +upc_pts_build_diff (location_t loc, tree exp) +{ + tree op0 = TREE_OPERAND (exp, 0); + tree op1 = TREE_OPERAND (exp, 1); + const tree result_type = ptrdiff_type_node; + const tree p_t = TREE_TYPE (upc_phase_field_node); + const tree t_t = TREE_TYPE (upc_thread_field_node); + const tree v_t = TREE_TYPE (upc_vaddr_field_node); + const tree target_type = TREE_TYPE (TREE_TYPE (op0)); + const tree n_threads = upc_num_threads (); + const tree elem_size = convert (ssizetype, size_in_bytes (target_type)); + const tree block_factor = get_block_factor (target_type); + tree thread0, thread1, thread_diff; + tree phase_diff; + tree off0, off1, offset_diff, elem_diff; + tree result; + + /* The two pointers must both point to shared objects, and we + have to perform the reverse of addition on UPC pointers-to-shared */ + + 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_at (loc, "attempt to take the difference of a UPC " + "pointer-to-shared and a local pointer"); + return error_mark_node; + } + op0 = save_expr (op0); + op1 = save_expr (op1); + op0 = build1 (VIEW_CONVERT_EXPR, upc_pts_rep_type_node, op0); + op1 = build1 (VIEW_CONVERT_EXPR, upc_pts_rep_type_node, op1); + off0 = build3 (COMPONENT_REF, v_t, op0, upc_vaddr_field_node, NULL_TREE); + off1 = build3 (COMPONENT_REF, v_t, op1, upc_vaddr_field_node, NULL_TREE); + /* Convert offset fields into ptrdiff_t types so that the + result of the difference comes out as a signed type. */ + off0 = convert (result_type, off0); + off1 = convert (result_type, off1); + offset_diff = build_binary_op (loc, MINUS_EXPR, off0, off1, 0); + elem_diff = + build_binary_op (loc, EXACT_DIV_EXPR, offset_diff, elem_size, 0); + if (integer_zerop (block_factor)) + { + return elem_diff; + } + thread0 = convert (ssizetype, + build3 (COMPONENT_REF, t_t, op0, + upc_thread_field_node, NULL_TREE)); + thread1 = convert (ssizetype, + build3 (COMPONENT_REF, t_t, op1, + upc_thread_field_node, NULL_TREE)); + thread_diff = build_binary_op (loc, MINUS_EXPR, thread0, thread1, 0); + phase_diff = integer_zero_node; + if (!tree_int_cst_equal (block_factor, integer_one_node)) + { + tree phase0 = convert (ssizetype, + build3 (COMPONENT_REF, p_t, op0, + upc_phase_field_node, NULL_TREE)); + tree phase1 = convert (ssizetype, + build3 (COMPONENT_REF, p_t, op1, + upc_phase_field_node, NULL_TREE)); + phase_diff = + save_expr (build_binary_op (loc, MINUS_EXPR, phase0, phase1, 0)); + } + /* The expression below calculates the following: + (elem_diff - phase_diff) * THREADS + + (thread_diff * block_factor) + phase_diff; */ + result = build_binary_op (loc, PLUS_EXPR, + build_binary_op (loc, PLUS_EXPR, + build_binary_op (loc, MULT_EXPR, + build_binary_op (loc, MINUS_EXPR, + elem_diff, phase_diff, 0), + n_threads, 0), + build_binary_op (loc, MULT_EXPR, + thread_diff, + block_factor, 0), 0), + phase_diff, 0); + result = fold_convert (result_type, result); + return result; +} + +/* Handle conversions between UPC pointers-to-shared and + local pointers, or between UPC pointers-to-shared which + have differing block factors. */ + +tree +upc_pts_build_cvt (location_t loc, tree exp) +{ + const tree type = TREE_TYPE (exp); + const tree p_t = ptr_type_node; + const tree t_t = TREE_TYPE (upc_thread_field_node); + const tree ptr = TREE_OPERAND (exp, 0); + tree tt1, tt2, b1, b2; + tree result = exp; + + tt1 = TREE_TYPE (TREE_TYPE (exp)); + tt2 = TREE_TYPE (TREE_TYPE (TREE_OPERAND (exp, 0))); + b1 = get_block_factor (tt1); + b2 = get_block_factor (tt2); + if (SHARED_TYPE_P (tt1) != SHARED_TYPE_P (tt2)) + { + if (SHARED_TYPE_P (tt1)) + { + /* Error: local -> shared */ + result = error_mark_node; + } + else + { + /* shared -> local */ + int doprofcall = flag_upc_debug + || (flag_upc_instrument && get_upc_pupc_mode ()); + const char *libfunc_name = + doprofcall ? UPC_GETADDRG_LIBCALL : UPC_GETADDR_LIBCALL; + tree src = build1 (NOP_EXPR, upc_pts_rep_type_node, + TREE_OPERAND (exp, 0)); + tree libfunc, lib_args, lib_call; + libfunc = identifier_global_value (get_identifier (libfunc_name)); + if (!libfunc) + internal_error ("UPC runtime library function %s not found", + libfunc_name); + lib_args = tree_cons (NULL_TREE, src, NULL_TREE); + if (doprofcall) + lib_args = + upc_gasp_add_src_args (lib_args, + LOCATION_FILE (input_location), + LOCATION_LINE (input_location)); + lib_call = build_function_call (loc, libfunc, lib_args); + result = build1 (VIEW_CONVERT_EXPR, type, lib_call); + } + } + else if ((SHARED_TYPE_P (tt1) && !VOID_TYPE_P (tt1)) + && !(integer_zerop (b1) && integer_zerop (b2))) + { + /* below, we handle the case of conversions to non-generic + shared types. If the target is a generic type, we can + safely use the source value directly. */ + tree s1 = TYPE_SIZE (tt1); + tree s2 = TYPE_SIZE (tt2); + /* normalize block sizes, so that [0] => NULL */ + if (integer_zerop (b1)) + b1 = NULL; + if (integer_zerop (b2)) + b2 = NULL; + /* normalize type size so that 0 => NULL */ + if (s1 && integer_zerop (s1)) + s1 = NULL; + if (s2 && integer_zerop (s2)) + s2 = NULL; + /* If the source type is an array type, then bypass + the check for equal type sizes. This arises when + an array is implicitly converted to a pointer to + the element type. */ + if ((TREE_CODE (tt1) != ARRAY_TYPE) + && (TREE_CODE (tt2) == ARRAY_TYPE)) + { + const tree elem_type1 = strip_array_types (tt1); + const tree elem_type2 = strip_array_types (tt2); + if (TYPE_MAIN_VARIANT (elem_type1) + == TYPE_MAIN_VARIANT (elem_type2)) + s2 = s1; + } + /* If the source type is a not a generic pointer to shared, and + either its block size or type size differs from the target, + then the result must have zero phase. If the source type is + a generic pointer to shared and the target type is a pointer + to a shared type with either an indefinite block size, or + a block size of one, then the resulting value must have a + phase of zero. */ + if ((!VOID_TYPE_P (tt2) + && !(tree_int_cst_equal (b1, b2) && tree_int_cst_equal (s1, s2))) + || (VOID_TYPE_P (tt2) + && ((b1 == NULL) + || tree_int_cst_equal (b1, integer_one_node)))) + { + const tree ptr_as_pts_rep = fold (build1 (VIEW_CONVERT_EXPR, + upc_pts_rep_type_node, + ptr)); + const tree sptr = save_expr (ptr_as_pts_rep); + const tree ptr_with_zero_phase = + upc_pts_build_value (loc, type, + build3 (COMPONENT_REF, p_t, sptr, + upc_vaddr_field_node, + NULL_TREE), + build3 (COMPONENT_REF, t_t, sptr, + upc_thread_field_node, + NULL_TREE), + integer_zero_node); + result = ptr_with_zero_phase; + } + } + return result; +} + + +/* Expand the expression EXP, which is a comparison between two + UPC pointers-to-shared. + + Per 6.4.2p6: + Two compatible pointers-to-shared which point to the same object + (i.e. having the same address and thread components) shall compare + as equal according to == and !=, regardless of whether the phase + components match. + + Thus, for the equality comparison, the phase component of the + pointers is omitted from the comparison. In that case, + rewrite the pointer-to-shared comparison operation into a + field by field comparison the vaddr and thread fields + of the UPC pointer-to-shared operands. + + If the bit-wise comparison cannot be performed, then the difference + between the pointers is compared to zero. */ + +tree +upc_pts_build_cond_expr (location_t loc, tree exp) +{ + tree result; + const enum tree_code code = TREE_CODE (exp); + const int is_eq_op = (code == EQ_EXPR || code == NE_EXPR); + tree op0 = TREE_OPERAND (exp, 0); + tree op1 = TREE_OPERAND (exp, 1); + const tree type0 = TREE_TYPE (op0); + const tree type1 = TREE_TYPE (op1); + gcc_assert (POINTER_TYPE_P (type0)); + gcc_assert (POINTER_TYPE_P (type1)); + { + const tree ttype0 = TREE_TYPE (type0); + const tree ttype1 = TREE_TYPE (type1); + const tree elem_type0 = strip_array_types (ttype0); + const tree elem_type1 = strip_array_types (ttype1); + gcc_assert (TREE_SHARED (elem_type0)); + gcc_assert (TREE_SHARED (elem_type1)); + /* For == and !=, per 6.4.2p6 only compare (vaddr, thread). */ + if (is_eq_op) + { + const tree t_t = TREE_TYPE (upc_thread_field_node); + const tree v_t = TREE_TYPE (upc_vaddr_field_node); + const enum tree_code code0 = TREE_CODE (op0); + const enum tree_code code1 = TREE_CODE (op1); + const enum tree_code tcode = (code == EQ_EXPR) + ? TRUTH_ANDIF_EXPR : TRUTH_ORIF_EXPR; + if (code0 == VIEW_CONVERT_EXPR + && TREE_TYPE (TREE_OPERAND (op0, 0)) == upc_pts_rep_type_node) + op0 = TREE_OPERAND (op0, 0); + else + op0 = build1 (VIEW_CONVERT_EXPR, upc_pts_rep_type_node, op0); + if (code1 == VIEW_CONVERT_EXPR + && TREE_TYPE (TREE_OPERAND (op1, 0)) == upc_pts_rep_type_node) + op1 = TREE_OPERAND (op1, 0); + else + op1 = build1 (VIEW_CONVERT_EXPR, upc_pts_rep_type_node, op1); + op0 = save_expr (op0); + op1 = save_expr (op1); + { + const tree off0 = build3 (COMPONENT_REF, v_t, op0, + upc_vaddr_field_node, NULL_TREE); + const tree off1 = build3 (COMPONENT_REF, v_t, op1, + upc_vaddr_field_node, NULL_TREE); + const tree off_cmp = build_binary_op (loc, code, off0, off1, 0); + const tree thread0 = build3 (COMPONENT_REF, t_t, op0, + upc_thread_field_node, NULL_TREE); + const tree thread1 = build3 (COMPONENT_REF, t_t, op1, + upc_thread_field_node, NULL_TREE); + const tree thread_cmp = + build_binary_op (loc, code, thread0, thread1, 0); + result = build_binary_op (loc, tcode, off_cmp, thread_cmp, 0); + /* Remove possible C_MAYBE_EXPR operands. */ + result = c_fully_fold (result, 0, NULL); + result = gimple_boolify (result); + result = fold_convert (TREE_TYPE (exp), result); + } + } + else + { + const tree ptr_diff = + build_binary_op (loc, MINUS_EXPR, op0, op1, 0); + op0 = ptr_diff; + op1 = build_int_cst (TREE_TYPE (op0), 0); + TREE_OPERAND (exp, 0) = op0; + TREE_OPERAND (exp, 1) = op1; + result = exp; + } + } + return result; +} |