Message ID | 87bnn1rrv3.fsf@schwinge.name |
---|---|
State | New |
Headers | show |
On Thu, Dec 18, 2014 at 02:48:32PM +0100, Thomas Schwinge wrote: > > Like for CILK, I'd strongly prefer if for the clauses that are > > specific to OpenACC only you'd use PRAGMA_OACC_CLAUSE_* instead, > > and put them after the PRAGMA_CILK_* enum values. > > If you want to have PRAGMA_OACC_CLAUSE_ aliases also for the > > clauses shared in between OpenMP and OpenACC, feel free to add > > aliases like Cilk+ has them. It is unfortunately lots of new clauses > > and we are getting close to the 64 clauses limit :( when they are used > > in bitmasks. > > I still don't like this very much, because we'll then get a "mess" of > PRAGMA_OMP_CLAUSE_* intermixed with PRAGMA_OACC_CLAUSE_*. I understand, > for example, PRAGMA_OMP_CLAUSE_REDUCTION to just be a "numeric > representation" of the "reduction" string -- and then, it doesn't make > too much sense to me to express this both as PRAGMA_OMP_CLAUSE_REDUCTION > and PRAGMA_OACC_CLAUSE_REDUCTION, or, similarly, to switch back and forth > between PRAGMA_OMP_CLAUSE_* and PRAGMA_OACC_CLAUSE_*. Yet, that's just > the point that I'm making, so I'll defer if there's no consensus to be > found here. The point is that we now have lots of clauses, and making it clear what from those clauses are Cilk+, what are OpenACC, what are OpenMP will help with code readability. Especially if some clauses diverge in their meaning between different standards. > Chung-Lin also had a suggestion to make; what do you think of this? We don't need it yet, and I'm not very keen on making GCC internals use STL more than it does, HWI is certainly more efficient than bitset. So I'd defer any decision here until we have to. Jakub
Hi Jakub! On Thu, 18 Dec 2014 15:29:42 +0100, Jakub Jelinek <jakub@redhat.com> wrote: > On Thu, Dec 18, 2014 at 02:48:32PM +0100, Thomas Schwinge wrote: > > > Like for CILK, I'd strongly prefer if for the clauses that are > > > specific to OpenACC only you'd use PRAGMA_OACC_CLAUSE_* instead, > > > and put them after the PRAGMA_CILK_* enum values. > > > If you want to have PRAGMA_OACC_CLAUSE_ aliases also for the > > > clauses shared in between OpenMP and OpenACC, feel free to add > > > aliases like Cilk+ has them. It is unfortunately lots of new clauses > > > and we are getting close to the 64 clauses limit :( when they are used > > > in bitmasks. OK, so there is this limit. But, I fail to understand how merely moving the OpenACC-only PRAGMA_*_CLAUSE_* to the end of enum pragma_omp_clause will help overcome that? Or have I now completely confused myself, and I'm not even understanding the problem anymore? :-| The only way this would make sense (in my confused mind) is, if we then did PRAGMA_OACC_CLAUSE_REDUCTION = PRAGMA_OMP_CLAUSE_REDUCTION for the clauses whose names exist in both standards, and PRAGMA_OACC_CLAUSE_PRESENT = [some PRAGMA_OMP_CLAUSE_* whose name does not exist in OpenACC], taking care that no two PRAGMA_OACC_CLAUSE_* are assigned the same enum value. Wouldn't this become very cumbersome for future maintenance, however? > > I still don't like this very much, because we'll then get a "mess" of > > PRAGMA_OMP_CLAUSE_* intermixed with PRAGMA_OACC_CLAUSE_*. I understand, > > for example, PRAGMA_OMP_CLAUSE_REDUCTION to just be a "numeric > > representation" of the "reduction" string -- and then, it doesn't make > > too much sense to me to express this both as PRAGMA_OMP_CLAUSE_REDUCTION > > and PRAGMA_OACC_CLAUSE_REDUCTION, or, similarly, to switch back and forth > > between PRAGMA_OMP_CLAUSE_* and PRAGMA_OACC_CLAUSE_*. Yet, that's just > > the point that I'm making, so I'll defer if there's no consensus to be > > found here. > > The point is that we now have lots of clauses, and making it clear what from > those clauses are Cilk+, what are OpenACC, what are OpenMP will help with > code readability. The idea then is, I guess, to split parsing of OpenACC's PRAGMA_OACC_CLAUSE_* out of gcc/c/c-parser.c:c_parser_omp_clause_name into a new c_parser_oacc_clause_name, just like we already have a separate c_parser_oacc_all_clauses and c_parser_omp_all_clauses? (The motivation for the latter is that this is where the disambiguation between the (possibly) different semantics of OpenACC and OpenMP clauses happens, that is, where the "names" PRAGMA_OMP_CLAUSE_* are resolved to actual gcc/tree-core.h:enum omp_clause_code's OMP_CLAUSE_*. For example, there a OpenACC copy clause is translated into a OMP_CLAUSE_MAP with tofrom kind.) > Especially if some clauses diverge in their meaning > between different standards. When you say "clauses" here, do you mean gcc/c-family/c-pragma.h:enum pragma_omp_clause's PRAGMA_*_CLAUSE_*, or gcc/tree-core.h:enum omp_clause_code's OMP_CLAUSE_*, or both? That is, are you suggesting that we should also be adding new OACC_CLAUSE_* next to the existing OMP_CLAUSE_* in gcc/tree-core.h:enum omp_clause_code? (Which would then require separate handling all over the middle end?) I thought the (long-term) goal is to unfiy all this even more? Or, as above, I have now completely confused myself, and I'm not even understanding the problem anymore? :-| Or, alternatively, wouldn't it also work if we did have a separate gcc/c-family/c-pragma.h:enum pragma_oacc_clause (instead of adding to enum pragma_omp_clause), and then the OpenACC clauses at the parsing level live in their own "namespace"? (The same should then be done for Cilk+, too, even though the problem there is not as "severe" as for OpenACC, as its only two handful PRAGMA_CILK_CLAUSE_*.) This means we can't support combined OpenACC/OpenMP pragmas -- but that doesn't make much sense anyway, so no problem. But I'm not sure that is actually the approach you've been suggesting? Grüße, Thomas
On Thu, Dec 18, 2014 at 07:00:09PM +0100, Thomas Schwinge wrote: > OK, so there is this limit. But, I fail to understand how merely moving > the OpenACC-only PRAGMA_*_CLAUSE_* to the end of enum pragma_omp_clause > will help overcome that? Or have I now completely confused myself, and > I'm not even understanding the problem anymore? :-| > > The only way this would make sense (in my confused mind) is, if we then > did PRAGMA_OACC_CLAUSE_REDUCTION = PRAGMA_OMP_CLAUSE_REDUCTION for the > clauses whose names exist in both standards, and > PRAGMA_OACC_CLAUSE_PRESENT = [some PRAGMA_OMP_CLAUSE_* whose name does > not exist in OpenACC], taking care that no two PRAGMA_OACC_CLAUSE_* are > assigned the same enum value. Wouldn't this become very cumbersome for > future maintenance, however? Well, if you e.g. put PRAGMA_OMP_CLAUSE_* that isn't relevant to OpenACC first, then pragmas shared by both, then OpenACC pragmas, then perhaps you could use biased bitmasks for the OpenACC constructs. Anyway, guess keep the ordering as is. > > > I still don't like this very much, because we'll then get a "mess" of > > > PRAGMA_OMP_CLAUSE_* intermixed with PRAGMA_OACC_CLAUSE_*. I understand, > > > for example, PRAGMA_OMP_CLAUSE_REDUCTION to just be a "numeric > > > representation" of the "reduction" string -- and then, it doesn't make > > > too much sense to me to express this both as PRAGMA_OMP_CLAUSE_REDUCTION > > > and PRAGMA_OACC_CLAUSE_REDUCTION, or, similarly, to switch back and forth > > > between PRAGMA_OMP_CLAUSE_* and PRAGMA_OACC_CLAUSE_*. Yet, that's just > > > the point that I'm making, so I'll defer if there's no consensus to be > > > found here. > > > > The point is that we now have lots of clauses, and making it clear what from > > those clauses are Cilk+, what are OpenACC, what are OpenMP will help with > > code readability. > > The idea then is, I guess, to split parsing of OpenACC's > PRAGMA_OACC_CLAUSE_* out of gcc/c/c-parser.c:c_parser_omp_clause_name > into a new c_parser_oacc_clause_name, just like we already have a > separate c_parser_oacc_all_clauses and c_parser_omp_all_clauses? (The > motivation for the latter is that this is where the disambiguation > between the (possibly) different semantics of OpenACC and OpenMP clauses > happens, that is, where the "names" PRAGMA_OMP_CLAUSE_* are resolved to > actual gcc/tree-core.h:enum omp_clause_code's OMP_CLAUSE_*. For example, > there a OpenACC copy clause is translated into a OMP_CLAUSE_MAP with > tofrom kind.) I don't think that is needed. It is the same parsing, so it can be shared, just use PRAGMA_OMP_* for OpenMP clauses or clauses shared between OpenMP and OpenACC and PRAGMA_OACC_* for OpenACC specific pragmas in the code that works with both, and in OpenACC specific FE code the PRAGMA_OACC_* aliases to PRAGMA_OMP_* values for the shared clauses. I just want to be able to clearly see what is OpenACC specific and what is not, similarly how Cilk+ already does it. Jakub
Hi Jakub! We now have to revisit this discussion about gcc/c-family/c-pragma.h:pragma_omp_clause, <http://news.gmane.org/find-root.php?message_id=%3C87bnn1rrv3.fsf%40schwinge.name%3E>: On Thu, 18 Dec 2014 14:48:32 +0100, I wrote: > > > -/* All clauses defined by OpenMP 2.5, 3.0, 3.1 and 4.0. > > > +/* All clauses defined by OpenACC 2.0, and OpenMP 2.5, 3.0, 3.1, and 4.0. > > > Used internally by both C and C++ parsers. */ > > > typedef enum pragma_omp_clause { > > > PRAGMA_OMP_CLAUSE_NONE = 0, > > > > > > PRAGMA_OMP_CLAUSE_ALIGNED, > > > [...] > > > PRAGMA_OMP_CLAUSE_TO, > > > PRAGMA_OMP_CLAUSE_UNIFORM, > > > PRAGMA_OMP_CLAUSE_UNTIED, > > > + PRAGMA_OMP_CLAUSE_VECTOR_LENGTH, > > > + PRAGMA_OMP_CLAUSE_WAIT, > > > > Like for CILK, I'd strongly prefer if for the clauses that are > > specific to OpenACC only you'd use PRAGMA_OACC_CLAUSE_* instead, > > and put them after the PRAGMA_CILK_* enum values. > > If you want to have PRAGMA_OACC_CLAUSE_ aliases also for the > > clauses shared in between OpenMP and OpenACC, feel free to add > > aliases like Cilk+ has them. (That's what we ended up doing.) > > It is unfortunately lots of new clauses > > and we are getting close to the 64 clauses limit :( when they are used > > in bitmasks. We're getting ready to submit patches extending the C/C++ front ends for the remaining OpenACC clauses, and given the current layout of gcc/c-family/c-pragma.h:pragma_omp_clause, we're then at 69 unique clauses, which is more than the 64-bit bitmask limit. > [...] I understand, > for example, PRAGMA_OMP_CLAUSE_REDUCTION to just be a "numeric > representation" of the "reduction" string [...] Should we now further split parsing of Cilk+/OpenACC/OpenMP pragmas (but I think you and I agreed that we don't want to go that route), or revisist Chung-Lin's std::bitset proposal (see below), or something else? Regarding std::bitset, you've been worried about performance, <http://news.gmane.org/find-root.php?message_id=%3C20141218142942.GM1667%40tucnak.redhat.com%3E>, but I'm not sure about this: aren't these code paths only exercised for pragma parsing, and aren't there really only ever one handful (or, a few) of pragmas per source code file, so this could hardly be an observable performance hit? > Chung-Lin also had a suggestion to make; what do you think of this? > > --- c-family/c-common.h (revision 442892) > +++ c-family/c-common.h (working copy) > @@ -1076,138 +1076,17 @@ extern void pp_dir_change (cpp_reader *, const cha > extern bool check_missing_format_attribute (tree, tree); > > /* In c-omp.c */ > -#if HOST_BITS_PER_WIDE_INT >= 64 > -typedef unsigned HOST_WIDE_INT omp_clause_mask; > -# define OMP_CLAUSE_MASK_1 ((omp_clause_mask) 1) > -#else > -struct omp_clause_mask > +#include <bitset> > +typedef std::bitset<128> omp_clause_mask; > +/* Provide '&' before full transition to set() method. */ > +static inline omp_clause_mask > +operator & (const omp_clause_mask& a, const omp_clause_mask& b) > { > - inline omp_clause_mask (); > - inline omp_clause_mask (unsigned HOST_WIDE_INT l); > - inline omp_clause_mask (unsigned HOST_WIDE_INT l, > - unsigned HOST_WIDE_INT h); > - inline omp_clause_mask &operator &= (omp_clause_mask); > - inline omp_clause_mask &operator |= (omp_clause_mask); > - inline omp_clause_mask operator ~ () const; > - inline omp_clause_mask operator & (omp_clause_mask) const; > - inline omp_clause_mask operator | (omp_clause_mask) const; > - inline omp_clause_mask operator >> (int); > - inline omp_clause_mask operator << (int); > - inline bool operator == (omp_clause_mask) const; > - inline bool operator != (omp_clause_mask) const; > - unsigned HOST_WIDE_INT low, high; > -}; > - > -inline > -omp_clause_mask::omp_clause_mask () > -{ > + omp_clause_mask tmp = a; > + return (tmp &= b); > } > +#define OMP_CLAUSE_MASK_1 (omp_clause_mask (1)) > > -inline > -omp_clause_mask::omp_clause_mask (unsigned HOST_WIDE_INT l) > -: low (l), high (0) > -{ > -} > - > -inline > -omp_clause_mask::omp_clause_mask (unsigned HOST_WIDE_INT l, > - unsigned HOST_WIDE_INT h) > -: low (l), high (h) > -{ > -} > - > -inline omp_clause_mask & > -omp_clause_mask::operator &= (omp_clause_mask b) > -{ > - low &= b.low; > - high &= b.high; > - return *this; > -} > - > -inline omp_clause_mask & > -omp_clause_mask::operator |= (omp_clause_mask b) > -{ > - low |= b.low; > - high |= b.high; > - return *this; > -} > - > -inline omp_clause_mask > -omp_clause_mask::operator ~ () const > -{ > - omp_clause_mask ret (~low, ~high); > - return ret; > -} > - > -inline omp_clause_mask > -omp_clause_mask::operator | (omp_clause_mask b) const > -{ > - omp_clause_mask ret (low | b.low, high | b.high); > - return ret; > -} > - > -inline omp_clause_mask > -omp_clause_mask::operator & (omp_clause_mask b) const > -{ > - omp_clause_mask ret (low & b.low, high & b.high); > - return ret; > -} > - > -inline omp_clause_mask > -omp_clause_mask::operator << (int amount) > -{ > - omp_clause_mask ret; > - if (amount >= HOST_BITS_PER_WIDE_INT) > - { > - ret.low = 0; > - ret.high = low << (amount - HOST_BITS_PER_WIDE_INT); > - } > - else if (amount == 0) > - ret = *this; > - else > - { > - ret.low = low << amount; > - ret.high = (low >> (HOST_BITS_PER_WIDE_INT - amount)) > - | (high << amount); > - } > - return ret; > -} > - > -inline omp_clause_mask > -omp_clause_mask::operator >> (int amount) > -{ > - omp_clause_mask ret; > - if (amount >= HOST_BITS_PER_WIDE_INT) > - { > - ret.low = high >> (amount - HOST_BITS_PER_WIDE_INT); > - ret.high = 0; > - } > - else if (amount == 0) > - ret = *this; > - else > - { > - ret.low = (high << (HOST_BITS_PER_WIDE_INT - amount)) > - | (low >> amount); > - ret.high = high >> amount; > - } > - return ret; > -} > - > -inline bool > -omp_clause_mask::operator == (omp_clause_mask b) const > -{ > - return low == b.low && high == b.high; > -} > - > -inline bool > -omp_clause_mask::operator != (omp_clause_mask b) const > -{ > - return low != b.low || high != b.high; > -} > - > -# define OMP_CLAUSE_MASK_1 omp_clause_mask (1) > -#endif > - > enum c_omp_clause_split > { > C_OMP_CLAUSE_SPLIT_TARGET = 0, Grüße, Thomas
On Tue, Apr 28, 2015 at 06:59:12PM +0200, Thomas Schwinge wrote: > We're getting ready to submit patches extending the C/C++ front ends for > the remaining OpenACC clauses, and given the current layout of > gcc/c-family/c-pragma.h:pragma_omp_clause, we're then at 69 unique > clauses, which is more than the 64-bit bitmask limit. I have an uncommitted patch for that that I plan to commit to gomp-4_1-branch tomorrow. Guess I should extract it and commit to trunk separately. Jakub
--- c-family/c-common.h (revision 442892) +++ c-family/c-common.h (working copy) @@ -1076,138 +1076,17 @@ extern void pp_dir_change (cpp_reader *, const cha extern bool check_missing_format_attribute (tree, tree); /* In c-omp.c */ -#if HOST_BITS_PER_WIDE_INT >= 64 -typedef unsigned HOST_WIDE_INT omp_clause_mask; -# define OMP_CLAUSE_MASK_1 ((omp_clause_mask) 1) -#else -struct omp_clause_mask +#include <bitset> +typedef std::bitset<128> omp_clause_mask; +/* Provide '&' before full transition to set() method. */ +static inline omp_clause_mask +operator & (const omp_clause_mask& a, const omp_clause_mask& b) { - inline omp_clause_mask (); - inline omp_clause_mask (unsigned HOST_WIDE_INT l); - inline omp_clause_mask (unsigned HOST_WIDE_INT l, - unsigned HOST_WIDE_INT h); - inline omp_clause_mask &operator &= (omp_clause_mask); - inline omp_clause_mask &operator |= (omp_clause_mask); - inline omp_clause_mask operator ~ () const; - inline omp_clause_mask operator & (omp_clause_mask) const; - inline omp_clause_mask operator | (omp_clause_mask) const; - inline omp_clause_mask operator >> (int); - inline omp_clause_mask operator << (int); - inline bool operator == (omp_clause_mask) const; - inline bool operator != (omp_clause_mask) const; - unsigned HOST_WIDE_INT low, high; -}; - -inline -omp_clause_mask::omp_clause_mask () -{ + omp_clause_mask tmp = a; + return (tmp &= b); } +#define OMP_CLAUSE_MASK_1 (omp_clause_mask (1)) -inline -omp_clause_mask::omp_clause_mask (unsigned HOST_WIDE_INT l) -: low (l), high (0) -{ -} - -inline -omp_clause_mask::omp_clause_mask (unsigned HOST_WIDE_INT l, - unsigned HOST_WIDE_INT h) -: low (l), high (h) -{ -} - -inline omp_clause_mask & -omp_clause_mask::operator &= (omp_clause_mask b) -{ - low &= b.low; - high &= b.high; - return *this; -} - -inline omp_clause_mask & -omp_clause_mask::operator |= (omp_clause_mask b) -{ - low |= b.low; - high |= b.high; - return *this; -} - -inline omp_clause_mask -omp_clause_mask::operator ~ () const -{ - omp_clause_mask ret (~low, ~high); - return ret; -} - -inline omp_clause_mask -omp_clause_mask::operator | (omp_clause_mask b) const -{ - omp_clause_mask ret (low | b.low, high | b.high); - return ret; -} - -inline omp_clause_mask -omp_clause_mask::operator & (omp_clause_mask b) const -{ - omp_clause_mask ret (low & b.low, high & b.high); - return ret; -} - -inline omp_clause_mask -omp_clause_mask::operator << (int amount) -{ - omp_clause_mask ret; - if (amount >= HOST_BITS_PER_WIDE_INT) - { - ret.low = 0; - ret.high = low << (amount - HOST_BITS_PER_WIDE_INT); - } - else if (amount == 0) - ret = *this; - else - { - ret.low = low << amount; - ret.high = (low >> (HOST_BITS_PER_WIDE_INT - amount)) - | (high << amount); - } - return ret; -} - -inline omp_clause_mask -omp_clause_mask::operator >> (int amount) -{ - omp_clause_mask ret; - if (amount >= HOST_BITS_PER_WIDE_INT) - { - ret.low = high >> (amount - HOST_BITS_PER_WIDE_INT); - ret.high = 0; - } - else if (amount == 0) - ret = *this; - else - { - ret.low = (high << (HOST_BITS_PER_WIDE_INT - amount)) - | (low >> amount); - ret.high = high >> amount; - } - return ret; -} - -inline bool -omp_clause_mask::operator == (omp_clause_mask b) const -{ - return low == b.low && high == b.high; -} - -inline bool -omp_clause_mask::operator != (omp_clause_mask b) const -{ - return low != b.low || high != b.high; -} - -# define OMP_CLAUSE_MASK_1 omp_clause_mask (1) -#endif - enum c_omp_clause_split { C_OMP_CLAUSE_SPLIT_TARGET = 0,