From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from esa2.mentor.iphmx.com (esa2.mentor.iphmx.com [68.232.141.98]) by sourceware.org (Postfix) with ESMTPS id 629B1385801D for ; Fri, 10 Dec 2021 17:27:50 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.1 sourceware.org 629B1385801D Authentication-Results: sourceware.org; dmarc=none (p=none dis=none) header.from=codesourcery.com Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=mentor.com IronPort-SDR: MdhMklRvpBH1KocbIcdw96RjqSXGVExs1U+NKHIqMYej3jFEq99tZO501tGMSJb321K3vb5baU Uk1goQP+vv8yprOZkOy6vaJVrtynqziudkc1ej+k+Jsbj2Blxd0TucBlJ7pjqQ4KFUxNnp6oUQ ottxoAQpsgpWpMY8oiGzt85ydvsVOpTrU1gUC0g9ddQ6GZckIZ47aaJGB6qXyfMlHI7tcGiS7b qikT46fdW+SM0Mhr3Y1Ea4ZGHxkPQH4qLEqixue23EedKfqRDb5vhLGl8cpuBoqQCtcs4Ngq1P v9aUyTiFhhe06uCHU3Vu8eFk X-IronPort-AV: E=Sophos;i="5.88,196,1635235200"; d="scan'208";a="69539733" Received: from orw-gwy-01-in.mentorg.com ([192.94.38.165]) by esa2.mentor.iphmx.com with ESMTP; 10 Dec 2021 09:27:48 -0800 IronPort-SDR: a+K281tGHi78bpgwwTeYAQoLIK0UPT1w//FSisUVD/0xTZQabjzhcaYmNMs6jWddqyNNAm4ZEO xs2U76Ftni+xVrN0LxfPgPszbzLsOBNQCI8DG8ND16uuFQyaVPReo1ogDLDjgA/vNqDq8TGlHI +vsGbfzE5n2AnwXW317yngbKbq0R3+ybyXWpFhkk9HYffEFREXXOfoqKN4DGiULtzFvWEzpGSZ 1l1hzyig03IkdKXuNEMEKGYkuDgLDtdDo2ff775831lldQk+Idq+zLofmc/zH1m/aTQT5c2xqV 298= Message-ID: <7d0be89e-5f43-6e40-8cfd-e9c431a8797a@codesourcery.com> Date: Fri, 10 Dec 2021 17:27:18 +0000 MIME-Version: 1.0 User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:91.0) Gecko/20100101 Thunderbird/91.4.0 From: Kwok Cheung Yeung Subject: Re: [WIP, OpenMP] OpenMP metadirectives support To: Jakub Jelinek CC: GCC Patches References: <8d413974-0068-3a31-6ae5-d36c1be06d06@codesourcery.com> <20210726142902.GW2380545@tucnak> In-Reply-To: <20210726142902.GW2380545@tucnak> Content-Type: text/plain; charset="UTF-8"; format=flowed Content-Transfer-Encoding: 7bit X-Originating-IP: [137.202.0.90] X-ClientProxiedBy: svr-ies-mbx-15.mgc.mentorg.com (139.181.222.15) To SVR-IES-MBX-04.mgc.mentorg.com (139.181.222.4) X-Spam-Status: No, score=-6.1 required=5.0 tests=BAYES_00, HEADER_FROM_DIFFERENT_DOMAINS, KAM_DMARC_STATUS, NICE_REPLY_A, SPF_HELO_PASS, SPF_PASS, TXREP autolearn=ham autolearn_force=no version=3.4.4 X-Spam-Checker-Version: SpamAssassin 3.4.4 (2020-01-24) on server2.sourceware.org X-BeenThere: gcc-patches@gcc.gnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Gcc-patches mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Fri, 10 Dec 2021 17:27:53 -0000 Hello It has been several months since I posted my WIP patch, and my current patch set (which I will post separately) has evolved considerably since then. I have added C++ and Fortran support, as well as dynamic selectors from the OpenMP 5.1 spec (currently only the 'user={condition()}' selector is implemented, target_device is TBD). On 26/07/2021 3:29 pm, Jakub Jelinek wrote: > Note, there is a partial overlap with the attribute syntax changes, see below. > c-family/c-omp.c now has omp_directives table that should be updated for > changes like this and then c_omp_categorize_directive that returns some > information about the directives given a directive name (though, that name > can be one, two or three tokens long, consider e.g. target enter data > or cancellation point directives). I have modified the C/C++ parser code to lookup the type of the directive using c_omp_categorize_directive. > For metadirective, I think very special case are declarative directives in > them, I'd tend to sorry for them at least for now, I'm pretty sure many > cases with them are just unimplementable and will need to be restricted in > the standard, others can be implemented with lots of effort. > Whether it is e.g. metadirective guarding declare target ... end declare > target pair that would only conditionally set declare target and instead of > a single bit to find out if something is declare target or not we'd until > resolved need to compute it for all possibilities, or e.g. conditional > declare reduction/declare mapper where the name lookup for reduction or map > directives would be dependent on metadirective resolution later on, etc. > I'm afraid a total nightmare nobody has really thought about details for it. The parsers currently emit a sorry if a C_OMP_DIR_DECLARATIVE directive is encountered in a metadirective, though I am sure there are many remaining ways that one could break it! >> As an optimisation, identical body trees could be merged together, but that >> can come later. > > I'm afraid it isn't just an optimization and we need to be as smart as > possible. I'm not sure it is possible to parse everything many times, > consider e.g. labels in the blocks, nested function definitions, variable > definitions, etc. > While OpenMP requires that essentially the code must be valid if the > metadirective is replaced by any of those mentioned directives which rules > quite some weirdo corner cases, nothing prevents e.g. two or more > when directives to be standalone directives (which don't have any body and > so whatever comes after them should be left parsed for later as normal > statement sequence), one or more to be normal constructs that accept a > structured block and one or more to be e.g. looping constructs (simd, for, > distribute, taskloop or combined versions of those). > Even when issues with labels etc. are somehow solved (e.g. for structured > blocks we have the restriction that goto, break, continue, or switch into > a case/default label, etc. can't be used to enter or exit the structured > block which could mean some cases can be handled through renaming seen > labels in all but one bodies), most important is to sync on where parsing > should continue after the metadirective. > I think it would be nice if the metadirective parsing at least made quick > analysis on what kind of bodies the directives will want and can use the new > c-omp.c infrastructure or if needed extend it (e.g. separate the C_OMP_DIR_CONSTRUCT > category into C_OMP_DIR_CONSTRUCT and C_OMP_DIR_LOOPING_CONSTRUCT where > the latter would be used for those that expect some omp loop after it). > One option would be then to parse the body as the most restricted construct > (looping (and determine highest needed collapse and ordered), then construct, > then standalone) and be able to adjust what we parsed into what the > different constructs need, but another option is the separate parsing of > the code after the directive multiple times, but at least in the order of > most restricted to least restricted, remember where to stop and don't parse > it multiple times at least for directives that need the same thing. > After some experimentation, I'm not sure if it is possible in the general case to share bodies between variants. For one thing, it complicates the OMP region outlining and lowering, and becomes rather invasive to implement in the parser. Another is the possibility of having metadirectives nested within metadirective bodies. e.g. Something of the form: #pragma omp metadirective \ when (cond1: dir1) \ when (cond2: dir2) { #pragma omp metadirective \ when (construct dir1: dirA) when (construct dir2: dirB) (body) } in which case the way the inner metadirective is resolved depends on the outer metadirective, leading to different bodies. In my current patch set, I have implemented a limited form of statement body sharing when the body is not part of an OMP directive (e.g. an 'omp flush' followed by the body). Variables declarations and local functions in the body are handled by the usual scoping rules, and labels are handled by declaring them as __local__ (C and C++) or by renaming (Fortran). I have also added assertions in the parsers to ensure that each variant stops parsing at the same point. Would you find this acceptable? >> 2) Selectors in the device set (i.e. kind, isa, arch) resolve differently >> depending on whether the program is running on a target or on the host. >> Since we don't keep multiple versions of a function for each target on the >> host compiler, resolving metadirectives with these selectors needs to be >> delayed until after LTO streaming, at which point the host or offload >> compiler can make the appropriate decision. > > How is this different from declare variant? For declare variant, it is true > I'm never trying to resolve it already during parsing of the call and that > probably should be changed, do a first attempt at that point. Initially > I thought it typically will not be possible, but later clarification and > strong desire of LLVM/ICC etc. to do everything or almost everything already > during parsing suggests that it must be doable at least in some cases. > E.g. we have restrictions that requires directive on which some decision > could be dependent must appear only lexically before it or not at all, etc. > So, similarly to that, metadirective ideally should see if something is > impossible already during parsing (dunno if it should mean we wouldn't parse > the body in that case, that would mean worse diagnostics), then repeat the > checks during gimplification like declare variant is resolved there, then > repeat again after IPA. Would be probably best if for metadirectives that > resolve to executable directives we represent it by something like a magic > IFN that is told everything needed to decide and can share as much code as > possible with the declare variant decisions. > > It is true other compilers implement offloading quite differently from GCC, > by repeating all of preprocessing, parsing etc. for the offloading target, > so they can decide some metadirective/declare variant decisions earlier than > we can. On the other side that approach has also quite some disadvantages, > it is much harder to ensure ABI compatibility between the host and offload > code if one can use #ifdefs and whatever to change layout of everything in > between. > > For the checks during parsing, we'll need a different way how to track which > directives are currently active (or defer anything with construct > selectors till gimplification). It is true that resolving that during > parsing goes against the goal to parse as many bodies together as possible, > so we need to pick one or the other. Parsing what follows for all > standalone directives isn't a problem of course, but if the metadirective > has one when with for and another with simd, then parsing the loop just once > would be a problem if there is metadirective in the body that wants to > decide whether it is in for or simd and wants that decision be done during > parsing. > In my current patch, I attempt to resolve metadirectives at three points - during parsing, during Gimplification, and just after LTO. For Fortran only, I skipped the parser resolution for now - I originally wanted to reuse the code from the C/C++ front ends to resolve metadirectives when translating from the Fortran parse tree to tree form, but there are quite a few references to C-family only functions in it (it would need to be rewritten to be more frontend-neutral). Thanks, Kwok