Either deprecate or strengthen upc_addrfield()

Issue #107 new
Former user created an issue

Originally reported on Google Code with ID 107

Steve's comment, split off from issue 106:

Consider the following code:

shared int *S1;
shared [] int *S2;

S2 = S1;

if ( upc_addrfield(S1) == upc_addrfield(S2) ) {
    printf("Match\n");
}

With the proposed change (as well as UPC 1.2 apparently), it is undefined whether or
not anything is printed.  We don't require anywhere that pointers-to-shared with different
types that point to the same object produce the same result when passed to upc_addrfield(),
merely that such pointers shall compare equal.  Since I don't think this is intended,
we probably need a stronger statement somewhere to make upc_addrfield() useful.

Reported by danbonachea on 2013-02-27 11:06:44

Comments (97)

  1. Former user Account Deleted
    The current semantics of upc_addrfield() (unchanged since UPC 1.0, Feb 2001):
    
      The upc_addrfield function returns an implementation-defined value reflecting
      the local address of the object pointed to by the pointer-to-shared
      argument.
      footnote: This function is used in defining the semantics of pointer-to-shared  
    
                arithmetic in Section 6.4.2
    
    
    This has been in place unchanged for 12 years now without complaint. In my experience
    the function itself has very limited utility in real programs, outside of printing
    pointer values for debugging (which should probably be handled in a better way). Strengthening
    the requirement in any way has the potential to render current implementations non-compliant
    with very little pay-off, so I don't think we should try to "squeeze" in a change in
    the next three days to make 1.3. 
    
    Placing it on the 1.4 milestone.
    

    Reported by danbonachea on 2013-02-27 11:32:11 - Labels added: Milestone-Spec-1.4

  2. Former user Account Deleted
    The code fragment in comment #0 calls upc_addrfield on an uninitialized pointer value.
    Lets assume they are statically allocated and not automatic variables, as the latter
    would be a case of garbage-in-garbage-out. S1 and S2 are thus initialized to null pointers
    which are then passed to the function. (Incidentally the assignment is also missing
    a required cast).
    
    Nothing in the specification defines the behavior of upc_addrfield(NULL). We could
    consider strengthening this, but I don't really see a problem with leaving it implementation-defined,
    since it's a rather silly thing for the user to do in the first place.
    
    The example I think Steve MEANT to provide was one where S1 and S2 point at an actual
    object, as below. I've also modified one of the pointers types to include phase information
    to make it more interesting.
    
    Example A:
    ----------
    #include <upc.h>
    #include <stdio.h>
    
    shared int x;
    int main() {
      shared int *S1 = &x;
      shared [10] int *S2 = (shared [10] int *)S1;
    
      if ( upc_addrfield(S1) == upc_addrfield(S2) ) printf("Match\n");
    
      if ( upc_addrfield(S1) == upc_addrfield(S1) ) printf("Match\n");
    
      return 0;
    }
    
    So the question at hand is whether upc_addrfield is guaranteed to return the same result
    when passed a pointer to the same location. For the moment lets ignore the fact the
    user could/should just use a direct pointer equality operator to test PTS equality.
    I don't think the type of the actual argument matters at all in this discussion, because
    standard call conversion will automatically convert any argument to (shared void *)
    before the library function ever sees it. The same behavioral question arises when
    you pass the exact same argument twice, as in my second test above.
    
    I believe that for "free-standing" objects that are not part of an array (as above),
    the return value is currently completely implementation-defined (which by the way differs
    from "undefined", in that implementations are required to document their behavior).
    This means a perverse implementation could potentially return a different value on
    each call with the same pointer to a free-standing object. We could consider adding
    stronger requirements here, but I don't really see a motivation to do so. There are
    better ways to test pointer equality, and the addrfield of the pointer to such an object
    is essentially a useless piece of information.
    
    Now lets consider upc_addrfield() called on pointers to shared array elements. Assume
    the shared array contains at least two elements with local affinity, otherwise it's
    essentially equivalent to the "free-standing object" case above. 
    
    Example B:
    ----------
    #include <upc.h>
    #include <stdio.h>
    
    shared int A[2*THREADS];
    int main() {
      shared int *S1 = &A[MYTHREAD];         // an element with affinity to MYTHREAD
      shared int *S2 = &A[MYTHREAD+THREADS]; // any other element with affinity to MYTHREAD
      int *P1 = (int *)S1;
      int *P2 = (int *)S2;
    
      ptrdiff_t S1addr = (ptrdiff_t) upc_addrfield(S1);
      ptrdiff_t S2addr = (ptrdiff_t) upc_addrfield(S2);
    
      if ((S2addr - S1addr) == (P2 - P1)*sizeof(int)) printf("Correct.\n"); // directly
    required by 6.4.2
    
      if (S2addr == S1addr + (P2 - P1)*sizeof(int)) printf("Correct.\n"); // same equation,
    mathematically transformed
    
      if ((ptrdiff_t) upc_addrfield(S2) == S1addr + (P2 - P1)*sizeof(int)) printf("Correct.\n");
    // duplicate call to upc_addrfield
    
      return 0;
    }
    
    This example is closely modeled on 6.4.2 to clarify my argument. 
    The first test is exactly the requirement imposed by 6.4.2, and must pass on all compliant
    implementations. 
    The second test is mathematically identical, I've just added S1addr to both sides of
    the equation and applied standard algebraic simplification. Thus it also must succeed
    in all compliant implementations.
    The third test introduces a second "duplicate" call to upc_addrfield(S2), to test the
    case Steve is worried about that might return a different answer. However by the equation
    in the second test, the required return value is already completely constrained by
    the requirements of 6.4.2. Returning a different value on the second call to upc_addrfield(S2)
    would thus be non-compliant.
    

    Reported by danbonachea on 2013-02-27 12:15:14

  3. Former user Account Deleted
    > The example I think Steve MEANT to provide was one where S1 and S2 point at an actual
    object, as below. I've also modified one of the pointers types to include phase information
    to make it more interesting.
    
    My code fragment was meant to mimic the code fragment in 6.4.2 5.
    
    > I don't think the type of the actual argument matters at all in this discussion,
    because standard call conversion will automatically convert any argument to (shared
    void *) before the library function ever sees it. The same behavioral question arises
    when you pass the exact same argument twice, as in my second test above.
    
    Not necessarily.  Nothing prohibits encoding the type in the representation of the
    shared pointer itself (perhaps to have a scaled offset internally and/or much better
    run-time warnings/errors) and preserving the type info when casting to a generic pointer-to-shared.
    
    > This means a perverse implementation could potentially return a different value on
    each call with the same pointer to a free-standing object. We could consider adding
    stronger requirements here, but I don't really see a motivation to do so. There are
    better ways to test pointer equality, and the addrfield of the pointer to such an object
    is essentially a useless piece of information.
    
    The strongest motivation I see is that upc_addrfield()+upc_threadof() is the only way
    to print the address of a shared object.  Requiring that all pointers to the same object
    get the same result from upc_addrfield() means that users can easily and usefully print
    the upc_addrfield()+upc_threadof() combination when debugging.
    
    > This example is closely modeled on 6.4.2 to clarify my argument. 
    
    And therein lies the problem.  We've ONLY define upc_addrfield() for pointers whose
    referenced type has block size 1 (block size 0 with the proposed fix for issue 106).
     Consider the following slightly different code:
    
    #include <upc.h>
    #include <stdio.h>
    
    shared [2] int A[2*THREADS];
    int main() {
      shared int *S1 = &A[2*MYTHREAD];   // an element with affinity to MYTHREAD
      shared int *S2 = &A[2*MYTHREAD+1]; // any other element with affinity to MYTHREAD
    
      shared [2] int *SB1 = &A[2*MYTHREAD];
      shared [2] int *SB2 = &A[2*MYTHREAD+1];
    
      int *P1 = (int *)S1;
      int *P2 = (int *)S2;
    
      int *PB2 = (int *)S1_1;
      int *PB2 = (int *)S2_1;
    
      ptrdiff_t S1addr = (ptrdiff_t) upc_addrfield(S1);
      ptrdiff_t S2addr = (ptrdiff_t) upc_addrfield(S2);
    
      ptrdiff_t SB1addr = (ptrdiff_t) upc_addrfield(SB1);
      ptrdiff_t SB2addr = (ptrdiff_t) upc_addrfield(SB2);
    
      if ((S2addr - S1addr) == (P2 - P1)*sizeof(int)) printf("Correct.\n"); // directly
    required by 6.4.2
    
      if (S2addr == S1addr + (P2 - P1)*sizeof(int)) printf("Correct.\n"); // same equation,
    mathematically transformed
    
      if ((ptrdiff_t) upc_addrfield(S2) == S1addr + (P2 - P1)*sizeof(int)) printf("Correct.\n");
    // duplicate call to upc_addrfield
    
    
      if ((S2addr - S1addr) == (P2 - P1)*sizeof(int)) printf("Correct?\n"); // directly
    required by 6.4.2? NO
    
      if (S2addr == S1addr + (P2 - P1)*sizeof(int)) printf("Correct?\n"); // same equation,
    mathematically transformed
    
      if ((ptrdiff_t) upc_addrfield(S2) == S1addr + (P2 - P1)*sizeof(int)) printf("Correct?\n");
    // duplicate call to upc_addrfield
    
      return 0;
    }
    
    Because we use an example with a fixed block size in 6.4.2 5-6, as opposed to something
    similar to 6.4.2 3-4, the results of upc_addrfield() are only constrained for pointers
    whose referenced type has that single block size.  In the code above, clearly the S1addr
    and S2addr are constrained by 6.4.2 4.  But what about SB1addr and SB2addr?  The spec
    does not currently place ANY constraints on their values.
    

    Reported by sdvormwa@cray.com on 2013-02-27 14:37:29

  4. Former user Account Deleted
    >The strongest motivation I see is that upc_addrfield()+upc_threadof() is the only way
    
    > to print the address of a shared object. ..print the upc_addrfield()+upc_threadof()
    
    >combination when debugging.
    
    Yes, this is the debugging motivation I was referring to in comment #1. However upc_addrfield
    is rather poorly designed to suit that purpose, so if that's the only usage case we
    can come up with to motivate the existence of this library function, I'd vote to deprecate
    it and replace it with a function that is better designed for debugging pointer values
    and formatting them for human consumption, akin to C99's printf("%p"). 
    For a concrete example, see http://upc.lbl.gov/docs/user/index.shtml#bupc_dump_shared
    
    > Because we use an example with a fixed block size in 6.4.2 5-6, as opposed to something
    similar to 6.4.2 3-4, the results of 
    > upc_addrfield() are only constrained for pointers whose referenced type has that
    single block size.  
    
    upc_addrfield() is a library function, not a built-in operator. Its actual argument
    is converted by C99 function calling rules to a (shared void *) before it ever reaches
    the function. Despite being implicit, this is an ACTUAL type conversion - (shared void
    *) is an incomplete type, but it is an actual static type, with NO associated blocking
    factor. We have some magic clauses in UPC to ensure the phase field is preserved when
    you cast back and forth to (shared void *), but otherwise the blocksize really and
    truly is gone from the type. A more explicit (but unnecessarily redundant) way to write
    the call in 6.4.2 would be upc_addrfield((shared void *)S1), but whether you write
    it explicitly or not, that's what the call MEANS and the language requires that conversion
    to happen prior to function entry. The function receives an argument value whose referenced
    type is incomplete and has NO blocksize.
    
    Saying the behavior of the function could change based on the static referent type
    of the pointer operand before argument conversion is like saying the behavior of C99
    free() might change based on whether you pass it a (char *) or an (int *). In both
    cases this information was lost upon implicit conversion to (void *) and is simply
    is not available to the callee as far as the language spec is concerned. Therefore,
    specifying a behavioral property using a particular PTS blocking factor in 6.4.2 automatically
    constrains the behavior for any PTS blocking factor.
    
    The fact that some hypothetical implementation might include static type information
    in the pointer representation does not change the fact that SEMANTICALLY that information
    was lost upon type conversion.
    

    Reported by danbonachea on 2013-02-27 15:54:51

  5. Former user Account Deleted
    > Yes, this is the debugging motivation I was referring to in comment #1. However upc_addrfield
    is rather poorly designed to suit that purpose, so if that's the only usage case we
    can come up with to motivate the existence of this library function, I'd vote to deprecate
    it and replace it with a function that is better designed for debugging pointer values
    and formatting them for human consumption, akin to C99's printf("%p").
    
    I agree that upc_addrfield() is poorly designed.  As far as I can tell, it can't be
    usefully used for anything but debugging.
    
    > The fact that some hypothetical implementation might include static type information
    in the pointer representation does not change the fact that SEMANTICALLY that information
    was lost upon type conversion.
    
    True, the type information was lost on conversion.  But that doesn't mean that two
    pointers-to-shared with different referenced types that point to the same object produce
    the same value when converted to a generic pointer-to-shared.  The only constraint
    is that the resulting values shall compare equal.  As you noted, the phase may differ.
     I argue that nothing prohibits the results of upc_addrfield() from differing as well.
    
    As currently defined, upc_addrfield() is useless to UPC programers.  It's return value
    is implementation defined and practically unconstrained.  It's not guaranteed to produce
    the same result on all threads when passed the same pointer.  The single constraint
    on it is defined only for a single block size.  So why is it in the spec?
    

    Reported by sdvormwa@cray.com on 2013-02-27 16:18:29

  6. Former user Account Deleted
    > So why is it in the spec?
    
    It predates my involvement, but I suspect it was introduced for symmetry with upc_threadof()
    and upc_phaseof() to "expose" the third logical component of a PTS. The original UPC
    implementation on the T3e used a PTS representation where the addrfield was equal to
    an actual virtual address, so upc_addrfield was interchangeable with cast-to-local.
    Subsequent revisions of the language made the pointer representation more opaque to
    allow for alternate implementation strategies, and the function was never removed.
    
    Perhaps Bill or Kathy can provide further insight..
    
    > As currently defined, upc_addrfield() is useless to UPC programers.  It's return
    value is 
    > implementation defined and practically unconstrained.  
    
    I think we agree it's useless for production codes and a poorly-designed tool for debugging.
    So instead of quibbling about the degree to which the result is or should be implementation-defined,
    I propose we talk about deprecating it entirely and possibly replacing it with a better
    debugging aid.
    
    As a starting point for discussion, here is the pseudo-spec for the BUPC vendor-specific
    replacement: (http://upc.lbl.gov/docs/user/index.shtml#bupc_dump_shared)
    
    ----------------------------------------------
    The 'bupc_dump_shared' function
    Shared pointers in UPC are logically composed of three fields: the address of the data
    that the shared pointer currently points to, the UPC thread on which that address is
    valid, and the 'phase' of the shared pointer (see the official UPC language specification
    for an explanation of shared pointer phase). Our version of UPC provides a 'bupc_dump_shared'
    function that will write a description of these fields into a character buffer that
    the user provides:
    
        int bupc_dump_shared(shared const void *ptr, char *buf, int maxlen);
    
    Any pointer to a shared type may be passed to this function. The 'maxlen' parameter
    gives the length of the buffer pointed to by 'buf', and this length must be at least
    BUPC_DUMP_MIN_LENGTH, or else -1 is returned, and errno set to EINVAL. On success,
    the function returns 0, The buffer will contain either "<NULL>" if the pointer to shared
    == NULL, or a string of the form
    
        "<address=0x1234 (addrfield=0x1234), thread=4, phase=1>" 
    
    The 'address' field provides the virtual address for the pointer, while the 'addrfield'
    contains the actual contents of the shared pointer's address bits. On some configurations
    these values may be the same (if the full address of the pointer can be fit into the
    address bits), while on others they may be quite different (if the address bits store
    an offset from a base initial address that may differ from thread to thread).
    
    Both bupc_dump_shared() and BUPC_DUMP_MIN_LENGTH are visible when any of the standard
    UPC headers (upc.h, upc_relaxed.h, or upc_strict.h) are #included. 
    

    Reported by danbonachea on 2013-02-27 16:47:21

  7. Former user Account Deleted
    > I think we agree it's useless for production codes and a poorly-designed tool for
    debugging. So instead of quibbling about the degree to which the result is or should
    be implementation-defined, I propose we talk about deprecating it entirely and possibly
    replacing it with a better debugging aid.
    
    Sounds reasonable.  As part of the deprecation, I'd recommend removing it from 6.4.2
    6.  I suspect it was originally put there to try to imply the contiguity property that
    is the subject of issue 106.  With the new language in that comment, I don't know that
    there's a need for it any more, given the lack of any other constraints on upc_addrfield().
    

    Reported by sdvormwa@cray.com on 2013-02-27 16:54:16

  8. Former user Account Deleted
    > So why is it in the spec?
    
    upc_addrfield is useful primarily for debugging and writing test cases for pointer
    arithmetic.  The test case that Steve uploaded for the pointer to array of shared issue
    would have been very difficult to write without upc_addrfield, but as written the test
    may not be portable given the underspecification of upc_addrfield.
    
    I'll leave it to UPC historians to explain exactly why upc_addrfield exists, but I
    suspect when it was introduced no one wanted the alternatives -- to add something to
    the UPC spec that required implementers to modify their libc printf to support a %P
    (or whatever letter) for a pointer-to-shared or to provide a upc_printf wrapper around
    printf.  I also suspect it felt odd to have upc_threadof and upc_phaseof but not have
    any mechanism to access the value of the remaining field; however the address is implementation-specific
    information whereas the thread or phase are not.
    
    We (too) frequently have users attempt this code:
    
        shared int* ptr;
        ...
        printf( "%p", ptr );
    
    which does not do what they expect (on our current systems, but used to work on older
    Crays).  The conforming alternative, given that upc_threadof and upc_phaseof return
    a size_t for which there is no format specifier, is the verbose:
    
        printf( "%lu %lu %p", (unsigned long)upc_threadof( ptr ), (unsigned long)upc_phaseof(
    ptr ),
                upc_addrfield( ptr ) );
    
    I'm sure they'd much rather be able to do this:
    
        upc_printf( "%P", ptr );
    
    and I think that would cover all user code that I've seen for upc_addrfield, but the
    output format would need to be implementation-defined and the printed address value
    would be just as unspecified as the current upc_addrfield return value.  I'm not sure
    it would be an improvement for implementers given that there would be a whole family
    of printf functions to wrap, but it may be an improvement for users.
    

    Reported by johnson.troy.a on 2013-02-27 17:00:16

  9. Former user Account Deleted
    Responding to this item from comment #8:
    > given that upc_threadof and upc_phaseof return a size_t for which there is no format
    specifier,
    
    Sure there is: the "z" length modifier (e.g. "%zd", "%zu", "%zx", etc) which was added
    in C99.
    
    And Yes, I agree that extending the printf formats to have one for PTS would be nice,
    but it may be hard for some vendors.  Berkeley, for instance, is at the mercy of somebody
    else's libc. Only when using glibc do we have register_printf_function().
    

    Reported by phhargrove@lbl.gov on 2013-02-27 18:54:03

  10. Former user Account Deleted
    upc_addrfield was devised when the expectation was that a UPC implementation of a pointer-to-shared
    actually would be a structure with three fields for thread, phase, and addr (and possibly
    other fields).  Thus, while addr was assumed not to be an actual address, it was assumed
    to act like an address and, more important, be used in a manner similar to an address
    in the actual implementation.  The behavior of upc_addrfield was not so much a description
    of the values returned by a function, but rather a set of directives for how to implement
    pointers-to-shared and how to do pointer arithmetic, behavior that was verified by
    extracting the values out of the structure using the decomposition functions.
    
    When the conception of a pointer-to-shared was broadened and the definitions of the
    pointer decomposition functions loosened to allow them to be calculated rather than
    extractions of actual portions of the representation of the pointer value, upc_addrfield
    lost its usefulness.
    

    Reported by brian.wibecan on 2013-02-27 19:03:54

  11. Former user Account Deleted
    While I never tried it, I have always imagined that if I was going to hash a PTS value,
    that I would use upc_addrfield().  If we remove this function, what is the recommended
    way to generate hashes from a PTS?
    
    We can't cast to int (or long, uintptr_t, etc) because we agreed in issue #11 that
    this has implementation-defined behavior (might always be 0xdeadbeef), and casts to
    local pointers are only defined when performed by the thread with affinity.
    
    So, unless somebody can point out an alternative way to get "bits" suitable for generating
    hash values from a PTS, I vote to KEEP upc_addrfield (adding any necessary constraints
    such as a value that is independent of calling thread).
    

    Reported by phhargrove@lbl.gov on 2013-02-27 19:04:34

  12. Former user Account Deleted
    Ah, I missed the 'z' option in the man page.  Thanks for pointing that out.
    
    Hashing without upc_addrfield is not a problem.  Many hash functions operate by churning
    through each byte of data in turn, so one could apply that idea to a PTS via:
    
        shared int* p;
        long my_hash( char* bytes, size_t nbytes );
    
        long hash_value = my_hash( (char*)&p, sizeof( p ) );
    

    Reported by johnson.troy.a on 2013-02-27 19:07:56

  13. Former user Account Deleted
    "Hashing without upc_addrfield is not a problem.  Many hash functions operate by churning
    through each byte of data in turn, so one could apply that idea to a PTS"
    
    That assumes that two different threads or two different contexts have the same data
    representation of a pointer value.  I don't believe that's required.  I think Paul
    is suggesting a hash mechanism that uses information guaranteed to be the same for
    the same pointer value in all contexts.
    

    Reported by brian.wibecan on 2013-02-27 19:26:15

  14. Former user Account Deleted
    Troy wrote in comment #14:
    > Hashing without upc_addrfield is not a problem.  Many hash functions operate by
    > churning through each byte of data in turn[....]
    
    We all agreed (issue #73) that phase is ignored in pointer comparison. So, hashing
    on the bytes that comprise the PTS representation might not yield the same hash for
    two pointers to the same object (which is one of the properties I would probably require).
    
    ADDITIONALLY, if the PTS representation has any "padding" that could vary between two
    pointers to the same object this byte-wise hashing would still fail the uniqueness
    constraint.  I believe that possibility eliminates the possibility of using upc_resetphase()
    to get around the objection I have in the previous paragraph.  The end-user would have
    no mechanism to "mask" the padding since they (should) know nothing of the internal
    representation.
    

    Reported by phhargrove@lbl.gov on 2013-02-27 19:27:35

  15. Former user Account Deleted
    While it is on my mind, here my thoughts on upc_addrfield() if it is to be useful for
    something like generating hashes.  I believe it also provides the properties desirable
    for debugging (no "false positives" from properly applied tests for equality) though
    that property is debatable (noted below)/
    
    Properties I *do* expect:
    + Caller-independent
      For a given PTS p0, the value of upc_addrfield(p0) should not depend
      on the calling thread
    + Object-specific
      Given two PTS p1 and p2 that compare equal, their upc_addrfield() must
      also be equal.  Using "->" as "implies":
         (p1 == p2) -> (upc_addrfield(p1) == upc_addrfield(p2))
    + Byte-oriented within an object
      Given two PTS, p3 and p4, to portions of a SINGLE object with affinity
      to the SAME thread, the following is true on the thread with affinity:
        (upc_addrfield(p3) - upc_addrfield(p4)) == ((uint8_t*)(p3) - (uint8_t*)(p4))
      [except that size_t vs. ptrdiff_t might need a cast?]
    + Per-thread uniqueness (debatable: constrains per-thread heap to SIZE_MAX)
      Given PTS p5 and p6 with affinity to the SAME thread, the upc_addfield()
      values are equal ONLY IF p5 and p6 compare equal:
        (upc_addrfield(p5) == upc_addrfield(p6)) &&
                (upc_threadof(p5) == upc_threadof(p6))  ->  (p5 == p6)
    
    These are "natural" for all reasonable PTS representations, including those that may
    encode "segment:offset" as bitfields in the addrfield (same object must have same segment,
    but distinct objects could have distinct segments) in which there is no single "flat"
    or "linear" space for the shared heap of a given thread.
    
    Properties I do NOT expect:
    + Global uniqueness
      Equality of upc_addrfield() does NOT imply anything when their threads differ
    + Constraint on PTS to distinct objects
      Other than per-thread uniqueness, there is no constraint on the upc_addrfield()
      values for two PTS with the same (or different) affinity.  This is just the
      same as C pointer subtraction using pointers to different objects - undefined.
      This is a requirement to permit the "segment:offset" sort of encoding.
    
    A note on the "debatable" point:
    The "per-thread uniqueness" property is a desirable property for debugging, but I don't
    think it is essential to other applications such as hashing.  This property would not
    normally be a problem, except that upc_addrfield() returns size_t.  In the C99 spec
    it is clear that size_t is intended to be large enough to encode the size of a single
    OBJECT, but nowhere is it stated that the size of the entire "heap" must fit in size_t.
     IN FACT, NEC (or is that Cray?) SX-6 had 64-bit pointers but 32-bit size_t.  So, for
    the RARE platform that had a "narrow" size_t the per-thread uniqueness of upc_addrfield()
    would constrain the per-thread shared heap size to SIZE_MAX.  I really doubt that is
    a problem for anyone (and vaguely recall some other issue in the tracker dismissing
    such a concern), but wanted to note this for completeness.
    

    Reported by phhargrove@lbl.gov on 2013-02-27 22:21:15

  16. Former user Account Deleted
    I am changing the description to reflect the current lack of consensus.
    
    Until/unless somebody can offer a portable hash function on PTS (without use of addrfield)
    that has at least the first 2 properties in my previous comment (caller-independent
    and object-specific), I am going to remain in "strengthen" camp.
    

    Reported by phhargrove@lbl.gov on 2013-02-27 23:04:12

  17. Former user Account Deleted
    For the hash function, could you cast the PTS to a shared [] char* and then subtract
    a NULL pointer from it to get an address value?  I have not tried this yet but just
    thought of it.
    

    Reported by johnson.troy.a on 2013-02-28 02:32:17

  18. Former user Account Deleted
    Troy suggests:
    > could you cast the PTS to a shared [] char* and then subtract
    > a NULL pointer from it to get an address value? 
    
    My initial response is that this suggestion runs afoul of the undefined nature of PTS
    subtraction when the pointers are not part of the same object.  However, it is the
    best alternative I've heard so far.
    

    Reported by phhargrove@lbl.gov on 2013-02-28 02:35:27

  19. Former user Account Deleted
    > My initial response is that this suggestion runs afoul of the undefined
    > nature of PTS subtraction when the pointers are not part of the same object.
    
    Right, C pointer subtraction rules would make it undefined, so the UPC spec would need
    to define it if we wanted to make that strategy portable.  I tried it with Cray UPC
    and these two printfs produce the same output:
    
    #include <stdio.h>
    #include "upc.h"
    
    shared int x;
    
    int main( int argc, char* argv[] )
    {
        shared int* p = &x;
    
        printf( "%zu\n", upc_addrfield( p ) );
    
        printf( "%tu\n", (shared [] char*)p - (shared [] char*)NULL );
    
        return 0;
    }
    
    If someone has an implementation for which these printfs would produce different output,
    I'd be interested in hearing why.
    

    Reported by johnson.troy.a on 2013-02-28 06:36:19

  20. Former user Account Deleted
    >    printf( "%tu\n", (shared [] char*)p - (shared [] char*)NULL );
    >
    > If someone has an implementation for which these printfs would produce different
    
    > output, I'd be interested in hearing why.
    
    In addition to violating C99's rule about pointer subtraction between pointers to separate
    objects, this also runs afoul of the UPC PTS subtraction semantics:
    
      the result is undefined unless there exists an integer x, representable
      as a ptrdiff t, such that (pts1 + x) == pts2 AND upc phaseof(pts1 +
      x) == upc phaseof(pts2). In this case (pts2 - pts1) evaluates to x.
    
    When *p has affinity to a non-zero thread, there may not be a value of x that you can
    add to NULL to get p. An implementation would be well within its rights to detect this
    as a fatal error. Barring that, the result of the subtraction would depend on the implementation-specific
    details of PTS NULL and the pointer representation.
    

    Reported by danbonachea on 2013-02-28 08:47:06

  21. Former user Account Deleted
    Dan, everything you wrote in Comment #22 is true, but I'm asking if any implementation
    actually does treat this as a fatal error, not if they could in theory.  Paul's looking
    for some way to write a hash function without upc_addrfield().  If we were to deprecate
    upc_addrfield() but define PTS - NULL for indefinite block size, that would leave a
    mechanism for writing his hash function.  If any current implementation treats PTS
    - NULL as a fatal error, then it's a bit harder for us to make a change that defines
    PTS - NULL.  I'm simply trying to gauge how such a change would affect current implementations.
    
    Defining addition pointer subtraction semantics is not without precedent -- C++03 defines
    a null pointer minus a null pointer to be 0 for example, whereas C leaves it undefined.
     UPC could similarly define PTS - NULL.  (We could also define a null PTS minus a null
    PTS to be 0 too, if we had reason.)
    

    Reported by johnson.troy.a on 2013-02-28 15:53:23

  22. Former user Account Deleted
    > I'm asking if any implementation actually does treat this as a fatal error, not if
    they could in theory. 
    
    BUPC DOES detect such a subtraction as a fatal error at runtime in debug mode, when
    the pointer argument has non-zero affinity. There are two possible errors based on
    how exactly the test is written and constant-folded in the frontend:
    
    UPC Runtime error: Illegal: subtraction of indefinite pointers with affinity to different
    UPC threads (7 and 0)
     at: issue107e_obj.c:78
    
    UPC Runtime error: Assertion failure at _upcr_pshared_to_local() at /usr/common/ftg/upc/2.16.0/bupc-2.16.0-icc-12.1.3/runtime/inst/dbg/include/upcr_sptr.h:689:
    upcr_isnull_pshared(sptr) || upcr_threadof_pshared(sptr) == upcr_mythread()
     at: issue107d_obj.c:76
    
    Paul's usage case of PTS hashing has changed my mind on this issue - I think generating
    an appropriate hash for a PTS is sufficiently problematic and dependent on implementation-details
    that it should probably be encapsulated as a library function to allow portable hashing.
    Strengthening upc_addrfield() to fill that need (as suggested in comment #17) seems
    reasonable and in keeping with the "spirit" of the original (ie "an implementation-defined
    value reflecting the “local address” of the object"), and also compatible with the
    other known usage case of printing PTS values for debugging.
    

    Reported by danbonachea on 2013-02-28 16:34:35

  23. Former user Account Deleted
    Thanks Dan, the BUPC example answers my question.
    
    A library function for generating a PTS hash may be problematic for two reasons.  Such
    a function would need to accept a shared void*, so if one wanted to hash based on all
    three parts of a PTS, not just the thread and addrfield, it's not possible because
    the phase is thrown away.  Second, and probably more importantly, hash functions are
    chosen carefully for performance reasons depending on what a specific application needs.
     Trying to provide a one-size-fits-all hash function for everyone via a upc_hash( shared
    void* ) function may be pointless because everyone will ignore it and write their own.
    
    Strengthening upc_addrfield() enough to allow people to write their own hash function
    sounds better to me.
    

    Reported by johnson.troy.a on 2013-02-28 17:14:13

  24. Former user Account Deleted
    Ignore my first reason in Comment #25.  Steve corrected me that shared void* preserves
    phase; I had forgotten that.
    

    Reported by johnson.troy.a on 2013-02-28 17:31:10

  25. Former user Account Deleted
    >  Trying to provide a one-size-fits-all hash function for everyone via a upc_hash(
    
    > shared void* ) function may be pointless because everyone will ignore it and write
    
    > their own.
    
    Apologies, my comment #24 was a bit unclear. What I meant was:
     "Generating an appropriate (value to be used in computing) a hash for a PTS is sufficiently
    problematic and dependent on implementation-details that it should probably be encapsulated
    as a library function to allow portable hashing."
    
    I think Paul was not suggesting to write the actual hashing function (ie the one that
    maps a data value to a bucket) but merely the utility that provides an appropriately
    unique integral value representing the object address, with the guarantees he suggests.
    There is currently no portable way to get such a value from a PTS, which implies there
    is no portable way to hash a PTS. The user is the one who hashes the return value to
    compute an actual bucket, and can choose to fold in additional information such as
    the result of upc_phaseof()/upc_threadof() as seems fit for his application.
    
    > Strengthening upc_addrfield() enough to allow people to write their own hash function
    sounds better to me.
    
    I'm pretty sure that's what Paul is proposing in comment #17.
    

    Reported by danbonachea on 2013-02-28 17:40:25

  26. Former user Account Deleted
    >> Strengthening upc_addrfield() enough to allow people to write their
    >> own hash function sounds better to me.
    > 
    > I'm pretty sure that's what Paul is proposing in comment #17.
    
    Exactly. I don't want a upc_hash_pts(), I just want upc_addrfield() to become well-defined
    enough that one can do something like the following:
    
      h = my_hash(upc_addrfield(p)) // good if p has known affinity
      h = my_hash(upc_addrfield(p) ^ upc_threadof(p))  // better when affinity may vary
    
    Additionally, upc_addrfield() would retain its usefulness for debugging (and writing
    of spec conformance tests).
    

    Reported by phhargrove@lbl.gov on 2013-02-28 18:37:43

  27. Former user Account Deleted
    I propose the following change.  I believe it strengthens upc_addrfield() sufficiently
    to satisfy all of Paul's concerns.
    
    Index: lang/upc-lib-core.tex
    ===================================================================
    --- lang/upc-lib-core.tex       (revision 205)
    +++ lang/upc-lib-core.tex       (working copy)
    @@ -302,11 +302,27 @@
    
     \np The {\tt upc\_addrfield} function returns an
        implementation-defined value reflecting the ``local address'' of the
    -   object pointed to by the pointer-to-shared argument.\footnote{%
    -   This function is used in defining the semantics of pointer-to-shared
    -   arithmetic in Section \ref{pointer-arithmetic}}
    +   object pointed to by the pointer-to-shared argument.
    +
    +\np \xadded[id=SV]{107}{The return value of {\tt upc\_addrfield} shall be
    +   independent of the calling thread.}
    
    -
    +\np \xadded[id=SV]{107}{If two pointers-to-shared compare equal, then they
    +   shall produce the same value when passed to {\tt upc\_addrfield}.  If two
    +   pointers-to-shared do not compare equal, they may still produce the same
    +   value when passed to {\tt upc\_addrfield}, but only if they point to shared
    +   objects with affinity to different threads.}
    +
    +\np \xadded[id=SV]{107}{If two pointers-to-shared {\tt S1} and {\tt S2} point
    +   to distinct bytes of the same shared object which have affinity to the same
    +   thread, then the expression\\*
    +   {\tt ((ptrdiff\_t) upc\_addrfield(S2) - (ptrdiff\_t) upc\_addrfield(S1))}\\*
    +   shall evaluate on all threads to the same value that\\*
    +   {\tt ((char *)S2 - (char *)S1)}\\*
    +   evalutes to on the thread with which the pointed-to bytes have affinity.}
    +
    +\xchangenote[id=SV]{107}{Constraints moved from 6.4.2 and cross-reference footnote
    removed.}
    +
     \paragraph{The {\tt upc\_affinitysize} function}
    
     {\bf Synopsis}
    Index: lang/upc-language.tex
    ===================================================================
    --- lang/upc-language.tex       (revision 205)
    +++ lang/upc-language.tex       (working copy)
    @@ -303,9 +303,8 @@
     \begin{itemize}
     \item S1 and P1 shall point to the same object.
     \item S2 and P2 shall point to the same object.
    -\item The expression (({\tt (ptrdiff\_t) upc\_addrfield} (S2) -  {\tt (ptrdiff\_t)
    upc\_addrfield(S1))} shall
    -   evaluate to the same value as ((P2 - P1) * sizeof(T)).
     \end{itemize}
    +\xchangenote[id=SV]{107}{Constraint on {\tt upc\_addrfield} strengthened and moved
    to Section~\ref{upc_addrfield}.}
    
     \np Two compatible pointers-to-shared which point to the same
         object (i.e. having the same address and thread components) shall
    

    Reported by sdvormwa@cray.com on 2013-02-28 19:25:28

  28. Former user Account Deleted
    Comment on Paul's list in #17:
    
    > Properties I do NOT expect:
    > + Global uniqueness
    >   Equality of upc_addrfield() does NOT imply anything when their threads differ
    
    Huh.  I would have sworn it was required that, for a declaration like
    
      shared T A[THREADS];
    
    that upc_addrfield(&A[i]) would yield the same value for all 0 <= i < THREADS.  But
    no, it's not there.  That makes upc_addrfield even less useful.  It was certainly the
    original expectation.
    

    Reported by brian.wibecan on 2013-02-28 19:39:50

  29. Former user Account Deleted
    Brian,
    
    While your stated/desired property in comment #30 is true for MANY implementations
    of statically declared variables it is STILL incorrect to infer that (upc_addrfield(p)
    == upc_addrfield(q)) implies that p and q point to the same array.  For instance, if
    p and q were dynamically allocated by upc_alloc().  Thus even if your stated property
    was true, my statement about no "global uniqueness" would remain true.
    
    Currently, nothing constrains implementations to have a "symmetric heap" property for
    static allocations.  This property WAS the case for the T3E, and is likely to still
    be true of most implementations because it is just simpler to deal with.  George or
    Yili may correct me if I have this wrong, but I believe the BG/L implementation of
    UPC lacked a symmetric heap and communicated "on the wire" in terms of some sort of
    GUID (or handle) and (since that was not a RDMA network) the code at the target node
    would perform translation/table-lookup, performing lazy allocation if the handle had
    not been seen before.
    
    Note that an implementation could have a symmetric heap and still not satisfy your
    expectation if the heaps are offset across nodes and upc_addrfield() returns the full
    virtual address (though that could be "fixed" by returning the offset-within-heap).
    
    So, YES, upc_addrfield() is less useful than some may have thought.
    

    Reported by phhargrove@lbl.gov on 2013-02-28 19:59:58

  30. Former user Account Deleted
    Brian, the requirement that upc_addrfield( &A[i] ) yield the same value for all threads
    for shared T A[THREADS] would be too strong.  If you have UPC purely inside a shared
    memory environment, the entire array could be laid out in the same virtual memory space
    such that every A[i] is at a different address and the implementation could be using
    those locations for the result of upc_addrfield().  There are also non shared memory
    systems unfortunate enough to have had address layout randomization enabled such that
    true symmetric addressing is made quite painful.
    

    Reported by johnson.troy.a on 2013-02-28 20:04:01

  31. Former user Account Deleted
    I endorse the intent and scope of Steve's proposed change in comment #29, but anticipate
    we'll want to refine the wording slightly.  I think Dan is best qualified to take a
    shot at that.
    
    Since Steve mostly reworded my "prose", I am "too close" to the text to be an impartial
    editor.  However, I'll make a few comments:
    
    + The constraint beginning "If two pointers-to-shared compare equal" should probably
    split in two, making one point at a time to make each one stronger.
    
    + Assuming the split suggested in my previous bullet, the "If two pointers-to-shared
    do not compare equal" half probably needs rewording - it just feels "clumsy" to me
    as written now.  I would avoid phrases like "but only if" which can be hard to understand,
    when we have the formal "implies" at our disposal.  The following is a "forward" version:
       ((p != q) && (upc_addrfield(p) == upc_addrfield(q)))
                             -> (upc_threadof(p) != upc_threadof(q))    
    
    + "distinct bytes" doesn't seem necessary in the last constraint, as the expressions
    both evaluate to zero if the PTS reference the same byte.
    
    
    I am "neutral" on the question of 1.3 vs. 1.4 except the the extent that I think resolving
    issues 106 and 107 in the SAME spec seems likely to produce the best results.
    

    Reported by phhargrove@lbl.gov on 2013-02-28 20:19:33

  32. Former user Account Deleted
    I just noticed the change to 6.4.2 made by the diff in comment #29.
    Such a change leaves constraint paragraphs 4 and 5 of 6.4.2 essentially pointless.
    They become all "setup" with no "punchline", because the remaining statements that
    taken pairwise (P1,S1) and (P2,S2) address the same objects is not of any consequence
    in defining address arithmetic.
    
    Steve, is it correct to assume you "yield" to Dan's change at the same location made
    by comment #61 of issue 106 (below)?
    
    -\item The expression (({\tt (ptrdiff\_t) upc\_addrfield} (S2) -  {\tt (ptrdiff\_t)
    upc\_addrfield(S1))} shall 
    -   evaluate to the same value as ((P2 - P1) * sizeof(T)).  
    +\xadded[id=DB]{106}{
    +\item The expression {\tt P1 + (S2 - S1) == P2} shall evaluate to 1.%
    +\truefootnote{This implies there is no padding inserted between blocks of shared array
    elements with affinity to a thread.}
    +}
    

    Reported by phhargrove@lbl.gov on 2013-02-28 20:39:20

  33. Former user Account Deleted
    > Steve, is it correct to assume you "yield" to Dan's change at the same location made
    by comment #61 of issue 106 (below)?
    
    Yes.  I actually like Dan's change--I just think that it is incomplete without also
    fixing upc_addrfield().
    
    An updated proposal taking into account Paul's comments in comment 33.
    
    Index: lang/upc-lib-core.tex
    ===================================================================
    --- lang/upc-lib-core.tex       (revision 205)
    +++ lang/upc-lib-core.tex       (working copy)
    @@ -302,11 +302,30 @@
    
     \np The {\tt upc\_addrfield} function returns an
        implementation-defined value reflecting the ``local address'' of the
    -   object pointed to by the pointer-to-shared argument.\footnote{%
    -   This function is used in defining the semantics of pointer-to-shared
    -   arithmetic in Section \ref{pointer-arithmetic}}
    +   object pointed to by the pointer-to-shared argument.
    +
    +\np \xadded[id=SV]{107}{The return value of {\tt upc\_addrfield} shall be
    +   independent of the calling thread.}
    
    -
    +\np \xadded[id=SV]{107}{If two pointers-to-shared point to bytes with affinity
    +   to the same thread, then the values resulting from passing them to
    +   {\tt upc\_addrfield} shall compare equal if and only if the pointers
    +   themselves compare equal.}
    +
    +\np \xadded[id=SV]{107}{If two pointers-to-shared {\tt S1} and {\tt S2} point
    +   to bytes with affinity to the same thread that are part of a single shared
    +   object, then the expression\\*
    +   {\tt ((ptrdiff\_t) upc\_addrfield(S2) - (ptrdiff\_t) upc\_addrfield(S1))}\\*
    +   shall evaluate on all threads to the same value that\\*
    +   {\tt ((char *)S2 - (char *)S1)}\\*
    +   evalutes to on the thread with which the pointed-to bytes have affinity.}
    +
    +\np \xadded[id=SV]{107}{If two pointers-to-shared point to bytes with affinity
    +   to different threads, then the result of comparing the values resulting
    +   from passing them to {\tt upc\_addrfield} is undefined.}
    +
    +\xchangenote[id=SV]{107}{Constraints moved from 6.4.2 and cross-reference footnote
    removed.}
    +
     \paragraph{The {\tt upc\_affinitysize} function}
    
     {\bf Synopsis}
    Index: lang/upc-language.tex
    ===================================================================
    --- lang/upc-language.tex       (revision 205)
    +++ lang/upc-language.tex       (working copy)
    @@ -303,9 +303,8 @@
     \begin{itemize}
     \item S1 and P1 shall point to the same object.
     \item S2 and P2 shall point to the same object.
    -\item The expression (({\tt (ptrdiff\_t) upc\_addrfield} (S2) -  {\tt (ptrdiff\_t)
    upc\_addrfield(S1))} shall
    -   evaluate to the same value as ((P2 - P1) * sizeof(T)).
     \end{itemize}
    +\xchangenote[id=SV]{107}{Constraint on {\tt upc\_addrfield} strengthened and moved
    to Section~\ref{upc_addrfield}.}
    
     \np Two compatible pointers-to-shared which point to the same
         object (i.e. having the same address and thread components) shall
    

    Reported by sdvormwa@cray.com on 2013-02-28 20:44:28

  34. Former user Account Deleted
    +\np \xadded[id=SV]{107}{If two pointers-to-shared compare equal, then they
    +   shall produce the same value when passed to {\tt upc\_addrfield}.  If two
    +   pointers-to-shared do not compare equal, they may still produce the same
    +   value when passed to {\tt upc\_addrfield}, but only if they point to shared
    +   objects with affinity to different threads.}
    
    The last clause of this paragraph specifies the "debatable" property from Paul's comment
    #17. I find that constraint unacceptable for the same reasons Paul listed - specifically,
    C99 does not guarantee size_t is large enough to contain a local address value (nor
    is it ever used for that purpose in C99 - size_t is for object sizes, (u)intptr_t are
    the integral types for containing address values). The function return type of size_t
    is not sufficient to guarantee every pointer-to-shared can be uniquely represented
    on every system, even when only considering pointers to objects with affinity a single
    thread. Consequently such a library specification could undesirably constrain the available
    shared memory on some systems.
    
    As Paul mentioned, the hashing usage case does not require this property. However if
    we want the property for other usage cases, then I think we must change the return
    type of upc_addrfield to ensure the result type is "wide enough" to uniquely represent
    any local pointer. Note that ptrdiff_t is also not guaranteed to be wide enough for
    this purpose (in fact C99 allows it to be smaller than size_t!). The most natural choice
    for a "wide-enough" return type would be uintptr_t or intptr_t - unfortunately these
    are designated as an OPTIONAL type in C99 (and also C11). To my knowledge these types
    are available on all systems of interest, as the architectural hardware to support
    them is usually the same as that used to support pointer arithmetic. UPC already requires
    a great many additional types and features relative to C99, so making that optional
    type mandatory for a compliant UPC implementation does not seem overly burdensome to
    implementers. A different concern is the effect on existing clients of upc_addrfield
    of changing the return value - although if we truly believe that's currently a small
    set then perhaps that minor break in backwards compatibility is acceptable.
    
    Of course the other option to changing the return type is to weaken the constraint
    and allow "false duplicates" in the return value.
    

    Reported by danbonachea on 2013-02-28 20:46:18

  35. Former user Account Deleted
    Our comments passed in the ether. My comment #36 applies equally to the new proposed
    paragraph:
    
    +\np \xadded[id=SV]{107}{If two pointers-to-shared point to bytes with affinity
    +   to the same thread, then the values resulting from passing them to
    +   {\tt upc\_addrfield} shall compare equal if and only if the pointers
    +   themselves compare equal.}
    

    Reported by danbonachea on 2013-02-28 20:49:59

  36. Former user Account Deleted
    I also object to this proposed text:
    
    +\np \xadded[id=SV]{107}{If two pointers-to-shared point to bytes with affinity
    +   to different threads, then the result of comparing the values resulting
    +   from passing them to {\tt upc\_addrfield} is undefined.}
    
    The return value of the function is already "implementation-defined" by default in
    paragraph 1. Subsequent paragraphs in the proposal further constrain this value. But
    the constraint above essentially implies that a comparison operator using two values
    returned by the function can have undefined behavior (ie crash the program, launch
    the nukes), which is way too strong. I believe it's sufficient to delete this paragraph
    and leave the "implementation-defined" default from paragraph 1 in force for that case.
    If we feel it's necessary to amplify this point, it should be reformulated as "unspecified
    behavior", and written in a generic way that is not specific to a particular arithmetic
    operator.
    

    Reported by danbonachea on 2013-02-28 21:00:40

  37. Former user Account Deleted
    How about the following, borrowing from the C99 definition of [u]intptr_t:
    
    Index: lang/upc-lib-core.tex
    ===================================================================
    --- lang/upc-lib-core.tex       (revision 205)
    +++ lang/upc-lib-core.tex       (working copy)
    @@ -302,11 +302,37 @@
    
     \np The {\tt upc\_addrfield} function returns an
        implementation-defined value reflecting the ``local address'' of the
    -   object pointed to by the pointer-to-shared argument.\footnote{%
    -   This function is used in defining the semantics of pointer-to-shared
    -   arithmetic in Section \ref{pointer-arithmetic}}
    +   object pointed to by the pointer-to-shared argument.
    +
    +\np \xadded[id=SV]{107}{The return value of {\tt upc\_addrfield} shall be
    +   independent of the calling thread.}
    
    -
    +\np \xadded[id=SV]{107}{If two pointers-to-shared point to bytes with affinity
    +   to the same thread, then the values resulting from passing them to
    +   {\tt upc\_addrfield} shall compare equal if the pointers themselves compare
    +   equal.}
    +
    +\np \xadded[id=SV]{107}{If {\tt size\_t} has the property that any valid
    +   pointer to {\tt void} can be converted to it, then converted back and
    +   compare equal to the original pointer, then the results of passing
    +   two pointers-to-shared that point to bytes with affinity to the same thread
    +   to {\tt upc\_addrfield} shall compare equal only if the pointers themselves
    +   compare equal.}
    +
    +\np \xadded[id=SV]{107}{If two pointers-to-shared {\tt S1} and {\tt S2} point
    +   to bytes with affinity to the same thread that are part of a single shared
    +   object, then the expression\\*
    +   {\tt ((ptrdiff\_t) upc\_addrfield(S2) - (ptrdiff\_t) upc\_addrfield(S1))}\\*
    +   shall evaluate on all threads to the same value that\\*
    +   {\tt ((char *)S2 - (char *)S1)}\\*
    +   evalutes to on the thread with which the pointed-to bytes have affinity.}
    +
    +\np \xadded[id=SV]{107}{If two pointers-to-shared point to bytes with affinity
    +   to different threads, then the result of comparing the values resulting
    +   from passing them to {\tt upc\_addrfield} is undefined.}
    +
    +\xchangenote[id=SV]{107}{Constraints moved from 6.4.2 and cross-reference footnote
    removed.}
    +
     \paragraph{The {\tt upc\_affinitysize} function}
    
     {\bf Synopsis}
    Index: lang/upc-language.tex
    ===================================================================
    --- lang/upc-language.tex       (revision 205)
    +++ lang/upc-language.tex       (working copy)
    @@ -303,9 +303,8 @@
     \begin{itemize}
     \item S1 and P1 shall point to the same object.
     \item S2 and P2 shall point to the same object.
    -\item The expression (({\tt (ptrdiff\_t) upc\_addrfield} (S2) -  {\tt (ptrdiff\_t)
    upc\_addrfield(S1))} shall
    -   evaluate to the same value as ((P2 - P1) * sizeof(T)).
     \end{itemize}
    +\xchangenote[id=SV]{107}{Constraint on {\tt upc\_addrfield} strengthened and moved
    to Section~\ref{upc_addrfield}.}
    
     \np Two compatible pointers-to-shared which point to the same
         object (i.e. having the same address and thread components) shall
    

    Reported by sdvormwa@cray.com on 2013-02-28 21:03:48

  38. Former user Account Deleted
    Re: Dan's argument against per-thread uniqueness.
    
    Since Steve's agreement to the current proposal for issue #106 is conditional on resolving
    this issue (#107), I'd like to propose a two-stage approach:
    
    1) To publish 1.3 without a lengthy debate on the "per-thread uniqueness" property,
    I suggest that Steve adjust the proposed text to EXCLUDE this property.
    
    2) That for 1.4 we engage in the debate that will include the possibility of widening
    the return type to allow this property to be satisfied (FWIW, I don't see how one could
    implement a UPC runtime without having a [u]intptr_t in the base C compiler).
    
    Unless I am missing something, adding this constraint in 1.4 cannot break anything
    EXCEPT issues related (directly or indirectly) to the return type.  If that is incorrect,
    then we'll have to hash this out sooner rather than later.
    

    Reported by phhargrove@lbl.gov on 2013-02-28 21:04:47

  39. Former user Account Deleted
    > The return value of the function is already "implementation-defined" by default in
    paragraph 1. Subsequent paragraphs in the proposal further constrain this value. But
    the constraint above essentially implies that a comparison operator using two values
    returned by the function can have undefined behavior (ie crash the program, launch
    the nukes), which is way too strong. I believe it's sufficient to delete this paragraph
    and leave the "implementation-defined" default from paragraph 1 in force for that case.
    If we feel it's necessary to amplify this point, it should be reformulated as "unspecified
    behavior", and written in a generic way that is not specific to a particular arithmetic
    operator.
    
    This is true.  I'll remove it in the next diff.
    

    Reported by sdvormwa@cray.com on 2013-02-28 21:07:19

  40. Former user Account Deleted
    Removing the paragraph about undefined results:
    
    Index: lang/upc-lib-core.tex
    ===================================================================
    --- lang/upc-lib-core.tex       (revision 205)
    +++ lang/upc-lib-core.tex       (working copy)
    @@ -302,11 +302,33 @@
    
     \np The {\tt upc\_addrfield} function returns an
        implementation-defined value reflecting the ``local address'' of the
    -   object pointed to by the pointer-to-shared argument.\footnote{%
    -   This function is used in defining the semantics of pointer-to-shared
    -   arithmetic in Section \ref{pointer-arithmetic}}
    +   object pointed to by the pointer-to-shared argument.
    +
    +\np \xadded[id=SV]{107}{The return value of {\tt upc\_addrfield} shall be
    +   independent of the calling thread.}
    
    -
    +\np \xadded[id=SV]{107}{If two pointers-to-shared point to bytes with affinity
    +   to the same thread, then the values resulting from passing them to
    +   {\tt upc\_addrfield} shall compare equal if the pointers themselves compare
    +   equal.}
    +
    +\np \xadded[id=SV]{107}{If {\tt size\_t} has the property that any valid
    +   pointer to {\tt void} can be converted to it, then converted back and
    +   compare equal to the original pointer, then the results of passing
    +   two pointers-to-shared that point to bytes with affinity to the same thread
    +   to {\tt upc\_addrfield} shall compare equal only if the pointers themselves
    +   compare equal.}
    +
    +\np \xadded[id=SV]{107}{If two pointers-to-shared {\tt S1} and {\tt S2} point
    +   to bytes with affinity to the same thread that are part of a single shared
    +   object, then the expression\\*
    +   {\tt ((ptrdiff\_t) upc\_addrfield(S2) - (ptrdiff\_t) upc\_addrfield(S1))}\\*
    +   shall evaluate on all threads to the same value that\\*
    +   {\tt ((char *)S2 - (char *)S1)}\\*
    +   evalutes to on the thread with which the pointed-to bytes have affinity.}
    +
    +\xchangenote[id=SV]{107}{Constraints moved from 6.4.2 and cross-reference footnote
    removed.}
    +
     \paragraph{The {\tt upc\_affinitysize} function}
    
     {\bf Synopsis}
    Index: lang/upc-language.tex
    ===================================================================
    --- lang/upc-language.tex       (revision 205)
    +++ lang/upc-language.tex       (working copy)
    @@ -303,9 +303,8 @@
     \begin{itemize}
     \item S1 and P1 shall point to the same object.
     \item S2 and P2 shall point to the same object.
    -\item The expression (({\tt (ptrdiff\_t) upc\_addrfield} (S2) -  {\tt (ptrdiff\_t)
    upc\_addrfield(S1))} shall
    -   evaluate to the same value as ((P2 - P1) * sizeof(T)).
     \end{itemize}
    +\xchangenote[id=SV]{107}{Constraint on {\tt upc\_addrfield} strengthened and moved
    to Section~\ref{upc_addrfield}.}
    
     \np Two compatible pointers-to-shared which point to the same
         object (i.e. having the same address and thread components) shall
    

    Reported by sdvormwa@cray.com on 2013-02-28 21:08:53

  41. Former user Account Deleted
    Regarding the following from comment #39
    > If two pointers-to-shared point to bytes with affinity
    > to the same thread, then the values resulting from passing them to
    > {\tt upc\_addrfield} shall compare equal if the pointers themselves
    > compare equal.
    
    PTS equality IMPLIES affinity to the same thread, making the first clause redundant.
    How about:
    
    If two pointers-to-shared compare equal, then the values resulting from passing them
    to {\tt upc\_addrfield} shall compare equal.
    

    Reported by phhargrove@lbl.gov on 2013-02-28 21:10:47

  42. Former user Account Deleted
    > Our comments passed in the ether. My comment #36 applies equally to the new proposed
    paragraph
    > ...
    
    Does the new language address these concerns?  I think it still provides the uniqueness
    guarantee for all platforms where size_t is "wide enough", while permitting implementations
    on platforms where that is not true.
    

    Reported by sdvormwa@cray.com on 2013-02-28 21:13:35

  43. Former user Account Deleted
    Updated with Paul's comment from comment 43.
    
    Index: lang/upc-lib-core.tex
    ===================================================================
    --- lang/upc-lib-core.tex       (revision 205)
    +++ lang/upc-lib-core.tex       (working copy)
    @@ -302,11 +302,32 @@
    
     \np The {\tt upc\_addrfield} function returns an
        implementation-defined value reflecting the ``local address'' of the
    -   object pointed to by the pointer-to-shared argument.\footnote{%
    -   This function is used in defining the semantics of pointer-to-shared
    -   arithmetic in Section \ref{pointer-arithmetic}}
    +   object pointed to by the pointer-to-shared argument.
    +
    +\np \xadded[id=SV]{107}{The return value of {\tt upc\_addrfield} shall be
    +   independent of the calling thread.}
    
    -
    +\np \xadded[id=SV]{107}{If two pointers-to-shared compare equal, then
    +   the values resulting from passing them to {\tt upc\_addrfield} shall
    +   compare equal.}
    +
    +\np \xadded[id=SV]{107}{If {\tt size\_t} has the property that any valid
    +   pointer to {\tt void} can be converted to it, then converted back and
    +   compare equal to the original pointer, then the results of passing
    +   two pointers-to-shared that point to bytes with affinity to the same thread
    +   to {\tt upc\_addrfield} shall compare equal only if the pointers themselves
    +   compare equal.}
    +
    +\np \xadded[id=SV]{107}{If two pointers-to-shared {\tt S1} and {\tt S2} point
    +   to bytes with affinity to the same thread that are part of a single shared
    +   object, then the expression\\*
    +   {\tt ((ptrdiff\_t) upc\_addrfield(S2) - (ptrdiff\_t) upc\_addrfield(S1))}\\*
    +   shall evaluate on all threads to the same value that\\*
    +   {\tt ((char *)S2 - (char *)S1)}\\*
    +   evalutes to on the thread with which the pointed-to bytes have affinity.}
    +
    +\xchangenote[id=SV]{107}{Constraints moved from 6.4.2 and cross-reference footnote
    removed.}
    +
     \paragraph{The {\tt upc\_affinitysize} function}
    
     {\bf Synopsis}
    Index: lang/upc-language.tex
    ===================================================================
    --- lang/upc-language.tex       (revision 205)
    +++ lang/upc-language.tex       (working copy)
    @@ -303,9 +303,8 @@
     \begin{itemize}
     \item S1 and P1 shall point to the same object.
     \item S2 and P2 shall point to the same object.
    -\item The expression (({\tt (ptrdiff\_t) upc\_addrfield} (S2) -  {\tt (ptrdiff\_t)
    upc\_addrfield(S1))} shall
    -   evaluate to the same value as ((P2 - P1) * sizeof(T)).
     \end{itemize}
    +\xchangenote[id=SV]{107}{Constraint on {\tt upc\_addrfield} strengthened and moved
    to Section~\ref{upc_addrfield}.}
    
     \np Two compatible pointers-to-shared which point to the same
         object (i.e. having the same address and thread components) shall
    

    Reported by sdvormwa@cray.com on 2013-02-28 21:15:09

  44. Former user Account Deleted

    Reported by sdvormwa@cray.com on 2013-02-28 21:18:15 - Labels added: Consensus-Medium, Milestone-Spec-1.3 - Labels removed: Consensus-Low, Milestone-Spec-1.4

  45. Former user Account Deleted
    More crossing-in-the-ether.
    
    My comment #40 requests deferral of the debate over per-thread uniqueness.
    HOWEVER, I see that Steve's comment #39 makes the property conditional on the width
    of size_t.  I find that the be an ideal response to the objection that Dan raised (that
    I had already alluded to in comment #17).
    

    Reported by phhargrove@lbl.gov on 2013-02-28 21:23:24

  46. Former user Account Deleted
    Another issue not yet mentioned that we need to be careful with here is what we guarantee
    about PTS arguments to upc_addrfield that reference objects with a limited lifetime
    (dynamically allocated shared data), and what we guarantee about the return value.
    I think there are two parts to this:
    
    1) Add some requirement that the argument to upc_addrfield points to a (valid) shared
    object during the call. Paragraph 1 weakly implies this, but if we're strengthening
    constraints then I believe it should be directly stated. Something like "If ptr does
    not point to a shared object, behavior is undefined."
    
    2) Be careful not to imply that upc_addrfield values "outlive" the object used to generate
    them. The current proposal text makes extensive use of the term "byte", but note that
    a "byte" may correspond to unallocated space containing no valid objects. For example
    if you did something like:
    
    shared void *p1 = upc_alloc(4096);
    size_t r1 = upc_addrfield(p1);
    upc_free(p1);
    shared void *p2 = upc_alloc(4096);
    size_t r2 = upc_addrfield(p2);
    
    It may happen to be the case that after this code (p1 == p2), but as they reference
    different objects I'm don't think its a good idea to require (r1 == r2). Conversely,
    if it happens to be the case that (p1 != p2), it seems like a bad idea to prohibit
    (r1 != r2). 
    

    Reported by danbonachea on 2013-02-28 21:26:23

  47. Former user Account Deleted
    /s/prohibit (r1 != r2)/require (r1 != r2)/
    

    Reported by danbonachea on 2013-02-28 21:27:21

  48. Former user Account Deleted
    Getting down to the nitty-gritty now:
    
    Re: "If two pointers-to-shared {\tt S1} and {\tt S2} point to bytes with affinity to
    the same thread that are part of a single shared object"
    
    I don't like "point to bytes", because in mind S1 and S2 don't "point to bytes" unless
    their type is a pointer to char or array of char (where I mean "char" in all its signed
    and unsigned variations including typedefs like uint8_t).
    
    Alas, I don't have a good alternative suggestion off the top of my head.
    I'll look at C99 to see if I can find an analogous passage for guidance.
    Perhaps I'll find that "bytes" is the right term after all.
    

    Reported by phhargrove@lbl.gov on 2013-02-28 21:31:02

  49. Former user Account Deleted
    in comment 50:  s/in mind/in MY mind/
    We are thinking faster than we can type today.
    

    Reported by phhargrove@lbl.gov on 2013-02-28 21:33:09

  50. Former user Account Deleted
    > 2) Be careful not to imply that upc_addrfield values "outlive" the object used to
    generate them. The current proposal text makes extensive use of the term "byte", but
    note that a "byte" may correspond to unallocated space containing no valid objects.
    For example if you did something like:
    
    I think a better solution to this is to state (either in the allocation routines or
    the free routines) that any use of pointers to shared objects beyond that object's
    lifetime results in undefined behavior.  Then we don't need to put anything special
    here (or other places where that causes problems, such as pointer-to-shared arithmetic
    ;) ).
    

    Reported by sdvormwa@cray.com on 2013-02-28 21:33:38

  51. Former user Account Deleted
    > 1) Add some requirement that the argument to upc_addrfield points to a (valid) shared
    object during the call. Paragraph 1 weakly implies this, but if we're strengthening
    constraints then I believe it should be directly stated. Something like "If ptr does
    not point to a shared object, behavior is undefined."
    
    Note that none of the other PTS utility routines address this.  We should probably
    update all of them (and probably some library routines as well) if we address this
    for upc_addrfield().
    

    Reported by sdvormwa@cray.com on 2013-02-28 21:39:47

  52. Former user Account Deleted
    I am sure the following is imperfect, but it is a starting point.
    For instance I am doubtful about several of my word choices.
    
    + The argument to upc_addrfield() shall be a pointer to a statically allocated shared
    object, or to a dynamically allocated shared object that has not yet been freed (by
    upc_free or upc_all_free).
    
    + The result of applying upc_addrfield() to the address of a dynamically allocated
    shared object shall be valid only for the lifetime of the object, terminating when
    the object is freed.  No constraint in this section applies to the result of upc_addrfield
    applied to a pointer to dynamic storage which has since been freed.
    

    Reported by phhargrove@lbl.gov on 2013-02-28 21:43:22

  53. Former user Account Deleted
    > I don't like "point to bytes", because in mind S1 and S2 don't "point to bytes" unless
    their type is a pointer to char or array of char (where I mean "char" in all its signed
    and unsigned variations including typedefs like uint8_t).
    
    I'm not particularly attached to "bytes", but I can't use object because two pointers
    that point to different objects may compare equal (e.g. a pointer to a structure, and
    a pointer to the first element in it, assuming no padding).  If you find something
    better, let me know.
    

    Reported by sdvormwa@cray.com on 2013-02-28 21:43:59

  54. Former user Account Deleted
    +\np \xadded[id=SV]{107}{If {\tt size\_t} has the property that any valid
    +   pointer to {\tt void} can be converted to it, then converted back and
    +   compare equal to the original pointer, then the results of passing
    +   two pointers-to-shared that point to bytes with affinity to the same thread
    +   to {\tt upc\_addrfield} shall compare equal only if the pointers themselves
    +   compare equal.}
    
    I don't like this proposal because it feels like "passing the buck" on portability
    to the client, who is left with a non-portable property. If they don't need that property
    then it's not a problem, but if they do need it and want portable code, then they are
    left with essentially no solution. The systems in question generally DO have an integer
    type wide enough to hold any PTL, it's just not size_t. Nor is there any expectation
    or even recommendation in C99 that size_t should be wide enough for this purpose -
    it just "happens" to be true on many common systems.
    
    The user can already write non-portable code to scan the bits in a PTS and munge them
    any way they want. If our primary goal is to provide a *portable* way to convert PTS
    to integer values with certain properties, then we should ensure those properties are
    provided portably. If the property is important enough to provide, then we should arrange
    types to make sure it can be implemented everywhere. If we believe we can live without
    the property, then remove it.
    

    Reported by danbonachea on 2013-02-28 21:45:53

  55. Former user Account Deleted
    More crossing in the ether...
    
    In time-distorted-response to Steve's comment #53, I withdraw the "The argument to..."
    constraint I propose in comment #54.  He is right that we have not made such explicit
    constraints on the arguments to other functions taking a PTS, and doing so once sets
    a precedent that sets us up for a lot more work.
    
    I think my second ("The result of...") constraint is still worth discussion to see
    if it addresses Dan's concern.
    

    Reported by phhargrove@lbl.gov on 2013-02-28 21:49:57

  56. Former user Account Deleted
    Actually, C99 already has language to prohibit this (ISO/IEC 9899 6.2.4 2):
    
    The lifetime of an object is the portion of program execution during which storage
    is
    guaranteed to be reserved for it. An object exists, has a constant address,25) and
    retains its last-stored value throughout its lifetime.26) If an object is referred
    to outside of its lifetime, the behavior is undefined. The value of a pointer becomes
    indeterminate when the object it points to reaches the end of its lifetime.
    

    Reported by sdvormwa@cray.com on 2013-02-28 21:49:57

  57. Former user Account Deleted
    > I don't like this proposal because it feels like "passing the buck" on portability
    to the client, who is left with a non-portable property. If they don't need that property
    then it's not a problem, but if they do need it and want portable code, then they are
    left with essentially no solution. The systems in question generally DO have an integer
    type wide enough to hold any PTL, it's just not size_t. Nor is there any expectation
    or even recommendation in C99 that size_t should be wide enough for this purpose -
    it just "happens" to be true on many common systems.
    
    Would you rather we simply require uintptr_t and make that the return type?  Remove
    the uniqueness guarantee altogether?  Something else?  I don't have a strong opinion
    either way on this particular aspect of upc_addrfield().
    

    Reported by sdvormwa@cray.com on 2013-02-28 21:54:37

  58. Former user Account Deleted
    In comment #55 Steve responds to my comment #50:
    > I'm not particularly attached to "bytes", but I can't use object because two
    > pointers that point to different objects may compare equal (e.g. a pointer to
    > a structure, and a pointer to the first element in it, assuming no padding).
    > If you find something better, let me know.
    
    What I found (so far) is a portion of C99 section 6.3.2.3: Pointers.
    
    > When a pointer to an object is converted to a pointer to a character type,
    > the result points to the lowest addressed byte of the object.  Successive
    > increments of the result, up to the size of the object, yield pointers
    > to the remaining bytes of the object.
    
    This seems to be fully consistent with Steve's proposed text which is treating an object
    as a sequence of bytes.
    
    I am still looking for a "better" term, but don't expect to find one.
    

    Reported by phhargrove@lbl.gov on 2013-02-28 21:59:35

  59. Former user Account Deleted
    > The value of a pointer becomes indeterminate when the object it points to reaches
    
    > the end of its lifetime.
    
    Yes, the problem is the value returned by upc_addrfield() while the object was valid
    does not automatically become indeterminate when the object is later deallocated, unless
    we state that restriction.
    
    > Would you rather we simply require uintptr_t and make that the return type?  Remove
    the uniqueness guarantee altogether?  
    
    I don't have a strong opinion on the importance of the actual property, so it depends
    on whether we see an important usage case that needs it. Although in the spirit of
    paragraph 1, if we want the return value of this function to represent "a local address",
    then it should probably be a type large enough to hold one. I don't really see a problem
    with requiring uintptr_t for UPC compliance, and given the massive changes we're about
    to make in the semantics, changing the return type seems like small potatoes. If someone
    is really worried about backwards compatibility, we could possibly deprecate upc_addrfield()
    and introduce our new semantics under a new function name.
    

    Reported by danbonachea on 2013-02-28 22:06:37

  60. Former user Account Deleted
    As an addendum to comment #48, we should probably also explicitly state whether upc_addrfield(NULL)
    is permitted or prohibited, and if permitted what the behavior should be.
    

    Reported by danbonachea on 2013-02-28 22:15:31

  61. Former user Account Deleted
    > Yes, the problem is the value returned by upc_addrfield() while the object was valid
    does not automatically become indeterminate when the object is later deallocated, unless
    we state that restriction.
    
    Yes, but you cannot compare the corresponding pointers without running into undefined
    behavior.  Since the constraint is defined in terms of the result of comparing the
    corresponding pointers, I don't think we need any further clarification.
    

    Reported by sdvormwa@cray.com on 2013-02-28 22:16:34

  62. Former user Account Deleted
    >  I don't like "point to bytes", because in mind S1 and S2 don't "point to bytes" 
    > unless their type is a pointer to char or array of char (where I mean "char" in all
    
    > its signed and unsigned variations including typedefs like uint8_t).
    
    I agree with Paul here - it is a type error to say that an (int *) "points to a byte".
    It points to an object of type int that is comprised of a sequence of bytes. However
    I think the second occurrence of "byte" in the comment #45 proposal can safely be replaced
    with "object" (as in the original wording from 6.4.2).
    

    Reported by danbonachea on 2013-02-28 22:21:09

  63. Former user Account Deleted
    In comment #56 Dan is unhappy w/ Steve's proposed compromise on the per-thread uniqueness
    property, and in comment #59 Steve indicates his flexibility in resolving this.  In
    comment #61 Dan states that doesn't have a strong opinion on the importance of this
    property.
    
    Since I am the one who drew up the original list of requirements, I guess I should
    "weigh in".  Though I already said I was happy w/ the conditional-on-the-width-of-size_t
    approach that Dan is unhappy with, now that I have read Dan's comment, I see his point-of-view
    and am somewhat sympathetic to it.
    
    I therefore suggest (again) that we continue to debate this particular constraint for
    possible inclusion in 1.4, and that we plan to omit if from 1.3.
    
    FWIW: The direct consequences of omitting this constraint is that we don't require
    (nor prohibit) that upc_addrfield() be a bijective (one-to-one) function.  In the context
    of hashing that is of no concern, since the hash generation will almost always be a
    many-to-one mapping.  There do exist hashing functions which are intended to preserve
    all the bits and only produce "randomness", and they would not be able to use upc_addrfield()
    without this property.  Additionally, debugging checks and spec test cases would need
    to be constructed never to assume equality of upc_addrfield() applied to different
    PTSs implied any relationship between the objects the reference.
    

    Reported by phhargrove@lbl.gov on 2013-02-28 22:22:22

  64. Former user Account Deleted
    In comment #61 Dan wrote, in part:
    > Although in the spirit of paragraph 1, if we want the return value of this
    > function to represent "a local address", then it should probably be a type
    > large enough to hold one.
    
    To me the key word in para 1 is "represent".
    Does that allow a "truncated representation" or not?
    I am of the opinion that for 1.3 we should (continue to) allow the possibility that
    the representation is truncated.
    

    Reported by phhargrove@lbl.gov on 2013-02-28 22:27:13

  65. Former user Account Deleted
    In comment #62 Dan asks about the legality and result of upc_addrfield(NULL).
    
    My vote is that this is illegal.
    However, if we do make it legal then it returns "an implementation-defined value" just
    as for any other PTS.
    

    Reported by phhargrove@lbl.gov on 2013-02-28 22:30:24

  66. Former user Account Deleted
    >> The lifetime of an object is the portion of program execution during which storage
    is
    >> guaranteed to be reserved for it. An object exists, has a constant address,25) and
    retains its 
    >> last-stored value throughout its lifetime.26) If an object is referred to outside
    of its lifetime, the 
    >> behavior is undefined. The value of a pointer becomes indeterminate when the object
    it points to reaches 
    >> the end of its lifetime.
    
    >Yes, but you cannot compare the corresponding pointers without running into undefined
    
    > behavior.  Since the constraint is defined in terms of the result of comparing the
    
    > corresponding pointers, I don't think we need any further clarification.
    
    C99 3.17.2: 
      indeterminate value
        either an unspecified value or a trap representation
    
    Use of an unspecified value does not automatically imply undefined behavior. I believe
    it was Troy that brought up this exact point with respect to the non-blocking memcpy
    library. 
    
    The fact that p1 has indeterminate value after the free does not mean the pointer comparison
    is prohibited, just that it's not guaranteed to have a specified result. We should
    not guarantee properties if the comparison happens to return true (or conversely false).
    
    Note that most library functions accepting pointers are relying on the part above that
    says "If an object is referred to outside of its lifetime, the behavior is undefined".
    However this function (and also upc_threadof/upc_phaseof) do not refer to an object.
    They operate soley upon the pointer value. Their argument does not even have an complete
    referenced type.
    

    Reported by danbonachea on 2013-02-28 22:32:41

  67. Former user Account Deleted
    > I therefore suggest (again) that we continue to debate this particular constraint
    
    > for possible inclusion in 1.4, and that we plan to omit if from 1.3.
    
    Firstly, I'm not convinced any of these semantic changes to upc_addrfield should go
    into 1.3. We have direct experience with our two implementations, but no input so far
    on how this might impact other implementations. We also have a very limited set of
    usage scenarios under consideration, and have not gathered widespread input on other
    potential clients. There may be other "useful" properties we should include that we
    just haven't thought of yet.
    
    Secondly, if we're going to make "big changes" to a library function semantics, that
    is also the logical time to change the return value (if we're ever going to take that
    action). Polishing up the semantics in a way to encourage widespread usage, and then
    breaking backward compatibility by changing the return type in the next revision seems
    like asking for trouble. We should decide whether the property matters and either include
    it with all the other changes, or discard it permanently. If we don't feel qualified
    to make that decision right now, that sounds like even more reason to delay the semantic
    changes until the matter has received further study and we're sure they cover everything
    we will ever want.
    

    Reported by danbonachea on 2013-02-28 22:44:02

  68. Former user Account Deleted
    > However I think the second occurrence of "byte" in the comment #45 proposal can safely
    be replaced with "object" (as in the original wording from 6.4.2).
    
    No, because I'm trying to capture the following:
    
    shared int a;
    shared [] char *cp = (&a) + 1;
    
    (upc_addrfield( cp ) - upc_addrfield( &a )) == 1)
    
    The wording from 6.4.2 doesn't work here as far as I can tell, because, as you pointed
    out, the objects are different.
    

    Reported by sdvormwa@cray.com on 2013-02-28 22:56:18

  69. Former user Account Deleted
    I think we may want/need to make the following explicit:
      upc_addrfield((T1*)p) == upc_addrfield((T2*)p)
    
    This is NOT the same as "If two pointers-to-shared compare equal, then the values resulting
    from passing them to upc_addrfield shall compare equal", since T1 and T2 don't need
    to be compatible types and thus their pointer comparison might not be legal.
    
    Note that this thought was initially motivated by the case where either T1 or T2 is
    "shared void" as will be the likely case for the formal parameter in a shared hash
    table implementation.  For that case, the existing "equal PTS -> equal addrfield" constraint
    *is* sufficient since the spec allows comparison between (shared void *) and any other
    PTS type.  However, this issue becomes important if one uses (shared uint8_t *) to
    treat objects as arrays of bytes in one portion of ones code (a third party library
    for instance) and by their "actual" type in another and need to "communicate" using
    the upc_addrfield value (as through a hash key generated from them).
    

    Reported by phhargrove@lbl.gov on 2013-02-28 23:00:38

  70. Former user Account Deleted
    Returning to the "point to bytes" text, let us take a step back to see if we can agree
    what scenarios we wish to cover.  I can think of two "base" cases, and their "convolution":
    
    1) We have P1 and P2 which are PTS referencing elements of a shared array object, and
    those elements have affinity to the same thread.
    
    2) We have P3 and P4 which are PTS (probably of different type, BTW) that reference
    either a shared struct and a field in that struct, or two fields in the same shared
    struct.
    
    1@2) The "convolution" of (1) and (2) in which P5 and P6 are references to structs
    or members of structs where those structs themselves are elements of a shared array,
    but still with the same-affinity constraint.
    
    I propose that we can "For the purposes of this section..." reduce all these cases
    to the case of an indefinite shared array of bytes (and reliance on the constraint
    I suggest in my previous comment).  I just don't have the language to express that
    well.
    

    Reported by phhargrove@lbl.gov on 2013-02-28 23:05:09

  71. Former user Account Deleted
    > This is NOT the same as "If two pointers-to-shared compare equal, then the values
    resulting from passing them to upc_addrfield shall compare equal", since T1 and T2
    don't need to be compatible types and thus their pointer comparison might not be legal.
    
    Actually, as Dan has had to point out to me so many times, because the argument to
    upc_addrfield() is a generic pointer-to-shared, all type information is lost, and the
    pointer comparison IS legal.
    

    Reported by sdvormwa@cray.com on 2013-02-28 23:05:54

  72. Former user Account Deleted
    A new proposal, taking into account a lot of the conversation (perhaps not all though)
    since the last one.  In particular, I've worked around the "points to bytes" issue,
    and added text to prevent the constraints from applying beyond an objects lifetime.
    
    Index: lang/upc-lib-core.tex
    ===================================================================
    --- lang/upc-lib-core.tex       (revision 205)
    +++ lang/upc-lib-core.tex       (working copy)
    @@ -222,6 +222,15 @@
    
     \subsubsection{Pointer-to-shared manipulation functions}
    
    +\np \xadded[id=SV]{107}{The UPC pointer-to-shared manipulation functions that
    +   accept a pointer-to-shared argument have undefined behavior when passed a
    +   pointer-to-shared that points to a shared object outside of the lifetime
    +   of that object.}
    +
    +\np \xadded[id=SV]{107}{The results of UPC pointer-to-shared manipulation
    +   functions that accept a pointer-to-shared argument become unspecified if
    +   the pointer becomes unspecified.}
    +
     \paragraph{The {\tt upc\_threadof} function}
     \label{upc_threadof}
    
    @@ -302,11 +311,28 @@
    
     \np The {\tt upc\_addrfield} function returns an
        implementation-defined value reflecting the ``local address'' of the
    -   object pointed to by the pointer-to-shared argument.\footnote{%
    -   This function is used in defining the semantics of pointer-to-shared
    -   arithmetic in Section \ref{pointer-arithmetic}}
    +   object pointed to by the pointer-to-shared argument.
    +
    +\np \xadded[id=SV]{107}{The return value of {\tt upc\_addrfield} shall be
    +   independent of the calling thread.}
    
    -
    +\np \xadded[id=SV]{107}{If two pointers-to-shared compare equal\footnote{This
    +   comparison occurs after any implict conversions to the generic
    +   pointer-to-shared type.}, then the values resulting from passing them to
    +   {\tt upc\_addrfield} shall compare equal.}
    +
    +\np \xadded[id=SV]{107}{If two pointers-to-shared {\tt S1} and {\tt S2} point
    +   shared objects with affinity to the same thread, and the expression\\*
    +   {\tt ((char *)S2 - (char *)S1)}\\*
    +   has a defined value when evaluated on that thread, then the expression\\*
    +   {\tt ((ptrdiff\_t) upc\_addrfield(S2) - (ptrdiff\_t) upc\_addrfield(S1))}\\*
    +   shall produce the same value when evaluated on any thread.}
    +
    +\np \xadded[id=SV]{107}{The return value of {\tt upc\_addrfield} shall be
    +   the value 0 when passed the {\em null pointer-to-shared}}.
    +
    +\xchangenote[id=SV]{107}{Constraints moved from 6.4.2 and cross-reference footnote
    removed.}
    +
     \paragraph{The {\tt upc\_affinitysize} function}
    
     {\bf Synopsis}
    Index: lang/upc-language.tex
    ===================================================================
    --- lang/upc-language.tex       (revision 205)
    +++ lang/upc-language.tex       (working copy)
    @@ -303,9 +303,8 @@
     \begin{itemize}
     \item S1 and P1 shall point to the same object.
     \item S2 and P2 shall point to the same object.
    -\item The expression (({\tt (ptrdiff\_t) upc\_addrfield} (S2) -  {\tt (ptrdiff\_t)
    upc\_addrfield(S1))} shall
    -   evaluate to the same value as ((P2 - P1) * sizeof(T)).
     \end{itemize}
    +\xchangenote[id=SV]{107}{Constraint on {\tt upc\_addrfield} strengthened and moved
    to Section~\ref{upc_addrfield}.}
    
     \np Two compatible pointers-to-shared which point to the same
         object (i.e. having the same address and thread components) shall
    

    Reported by sdvormwa@cray.com on 2013-02-28 23:11:55

  73. Former user Account Deleted
    A slight change to the proposal in comment 74, removing the redundant "on any thread"
    from the second to last constraint.
    
    Index: lang/upc-lib-core.tex
    ===================================================================
    --- lang/upc-lib-core.tex       (revision 205)
    +++ lang/upc-lib-core.tex       (working copy)
    @@ -222,6 +222,15 @@
    
     \subsubsection{Pointer-to-shared manipulation functions}
    
    +\np \xadded[id=SV]{107}{The UPC pointer-to-shared manipulation functions that
    +   accept a pointer-to-shared argument have undefined behavior when passed a
    +   pointer-to-shared that points to a shared object outside of the lifetime
    +   of that object.}
    +
    +\np \xadded[id=SV]{107}{The results of UPC pointer-to-shared manipulation
    +   functions that accept a pointer-to-shared argument become unspecified if
    +   the pointer becomes unspecified.}
    +
     \paragraph{The {\tt upc\_threadof} function}
     \label{upc_threadof}
    
    @@ -302,11 +311,28 @@
    
     \np The {\tt upc\_addrfield} function returns an
        implementation-defined value reflecting the ``local address'' of the
    -   object pointed to by the pointer-to-shared argument.\footnote{%
    -   This function is used in defining the semantics of pointer-to-shared
    -   arithmetic in Section \ref{pointer-arithmetic}}
    +   object pointed to by the pointer-to-shared argument.
    +
    +\np \xadded[id=SV]{107}{The return value of {\tt upc\_addrfield} shall be
    +   independent of the calling thread.}
    
    -
    +\np \xadded[id=SV]{107}{If two pointers-to-shared compare equal\footnote{This
    +   comparison occurs after any implict conversions to the generic
    +   pointer-to-shared type.}, then the values resulting from passing them to
    +   {\tt upc\_addrfield} shall compare equal.}
    +
    +\np \xadded[id=SV]{107}{If two pointers-to-shared {\tt S1} and {\tt S2} point
    +   shared objects with affinity to the same thread, and the expression\\*
    +   {\tt ((char *)S2 - (char *)S1)}\\*
    +   has a defined value when evaluated on that thread, then the expression\\*
    +   {\tt ((ptrdiff\_t) upc\_addrfield(S2) - (ptrdiff\_t) upc\_addrfield(S1))}\\*
    +   shall evaluate to the same value.}
    +
    +\np \xadded[id=SV]{107}{The return value of {\tt upc\_addrfield} shall be
    +   the value 0 when passed the {\em null pointer-to-shared}}.
    +
    +\xchangenote[id=SV]{107}{Constraints moved from 6.4.2 and cross-reference footnote
    removed.}
    +
     \paragraph{The {\tt upc\_affinitysize} function}
    
     {\bf Synopsis}
    Index: lang/upc-language.tex
    ===================================================================
    --- lang/upc-language.tex       (revision 205)
    +++ lang/upc-language.tex       (working copy)
    @@ -303,9 +303,8 @@
     \begin{itemize}
     \item S1 and P1 shall point to the same object.
     \item S2 and P2 shall point to the same object.
    -\item The expression (({\tt (ptrdiff\_t) upc\_addrfield} (S2) -  {\tt (ptrdiff\_t)
    upc\_addrfield(S1))} shall
    -   evaluate to the same value as ((P2 - P1) * sizeof(T)).
     \end{itemize}
    +\xchangenote[id=SV]{107}{Constraint on {\tt upc\_addrfield} strengthened and moved
    to Section~\ref{upc_addrfield}.}
    
     \np Two compatible pointers-to-shared which point to the same
         object (i.e. having the same address and thread components) shall
    

    Reported by sdvormwa@cray.com on 2013-02-28 23:21:08

  74. Former user Account Deleted
    As an aside, why is upc_affinitysize() in the "Pointer-to-shared manipulation functions"
    sections?  It seems out of place.  That's the reason for the oddly phrased "UPC pointer-to-shared
    manipulation functions that accept a pointer-to-shared argument" rather than simply
    "UPC pointer-to-shared manipulation functions".
    

    Reported by sdvormwa@cray.com on 2013-02-28 23:24:22

  75. Former user Account Deleted
    +\np \xadded[id=SV]{107}{The UPC pointer-to-shared manipulation functions that
    +   accept a pointer-to-shared argument have undefined behavior when passed a
    +   pointer-to-shared that points to a shared object outside of the lifetime
    +   of that object.}
    
    This doesn't really "work", because a pointer to an object outside the lifetime of
    that object technically no longer points to that object. It also doesn't capture PTS
    containing other unspecified values (eg. an uninitialized pointer which is a stack
    variable).
    
    It should probably instead say something like "if the argument does not point to a
    shared object and is not a null pointer-to-shared, then the function has undefined
    behavior.".
    
    Also regarding upc_addrfield(NULL), note that upc_threadof(NULL) and upc_phaseof(NULL)
    ARE explicitly permitted and defined to return zero.
    

    Reported by danbonachea on 2013-02-28 23:28:56

  76. Former user Account Deleted
    +\np \xadded[id=SV]{107}{If two pointers-to-shared compare equal\footnote{This
    +   comparison occurs after any implict conversions to the generic
    +   pointer-to-shared type.}, then the values resulting from passing them to
    +   {\tt upc\_addrfield} shall compare equal.}
    
    I understand your approach here, but the phrasing isn't quite right. There is no implict(sic)
    conversion for comparing two actual arguments, implicit conversion occurs upon function
    call (so you'd have to talk about comparison of the formal arguments, across different
    function calls, yuk). 
    
    Perhaps it should be spelled out via formula, eg: 
    For any two pointers-to-shared S1 and S2, if (shared void *)S1 == (shared void *)S2,
    then upc_addrfield(S1) shall return the same value as upc_addrfield(S2).
    

    Reported by danbonachea on 2013-02-28 23:38:08

  77. Former user Account Deleted
    I an alternative solution to the "point to bytes" by restating the byte-oriented-within-an-object
    constraint along the following lines:
    
    Given two pointer-to-shared P1 and P2:
    IF
     P1 and P2 referencing objects with affinity to the same thread
    AND
     (P1-P2) is has a defined value
    AND
     P1 is not an incomplete type
    THEN
     (upc_addrfield(P1) - upc_addrfield(P2)) == (P1-P2)*sizeof(*P1)
    
    Note that "(P1-P2) has a defined value" here is an indirect way of requiring that they
    are pointers to some portion of the same object (and additionally requires compatible
    types).  It appears that Steve had this same idea in drafting what appears in comment
    #74 (and 75), which didn't exist when I began typing this.
    
    Well, guess what?  We already have text that is nearly equivalent and it has been right
    under our nose (in Dan's comment #61 in issue 106):
    
    +\np Given the following declarations:
    +
    +\begin{verbatim}
    +    T *P1, *P2;  
    +    shared T *S1, *S2;  
    +
    +    P1 = (T*) S1;  /* allowed if upc_threadof(S1) == MYTHREAD */ 
    +    P2 = (T*) S2;  /* allowed if upc_threadof(S2) == MYTHREAD */ 
    +\end{verbatim}
    +
    +   For all S1 and S2 that point to two distinct elements of
    +   the same shared array object which have affinity to the same
    +   thread, the expression:\\
    +    {\tt ((ptrdiff\_t) upc\_addrfield(S2) - (ptrdiff\_t)upc\_addrfield(S1))} \\
    +   shall evaluate to the same value as: {\tt ((P2 - P1) * sizeof(T))}.
    
    I think keeping this minor revision of the time-honored text being removed from 6.4.2
    also helps reassure the reader that the we've NOT fundamentally *altered* upc_addrfield()
    in the 1.3 spec - just added constraints required to make it useful.
    
    Then, as I mention in comment #72 a reduction of the other cases to array-of-bytes
    provides all of the byte-oriented guarantees I was seeking.  Such a reduction to array-of-bytes
    does NOT need to appear in the spec, just as long as we include the type-independent
    constraint I suggested in comment #71, which allows the reader to perform such reduction
    if/when they need to prove some theorem.
    
    Added "in proof": since comment #74 appeared after I began drafting this comment, the
    text beginning "just as long as..." in the previous paragraph is probably irrelevant
    now.
    

    Reported by phhargrove@lbl.gov on 2013-02-28 23:43:55

  78. Former user Account Deleted
    I agree w/ Dan's comment #78 that the approach taken is good but the phrasing is poor.
    Dan's suggested replacement is as unambiguous as we are likely to get.
    

    Reported by phhargrove@lbl.gov on 2013-02-28 23:46:44

  79. Former user Account Deleted
    In comment #77 Dan states:
    > note that upc_threadof(NULL) and upc_phaseof(NULL) ARE explicitly
    > permitted and defined to return zero.
    
    I guess I should have checked those before writing comment #67.
    I change my "vote" to:
      Add a constraint reading "upc_addrfield(NULL) shall return zero"
    
    The constraint that now begins
      "The upc_addrfield function returns an implementation-defined value ..."
    could then be prefixed with the following text:
      "When passed a non-NULL argument, "
    

    Reported by phhargrove@lbl.gov on 2013-02-28 23:54:45

  80. Former user Account Deleted
    I think (please correct me gently if I am wrong) that while some wording issues may
    remain, the only non-trivial point of contention remaining are:
    
    + The per-thread uniqueness constraint (include/conditional-on-size_t/exclude)
    + Dan is still not convinced (as of comment #69) that these changes belong in 1.3.
    
    I think we (Paul, Dan and Steve) should try to bring things to a point where we can
    send an email to the wg list (one NOT generated from the issue tracker) asking for
    outside opinions on a STATIC draft.  As this issue has 60 comments today (counting
    this one), I doubt anyone is likely to jump in to state their views until we let the
    dust settle (otherwise it is like boarding a moving train).
    
    I am fairly confident that I have no more comments to offer on the current draft. 
    However, I am hoping to see a new one that takes Dan's text in my comment #79 to replace
    the current "objects with affinity to the same thread" constraint, or a good "counter
    offer".
    

    Reported by phhargrove@lbl.gov on 2013-03-01 00:21:19

  81. Former user Account Deleted
    I already defined that upc_addrfield( NULL ) == 0.  Take a closer look at the last constraint.
    ;)
    
    > This doesn't really "work", because a pointer to an object outside the lifetime of
    that object technically no longer points to that object. It also doesn't capture PTS
    containing other unspecified values (eg. an uninitialized pointer which is a stack
    variable).
    
    Unfortunately, there ARE cases in C (and thus UPC) where we can generate meaningful
    pointers that don't point to an actual object.  In particular, pointers that point
    just past the end of an array object are valid and have defined semantics, but do not
    point at any object.  I believe the pointer-to-shared manipulation functions should
    generate the "expected" results when applied to such pointers.
    
    What about the following?
    
    Index: lang/upc-lib-core.tex
    ===================================================================
    --- lang/upc-lib-core.tex       (revision 205)
    +++ lang/upc-lib-core.tex       (working copy)
    @@ -222,6 +222,17 @@
    
     \subsubsection{Pointer-to-shared manipulation functions}
    
    +\np \xadded[id=SV]{107}{The UPC pointer-to-shared manipulation functions
    +   that accept a pointer-to-shared argument have undefined behavior when
    +   passed a pointer-to-shared that is the result of an expression with
    +   undefined or unspecified value.}
    +
    +\np \xadded[id=SV]{107}{The results of UPC pointer-to-shared manipulation
    +   functions that accept a pointer-to-shared argument are unspecified when
    +   passed a pointer-to-shared that is the result of an expression with an
    +   implementation defined value, and become unspecified when the pointer
    +   becomes unspecified.}
    +
     \paragraph{The {\tt upc\_threadof} function}
     \label{upc_threadof}
    
    @@ -302,11 +313,27 @@
    
     \np The {\tt upc\_addrfield} function returns an
        implementation-defined value reflecting the ``local address'' of the
    -   object pointed to by the pointer-to-shared argument.\footnote{%
    -   This function is used in defining the semantics of pointer-to-shared
    -   arithmetic in Section \ref{pointer-arithmetic}}
    +   object pointed to by the pointer-to-shared argument.
    +
    +\np \xadded[id=SV]{107}{The return value of {\tt upc\_addrfield} shall be
    +   independent of the calling thread.}
    
    -
    +\np \xadded[id=SV]{107}{If two pointers-to-shared compare equal after being
    +   converted to generic pointers-to-shared, then the values resulting from
    +   passing them to {\tt upc\_addrfield} shall compare equal.}
    +
    +\np \xadded[id=SV]{107}{If two pointers-to-shared {\tt S1} and {\tt S2} point
    +   shared objects with affinity to the same thread, and the expression\\*
    +   {\tt ((char *)S2 - (char *)S1)}\\*
    +   has a defined value when evaluated on that thread, then the expression\\*
    +   {\tt ((ptrdiff\_t) upc\_addrfield(S2) - (ptrdiff\_t) upc\_addrfield(S1))}\\*
    +   shall evaluate to the same value.}
    +
    +\np \xadded[id=SV]{107}{The return value of {\tt upc\_addrfield} shall be
    +   the value 0 when passed the {\em null pointer-to-shared}}.
    +
    +\xchangenote[id=SV]{107}{Constraints moved from 6.4.2 and cross-reference footnote
    removed.}
    +
     \paragraph{The {\tt upc\_affinitysize} function}
    
     {\bf Synopsis}
    Index: lang/upc-language.tex
    ===================================================================
    --- lang/upc-language.tex       (revision 205)
    +++ lang/upc-language.tex       (working copy)
    @@ -303,9 +303,8 @@
     \begin{itemize}
     \item S1 and P1 shall point to the same object.
     \item S2 and P2 shall point to the same object.
    -\item The expression (({\tt (ptrdiff\_t) upc\_addrfield} (S2) -  {\tt (ptrdiff\_t)
    upc\_addrfield(S1))} shall
    -   evaluate to the same value as ((P2 - P1) * sizeof(T)).
     \end{itemize}
    +\xchangenote[id=SV]{107}{Constraint on {\tt upc\_addrfield} strengthened and moved
    to Section~\ref{upc_addrfield}.}
    
     \np Two compatible pointers-to-shared which point to the same
         object (i.e. having the same address and thread components) shall
    

    Reported by sdvormwa@cray.com on 2013-03-01 00:37:25

  82. Former user Account Deleted
    Split up the two paragraphs about pointer-to-shared manipulation functions into three
    for clarity.  Reword the constraints on upc_addrfield() for clarity and to better match
    that in the other pointer-to-shared manipulation functions.
    
    Index: lang/upc-lib-core.tex
    ===================================================================
    --- lang/upc-lib-core.tex       (revision 205)
    +++ lang/upc-lib-core.tex       (working copy)
    @@ -222,6 +222,20 @@
    
     \subsubsection{Pointer-to-shared manipulation functions}
    
    +\np \xadded[id=SV]{107}{The UPC pointer-to-shared manipulation functions
    +   that accept a pointer-to-shared argument have undefined behavior when
    +   passed a pointer-to-shared that is the result of an expression with
    +   undefined or unspecified value.}
    +
    +\np \xadded[id=SV]{107}{The results of UPC pointer-to-shared manipulation
    +   functions that accept a pointer-to-shared argument are implementation
    +   defined when passed a pointer-to-shared that is the result of an
    +   expression with an implementation defined value.}
    +
    +\np \xadded[id=SV]{107}{The results of UPC pointer-to-shared manipulation
    +   functions that accept a pointer-to-shared argument become unspecified
    +   when the pointer becomes unspecified.}
    +
     \paragraph{The {\tt upc\_threadof} function}
     \label{upc_threadof}
    
    @@ -302,11 +316,29 @@
    
     \np The {\tt upc\_addrfield} function returns an
        implementation-defined value reflecting the ``local address'' of the
    -   object pointed to by the pointer-to-shared argument.\footnote{%
    -   This function is used in defining the semantics of pointer-to-shared
    -   arithmetic in Section \ref{pointer-arithmetic}}
    +   object pointed to by the pointer-to-shared argument.
    +
    +\np \xadded[id=SV]{107}{The return value of {\tt upc\_addrfield} shall be
    +   independent of the calling thread.}
    
    -
    +\np \xadded[id=SV]{107}{Given two pointers-to-shared {\tt S1} and {\tt S2},
    +   if the expression\\*
    +   {\tt ((shared void *)S1 == (shared void *)S2)}\\*
    +   evaluates to true, then so shall the expression\\*
    +   {\tt (upc\_addrfield(S1) == upc\_addrfield(S2))}}
    +
    +\np \xadded[id=SV]{107}{Given two pointers-to-shared {\tt S1} and {\tt S2},
    +   if the expression\\*
    +   {\tt ((char *)S2 - (char *)S1)}\\*
    +   has a defined value on any thread, then the expression\\*
    +   {\tt ((ptrdiff\_t) upc\_addrfield(S2) - (ptrdiff\_t) upc\_addrfield(S1))}\\*
    +   shall evaluate to the same value.}
    +
    +\np \xadded[id=SV]{107}{If {\tt ptr} is a null pointer-to-shared, the function
    +   returns 0.}
    +
    +\xchangenote[id=SV]{107}{Constraints moved from 6.4.2 and cross-reference footnote
    removed.}
    +
     \paragraph{The {\tt upc\_affinitysize} function}
    
     {\bf Synopsis}
    Index: lang/upc-language.tex
    ===================================================================
    --- lang/upc-language.tex       (revision 205)
    +++ lang/upc-language.tex       (working copy)
    @@ -303,9 +303,8 @@
     \begin{itemize}
     \item S1 and P1 shall point to the same object.
     \item S2 and P2 shall point to the same object.
    -\item The expression (({\tt (ptrdiff\_t) upc\_addrfield} (S2) -  {\tt (ptrdiff\_t)
    upc\_addrfield(S1))} shall
    -   evaluate to the same value as ((P2 - P1) * sizeof(T)).
     \end{itemize}
    +\xchangenote[id=SV]{107}{Constraint on {\tt upc\_addrfield} strengthened and moved
    to Section~\ref{upc_addrfield}.}
    
     \np Two compatible pointers-to-shared which point to the same
         object (i.e. having the same address and thread components) shall
    

    Reported by sdvormwa@cray.com on 2013-03-01 00:57:34

  83. Former user Account Deleted
    > I already defined that upc_addrfield( NULL ) == 0.
    > Take a closer look at the last constraint. ;)
    
    Yup, I saw that after posting my comment.
    
    While I think this is the right thing to define, I have realized that there is a minor
    conflict with the "debatable" per-thread uniqueness property which I will now explain:
    
    A "likely" implementation of upc_addrfield() (used in BUPC in some cases) is an offset
    relative to the lowest address in the shared heap.
    That means that the "first" object allocated from the shared heap on thread 0 may have
    a upc_addrfield() of zero.
    Howerver, upc_threadof(NULL) == upc_adrfield(NULL) == 0.
    That would seem to imply that the first shared object allocated on thread 0 and the
    NULL PTS would "collide" in such a way as to violate the per-thread uniqueness property.
    
    I think the resolution is straight-forward: the per-thread uniqueness constraint (if
    any) must be worded to apply to non-NULL PTS only.
    
    FWIW: this "collision" can not occur in practice in BUPC because the runtime use memory
    at the "bottom" of the heap for internal purposes and thus no user-visible object can
    have that address.  It is possible, but by no means certain, that other implementations
    that use an offset-from-bottom-of-heap have something similar in order to avoid having
    the internal representation of NULL and a valid object coincide.
    

    Reported by phhargrove@lbl.gov on 2013-03-01 01:03:28

  84. Former user Account Deleted
    A usage-motivated question occurred to me while writing my previous comment, and lead
    to a significant change-of-heart for me:
    
    
    Do we want to say anything about the "alignment" of the upc_addrfield() values?
    For instance, lets take a pointer to a type (lets say shared double) that requires
    N-byte alignment on a given platform (N=8 on many ABIs).  Do we guarantee that the
    upc_addrfield() is divisible by N?
    
    As with the issue of "width" (size_t vs uintptr_t) this comes down to what one wants
    to read into the phrase "reflecting the “local address”".  How many properties of the
    local address are important enough that we are willing to constrain implementations
    of upc_addrfield() to "reflect" them?
    
    In response to my own question, I think that the more properties we can "reflect" the
    better, but that is based on a bias inherent in having an implementation where in the
    PTS representation contains either the full virtual address or the offset relative
    to a page-aligned base-of-shared-heap.  So, for me the "trivial" implementation of
    upc_addrfield() preserves LOTS of properties, including "cache aligned" and "page aligned"
    properties that I have no intention of requiring in the spec.
    
    
    Having now (and not for the first time today) a new insight while composing one of
    these comments, I think I now have a good motivation to NOT require the per-thread
    uniqueness.  This goes back to my almost throw-away mention in comment #31 of IBM's
    UPC implementation for BG/L, which used a GUID/handle in the PTS instead of anything
    directly connected to a virtual address.  I began (while typing the previous paragraph)
    to wonder how they implemented upc_addrfield() in such a case.  It occurred to that
    if your runtime addresses remote memory using a (GUID,thread,offset) tuple, then your
    upc_addrfield() is probably the offset FROM THE START OF THE CONTAINING OBJECT.  Such
    an implementation *is* conforming to 6.4.2 as it stands in the 1.2 spec.  I hope that
    is still permitted by all of the constraints we have discussed, with the exceptions
    of the per-thread uniqueness property.
    
    A upc_addrfield() implemented using (perhaps not alone) the offset from the base of
    the containing object is the only likely implementation for a system such as the BG/L
    where Put/Get are based on a target-side translation of a "handle".  In such a case
    the offset of scalars is always zero, and for arrays is bounded by 0 and upc_affinitysize().
     That, if taken alone, makes for a horrible input to a shared hash table implementation!
     That could, I suppose be remedied by "mixing" bits from the handle itself into the
    value returned from upc_addrfield(), but that is not something we can describe/mandate
    in the spec.  Even if nobody runs on BG/L anymore, and even if I am wrong about some
    key implementation detail on BG/L, the fact remains that this offset-from-start-of-object
    implementation is currently allowed, would still be allowed by the current proposal,
    and yet doesn't address the usage case I presented to keep upc_addrfield() from being
    deprecated.
    
    On the whole I now feel OPPOSED to pushing additional constraints on upc_addrfield()
    into the 1.3 spec.  I feel that we (though rightly I should only speak for myself)
    have taken too much for granted in our rush to resolve this issue.
    
    While I am very appreciative of Steve's LaTaX work today, I propose that for 1.3 we
    just use what Dan proposed in comment #61 of issue #106.  That relocates the only pre-existing
    constraint to the proper document (thereby removing a cross-document forward reference)
    and it does NOT add any new constraints.  We then carefully (less rush) work on additional
    constraints for the 1.4 spec.
    

    Reported by phhargrove@lbl.gov on 2013-03-01 01:48:52

  85. Former user Account Deleted
    Paul said:
    > On the whole I now feel OPPOSED to pushing additional constraints on upc_addrfield()
    into the 1.3 spec.  I feel 
    > that we (though rightly I should only speak for myself) have taken too much for granted
    in our rush to resolve this issue.
    
    Echoing Paul's sentiment and stepping back for a moment, we're expending significant
    effort to ensure we can support portable hashing of PTS values via upc_addrfield().
    This seems like a laudable goal from a programming language perspective, but I'm unclear
    on the true importance of this capability to real-world application code - this feature
    was motivated internally from a language design perspective, not by user request. Hashing
    a pointer value is a common practice in systems software and low-level libraries, because
    it allows you to transparently store hidden metadata about an object, without visibly
    affecting the pointer or object. However the utility of this technique is greatly reduced
    at the application level, where the programmer presumably has full control of the data
    structures and can usually store any necessary metadata directly in the relevant object
    - thus obviating the need for any hash structure and resulting in simpler code and
    slightly more efficient access. Applications usually hash on *data* values that are
    part of the problem domain, or possibly array indices, not pointer values that are
    implementation-defined, change from run to run, and have an arbitrary relation between
    separate objects.
    
    Am I missing something here? Do we have any examples of production codes that want
    to hash pointer values? It's difficult to decide the importance of various semantic
    details for a utility with no real-world client in mind. The only contrived example
    I can think of is to implement something like remote value caching at the application
    level, but at the app level that's traditionally done more simply and efficiently using
    replication.
    
    > While I am very appreciative of Steve's LaTaX work today, I propose that for 1.3
    we just use what Dan proposed in 
    > comment #61 of issue #106.  That relocates the only pre-existing constraint to the
    proper document (thereby 
    > removing a cross-document forward reference) and it does NOT add any new constraints.
     We then carefully (less 
    > rush) work on additional constraints for the 1.4 spec.
    
    I agree on all counts. I think the length of this thread and the proliferation of semantic
    issues that just us three have uncovered in 24 hours related to redesigning this function
    is indication that further study is required before taking normative action. There
    are good reasons why we have a very long-duration process in place for introduction
    of new library functionality, generally starting with inclusion as an optional feature.
    Even if we end up keeping the same name for upc_addrfield(), the radical changes to
    the semantic guarantees that we're considering effectively make it a new library call.
    Any robust UPC code relying on the new guarantees would need to check the value of
    __UPC_VERSION__ before calling this new upc_addrfield, to avoid silently relying upon
    the underspecified "1.2 behavior" of the function that might result in undefined behavior.
    From that perspective, it might be preferable to introduce these semantics under a
    new library name (eg upc_pointertoint() or something else clever) with a dedicated
    feature macro to indicate its presence, and allow initial implementations to provide
    it as an optional feature while we evaluate the utility of the function and the design
    of its semantics in real application usage. 
    

    Reported by danbonachea on 2013-03-01 13:38:10 - Labels added: Milestone-Spec-1.4 - Labels removed: Milestone-Spec-1.3

  86. Former user Account Deleted
    > Am I missing something here?
    
    Kind of.  I originally brought this issue up because upc_addrfield() is so ill-defined
    as to be useless.  Its single constraint had the single purpose of attempting to provide
    the guarantee that issue 106 addresses.  Because we're now addressing that guarantee
    in another way, I felt that it would be cleaner to simply remove it to avoid giving
    UPC (1.3) developers the impression that upc_addrfield() actually works the way they
    probably think it does.
    
    Then Paul chipped in with a potential use for a "stronger" upc_addrfield() that could
    not (easily) be done with any existing language features, and we spent the last 24
    hours or so trying to make that work.
    
    In summary, the main focus of the bulk of the thread was indeed trying to find a way
    to support portable hashing of pointer-to-shared values, but the issue itself is not
    concerned with that per se.
    
    > There are good reasons why we have a very long-duration process in place for introduction
    of new library functionality
    
    That applies equally to the introduction of ANY language changes (*cough* issue 106
    *cough*).  The reason I pushed so hard to address this in 1.3 is because others pushed
    so hard to fix issue 106 in 1.3.  These issues are EXTREMELY closely related, so fixing
    one without the other just makes things worse in my mind.
    
    > Even if we end up keeping the same name for upc_addrfield(), the radical changes
    to the semantic guarantees that we're considering effectively make it a new library
    call. Any robust UPC code relying on the new guarantees would need to check the value
    of __UPC_VERSION__ before calling this new upc_addrfield, to avoid silently relying
    upon the underspecified "1.2 behavior" of the function that might result in undefined
    behavior.
    
    It wouldn't be the first time.  A similar thing happened when going from 1.1.1 to 1.2,
    so any "robust" UPC code must already check the value of __UPC_VERSION__.
    

    Reported by sdvormwa@cray.com on 2013-03-01 16:40:13

  87. Former user Account Deleted
    > The reason I pushed so hard to address this in 1.3 is because others pushed so hard
    
    > to fix issue 106 in 1.3...fixing one without the other just makes things worse in
    my 
    mind.
    
    Issue 106 is a CLARIFICATION to 6.4.2 that expresses the widespread implicit understanding
    of all implementers, tutorial materials and users about how blocked shared arrays must
    be laid out. Someone finally noticed that wasn't explicitly written down, and now it
    is.
    
    Everything else under discussion in this issue is clearly a CHANGE to existing semantics
    in section 7, with potential impact to users and implementers. A clarification and
    a change are two very different beasts, even if they happen to touch nearby paragraphs
    (that really never belonged nearby in the first place). I've worked very hard to satisfy
    the concerns of Steve and Troy regarding issue 106, and the current proposal makes
    the necessary clarification with exactly zero semantic changes or side-effects to upc_addrfield().
    
    
    I believe this resolves Troy's concern about "subtly changing" upc_addrfield expressed
    in http://code.google.com/p/upc-specification/issues/detail?id=106#c59 although I'll
    wait for his opinion on the latest proposal. Paul and I have expressed strong opinions
    in favor of accepting the current proposal for 106 and deferring 107 for 1.4. I know
    we don't work under a voting system, but of the expressed opinions I believe Steve
    is currently "out-voted" on this matter. If our disagreement is insoluable, then we'll
    need to schedule another teleconference this coming week to discuss the matter amongst
    the entire committee and reach a final decision.
    

    Reported by danbonachea on 2013-03-01 16:56:21

  88. Former user Account Deleted
    > Issue 106 is a CLARIFICATION to 6.4.2 that expresses the widespread implicit understanding
    of all implementers, tutorial materials and users about how blocked shared arrays must
    be laid out. Someone finally noticed that wasn't explicitly written down, and now it
    is.
    >
    > Everything else under discussion in this issue is clearly a CHANGE to existing semantics
    in section 7
    
    Historically, the primary reason for those semantics in the first place was to (attempt
    to) provide the guarantees that issue 106 is addressing.  Additionally, due to the
    poor existing wording in 7.2.3.4, users are likely to assume more constraints than
    they are guaranteed by the spec.  Maintaining them simply because they were in 1.2
    doesn't make sense to me in light of this.
    

    Reported by sdvormwa@cray.com on 2013-03-01 18:37:54

  89. Former user Account Deleted

    Reported by danbonachea on 2013-03-01 18:52:10 - Labels added: Type-Enhancement - Labels removed: Type-Defect

  90. Former user Account Deleted

    Reported by danbonachea on 2013-03-01 18:52:25 - Labels added: Consensus-Low - Labels removed: Consensus-Medium

  91. Former user Account Deleted
    I just came across another use for stronger guarantees on upc_addrfield(), in particular
    that the return value be the same on all threads, while looking at a customer code.
     The code in question uses a lot of shared locks, acquired in pairs.  As written, the
    code spins trying to acquire both locks with upc_lock_attempt() until both locks are
    acquired to avoid deadlock.  If upc_addrfield() were guaranteed to return the same
    value on all threads, the code could instead grab locks with upc_lock() in increasing
    order of upc_addrfield() (using upc_threadof() to manage ties), achieving the same
    goal with (in most implementations) much better lock performance.
    

    Reported by sdvormwa@cray.com on 2013-03-04 16:38:50

  92. Former user Account Deleted
    In response to Steve's comment #93 which suggests that ordering of locks might be another
    application of upc_addrfield(), I must point out 7.4.2.1 3:
    
       Two pointers to upc_lock_t that reference the same lock object will compare
       as equal. The results of applying upc_phaseof(), upc_threadof(), and
       upc_addrfield() to such pointers are undefined.
    
    Thus a non-trivial change to locks would be required to allow the application scenario
    described.
    

    Reported by phhargrove@lbl.gov on 2013-03-04 18:05:04

  93. Former user Account Deleted
    I was merely pointing out another possible use case for a stronger upc_addrfield()--one
    which programmers are probably more familiar with if they've ever used locks in other
    programming models given that this is one of the most common methods of deadlock avoidance
    in the presence of multiple locks.  If we wanted to actually support this use case,
    we'd obviously have to go through and fix anything else (such as the restrictions in
    7.4.2.1 3) that would prevent it.
    

    Reported by sdvormwa@cray.com on 2013-03-04 18:16:30

  94. Former user Account Deleted
    This comment is mostly about history.  I do have one fairly minor suggestion to make.
     Sorry, this is another bit of tangent, but I think it worthwhile enough to bring up
    here.  People were wondering about the history, so I did some digging.
    
    I had mentioned that upc_addrfield, initially referred to as "vadr" portion of a pointer-to-shared,
    as originally conceived, did have cross-thread consistency.  One place to see this
    is expectation is in the 1999 paper by Carlson, Draper, et al, "Introduction to UPC
    and Language Specification".  Another place to see this is in some of the existing
    tests in the GUTS suite from GWU.
    
    It was suggested in a comment that this particular implementation of upc_addrfield
    would be difficult in an SMP environment.  It does take work, but it has been done
    that way in some implementations, including HP UPC.  The HP UPC pointer-to-shared structure
    actually maintains as its "address" component the field that is reported by upc_addrfield,
    and does the appropriate offset calculations when converting it to a "real" address.
     But, more to the point, it doesn't have to be that way, either; it could maintain
    the "real" address, for example, and do the offset calculations only when returning
    upc_addrfield calls.  Address randomization is also handled by a number of implementations
    while maintaining this consistency in the upc_addrfield function return value.
    
    HP UPC is a very old implementation.  It existed before the specification (as Digital
    UPC, later Compaq UPC).  It honors some understandings, such as this one, that never
    made it into the specification.
    
    I am NOT advocating that we introduce this consistency.  That ship sailed long ago.
     There are too many implementations that do not provide it.  It is not in the specification;
    it has NEVER been in the specification.
    
    I was going to suggest that the note regarding upc_addrfield being "used in the definition
    of pointer arithmetic" be dropped, but I see that there is some amount of constraint
    on the values returned by upc_addrfield that are listed under the pointer arithmetic
    section.
    
    I will, however, suggest that an explicit mention be made that upc_addrfield values
    across threads do not have any relation to each other.  If something like the GUTS
    suite makes this assumption, there are potentially other code bases that do.
    

    Reported by brian.wibecan on 2013-03-05 17:09:13

  95. Former user Account Deleted
    > I will, however, suggest that an explicit mention be made that upc_addrfield values
    across threads do not have any relation to each other.  If something like the GUTS
    suite makes this assumption, there are potentially other code bases that do.
    
    Do you mean that for the same pointer, when passed to upc_addrfield(), the return value
    on different threads do not have any relation to each other?  Or that pointers to elements
    of the same shared array object with affinity to different threads, when passed to
    upc_addrfield(), produce values with no relation to each other?  I think the latter
    is desirable (for exactly the reasons you brought up in your post), but the former
    makes upc_addrfield() completely useless.  Unfortunately, both are true for UPC 1.2
    and the current UPC 1.3 draft, and I'm sure there are UPC codes that make invalid assumptions
    about one or both.
    

    Reported by sdvormwa@cray.com on 2013-03-05 17:24:27

  96. Former user Account Deleted
    Sorry for not being clear.  This one is what I meant:
    
    > pointers to elements of the same shared array object with affinity to
    > different threads, when passed to upc_addrfield(), produce values with
    > no relation to each other
    
    For example, given
    
    shared T Arr[THREADS];
    
    upc_addrfield(&Arr[idx]) is not actually guaranteed to return the same result for all
    values of idx.  I think this should be called out, rather than defined this way solely
    by omission.
    
    > the former makes upc_addrfield() completely useless
    
    I agree.  I am surprised that even this basic expectation, the same result returned
    for the same argument when called by all threads, is not specified.
    

    Reported by brian.wibecan on 2013-03-05 17:37:33

  97. Former user Account Deleted
    In the 3/15/13 telecon, we discussed this issue and decided that it should be deferred
    to 1.4, to allow further time for study into the desired semantics, usage cases and
    best way to deploy the new functionality.
    

    Reported by danbonachea on 2013-03-16 01:16:36

  98. Log in to comment