From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 34434 invoked by alias); 16 Oct 2019 14:42:25 -0000 Mailing-List: contact gcc-patches-help@gcc.gnu.org; run by ezmlm Precedence: bulk List-Id: List-Archive: List-Post: List-Help: Sender: gcc-patches-owner@gcc.gnu.org Received: (qmail 34426 invoked by uid 89); 16 Oct 2019 14:42:25 -0000 Authentication-Results: sourceware.org; auth=none X-Spam-SWARE-Status: No, score=-8.9 required=5.0 tests=AWL,BAYES_00,GIT_PATCH_2,GIT_PATCH_3,KAM_SHORT,SPF_PASS autolearn=ham version=3.3.1 spammy=RELEASE, on!, differences, scp X-HELO: esa3.mentor.iphmx.com Received: from esa3.mentor.iphmx.com (HELO esa3.mentor.iphmx.com) (68.232.137.180) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with ESMTP; Wed, 16 Oct 2019 14:42:22 +0000 IronPort-SDR: OCaz9IVGnluveDyV0ST5ugf1c9k9+45NdHgIRKFy79vh9IPoHbe8JdGQBVnySmXvGCZzRwXsy1 67d8ye8s0N1Qq+mXjbsDW0YT4zN0hIts1bE0+R9XgkJQ9BaCSnAsOBWgAvURd25Bfn8b81GfWb 5IlaSJO7CemLEwoPE4M7rAMJEiecjs5aeVnNH+vYNaZz/nbAw5F+IPE5a0DavWRvLPzdAOllf+ dItNcdqs8Tmd0763bEUSLD3J116pz7aAtUS0qo4afdxB2K2jANNxN+LM/0WBIU8vE96Ims5GsU ADo= Received: from orw-gwy-02-in.mentorg.com ([192.94.38.167]) by esa3.mentor.iphmx.com with ESMTP; 16 Oct 2019 06:42:18 -0800 IronPort-SDR: 3OgXtXWX/0O8ugw+15wDzktbFjNbD6R91asabrsvaal8X3lJNWB6I7SyekagJMSjyK41WlviA6 0YogNXY83NTmsMFQcGheUKiTuqEGVsbBQlHF73DgP1JnDZqjCxRaWkDGvDor1ZQwbyWN2yURaQ F+2BTTtArN0sJluaE/9HaXs4dC/CDAKB2mHTQUs9pt9GSHm79xf3K4EifIqD16KdxaBYVjI2qR c2pQwCJtTan428Ov90hnyrGHK0vXhXZiicZgGAN3lry42aG3D8U2lBBerUxOc6TZJvFN0i872O g1w= From: Thomas Schwinge To: Julian Brown CC: , Subject: Re: [PATCH 3/4] Factor out duplicate code in gimplify_scan_omp_clauses In-Reply-To: <20191006223237.81842-4-julian@codesourcery.com> References: <20191006223237.81842-1-julian@codesourcery.com> <20191006223237.81842-4-julian@codesourcery.com> User-Agent: Notmuch/0.29.1+93~g67ed7df (https://notmuchmail.org) Emacs/26.1 (x86_64-pc-linux-gnu) Date: Wed, 16 Oct 2019 14:43:00 -0000 Message-ID: <87o8ygwy4k.fsf@euler.schwinge.homeip.net> MIME-Version: 1.0 Content-Type: multipart/signed; boundary="=-=-="; micalg=pgp-sha512; protocol="application/pgp-signature" Return-Path: tschwing@mentor.com X-SW-Source: 2019-10/txt/msg01192.txt.bz2 --=-=-= Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: quoted-printable Content-length: 16213 Hi Julian! On 2019-10-06T15:32:36-0700, Julian Brown wrote: > This patch factors out some code in gimplify_scan_omp_clauses into two > new outlined functions. Yay for such simplification, and yay for documenting what's going on! > Previously approved here: > > https://gcc.gnu.org/ml/gcc-patches/2018-12/msg01309.html > > FAOD, OK for trunk? I have not reviewed whether it's a suitable refactoring; I'm not at all familiar with that code. I started to "functionally" review it by re-inlining your outlined code, and checking the differences to the original code. Additionally to the 'gcc_assert' item I just raised with Jakub, there are a few more things I don't understand: > gcc/ > * gimplify.c (insert_struct_comp_map, check_base_and_compare_lt): New. > (gimplify_scan_omp_clauses): Outline duplicated code into calls to > above two functions. > --- > gcc/gimplify.c | 307 ++++++++++++++++++++++++++++--------------------- > 1 file changed, 174 insertions(+), 133 deletions(-) > --- a/gcc/gimplify.c > +++ b/gcc/gimplify.c > @@ -8120,6 +8120,160 @@ gimplify_omp_depend (tree *list_p, gimple_seq *pr= e_p) > return 1; > } >=20=20 > +/* Insert a GOMP_MAP_ALLOC or GOMP_MAP_RELEASE node following a > + GOMP_MAP_STRUCT mapping. C is an always_pointer mapping. STRUCT_NOD= E is > + the struct node to insert the new mapping after (when the struct node= is > + initially created). PREV_NODE is the first of two or three mappings = for a > + pointer, and is either: > + - the node before C, when a pair of mappings is used, e.g. for a C/= C++ > + array section. > + - not the node before C. This is true when we have a reference-to-= pointer > + type (with a mapping for the reference and for the pointer), or f= or > + Fortran derived-type mappings with a GOMP_MAP_TO_PSET. > + If SCP is non-null, the new node is inserted before *SCP. > + if SCP is null, the new node is inserted before PREV_NODE. > + The return type is: > + - PREV_NODE, if SCP is non-null. > + - The newly-created ALLOC or RELEASE node, if SCP is null. > + - The second newly-created ALLOC or RELEASE node, if we are mapping= a > + reference to a pointer. */ > + > +static tree > +insert_struct_comp_map (enum tree_code code, tree c, tree struct_node, > + tree prev_node, tree *scp) > +{ > + enum gomp_map_kind mkind > + =3D ((code =3D=3D OMP_TARGET_EXIT_DATA || code =3D=3D OACC_EXIT_DATA) > + ? GOMP_MAP_RELEASE : GOMP_MAP_ALLOC); The original code does not handle 'OACC_EXIT_DATA', so that will be a change separate from this refactoring? > + > + tree c2 =3D build_omp_clause (OMP_CLAUSE_LOCATION (c), OMP_CLAUSE_MAP); > + tree cl =3D scp ? prev_node : c2; > + OMP_CLAUSE_SET_MAP_KIND (c2, mkind); > + OMP_CLAUSE_DECL (c2) =3D unshare_expr (OMP_CLAUSE_DECL (c)); > + OMP_CLAUSE_CHAIN (c2) =3D scp ? *scp : prev_node; > + OMP_CLAUSE_SIZE (c2) =3D TYPE_SIZE_UNIT (ptr_type_node); > + if (struct_node) > + OMP_CLAUSE_CHAIN (struct_node) =3D c2; > + > + /* We might need to create an additional mapping if we have a referenc= e to a > + pointer (in C++). Don't do this if we have something other than a > + GOMP_MAP_ALWAYS_POINTER though, i.e. a GOMP_MAP_TO_PSET. */ > + if (OMP_CLAUSE_CHAIN (prev_node) !=3D c > + && OMP_CLAUSE_CODE (OMP_CLAUSE_CHAIN (prev_node)) =3D=3D OMP_CLAUS= E_MAP > + && (OMP_CLAUSE_MAP_KIND (OMP_CLAUSE_CHAIN (prev_node)) > + =3D=3D GOMP_MAP_ALWAYS_POINTER)) In the original code, and with 'prev_node' being '*prev_list_p', this condition was just 'if (OMP_CLAUSE_CHAIN (*prev_list_p) !=3D c)', without the 'GOMP_MAP_ALWAYS_POINTER' handling, so that'd be another change separate from this refactoring? > + { > + tree c4 =3D OMP_CLAUSE_CHAIN (prev_node); > + tree c3 =3D build_omp_clause (OMP_CLAUSE_LOCATION (c), OMP_CLAUSE_= MAP); > + OMP_CLAUSE_SET_MAP_KIND (c3, mkind); > + OMP_CLAUSE_DECL (c3) =3D unshare_expr (OMP_CLAUSE_DECL (c4)); > + OMP_CLAUSE_SIZE (c3) =3D TYPE_SIZE_UNIT (ptr_type_node); > + OMP_CLAUSE_CHAIN (c3) =3D prev_node; > + if (!scp) > + OMP_CLAUSE_CHAIN (c2) =3D c3; > + else > + cl =3D c3; > + } > + > + if (scp) > + *scp =3D c2; > + > + return cl; > +} > + > +/* Called initially with ORIG_BASE non-null, sets PREV_BITPOS and PREV_P= OFFSET > + to the offset of the field given in BASE. Return type is 1 if BASE i= s equal > + to *ORIG_BASE after stripping off ARRAY_REF and INDIRECT_REF nodes and > + calling get_inner_reference, else 0. > + > + Called subsequently with ORIG_BASE null, compares the offset of the f= ield > + given in BASE to PREV_BITPOS, PREV_POFFSET. Returns -1 if the base ob= ject > + has changed, 0 if the new value has a higher bit position than that > + described by the aforementioned arguments, or 1 if the new value is l= ess > + than them. Used for (insertion) sorting components after a GOMP_MAP_= STRUCT > + mapping. */ Hmm, that doesn't seem to be the most intuitive API: the 'orig_base' handling, specifically. (See my struggle below.) > + > +static int > +check_base_and_compare_lt (tree base, tree *orig_base, tree decl, > + poly_int64 *prev_bitpos, > + poly_offset_int *prev_poffset) > +{ > + tree offset; > + poly_int64 bitsize, bitpos; > + machine_mode mode; > + int unsignedp, reversep, volatilep =3D 0; > + poly_offset_int poffset; > + > + if (orig_base) > + { > + while (TREE_CODE (base) =3D=3D ARRAY_REF) > + base =3D TREE_OPERAND (base, 0); > + > + if (TREE_CODE (base) =3D=3D INDIRECT_REF) > + base =3D TREE_OPERAND (base, 0); > + } > + else > + { > + if (TREE_CODE (base) =3D=3D ARRAY_REF) > + { > + while (TREE_CODE (base) =3D=3D ARRAY_REF) > + base =3D TREE_OPERAND (base, 0); > + if (TREE_CODE (base) !=3D COMPONENT_REF > + || TREE_CODE (TREE_TYPE (base)) !=3D ARRAY_TYPE) > + return -1; > + } > + else if (TREE_CODE (base) =3D=3D INDIRECT_REF > + && TREE_CODE (TREE_OPERAND (base, 0)) =3D=3D COMPONENT_REF > + && (TREE_CODE (TREE_TYPE (TREE_OPERAND (base, 0))) > + =3D=3D REFERENCE_TYPE)) > + base =3D TREE_OPERAND (base, 0); > + } > + > + base =3D get_inner_reference (base, &bitsize, &bitpos, &offset, &mode, > + &unsignedp, &reversep, &volatilep); > + > + if (orig_base) > + *orig_base =3D base; > + > + if ((TREE_CODE (base) =3D=3D INDIRECT_REF > + || (TREE_CODE (base) =3D=3D MEM_REF > + && integer_zerop (TREE_OPERAND (base, 1)))) > + && DECL_P (TREE_OPERAND (base, 0)) > + && TREE_CODE (TREE_TYPE (TREE_OPERAND (base, 0))) =3D=3D REFERENCE= _TYPE) > + base =3D TREE_OPERAND (base, 0); > + > + gcc_assert (offset =3D=3D NULL_TREE || poly_int_tree_p (offset)); > + > + if (offset) > + poffset =3D wi::to_poly_offset (offset); > + else > + poffset =3D 0; > + > + if (maybe_ne (bitpos, 0)) > + poffset +=3D bits_to_bytes_round_down (bitpos); > + I find the block of code following below until the end of the function a bit unwieldy to (a) understand, and (b) relate to the original code: > + if (orig_base) > + { > + gcc_assert (base =3D=3D decl); > + > + *prev_bitpos =3D bitpos; > + *prev_poffset =3D poffset; > + > + return *orig_base =3D=3D base; > + } > + else > + { > + if (base !=3D decl) > + return -1; > + > + return (maybe_lt (*prev_poffset, poffset) > + || (known_eq (*prev_poffset, poffset) > + && maybe_lt (*prev_bitpos, bitpos))); > + } > + > + return 0; > +} Can this be done differently, to make it easier to understand? For example, would it help if that code was not outlined into 'insert_struct_comp_map', but kept in its original places? At least on first sight that seemsa reasonable thing to do, given that it's just two separate variants/code paths (as guarded by 'if (orig_base)'), where the first of two calls takes the first branch ('orig_base' supplied), and the other caller takes the second branch ('orig_base' not supplied). If you tell me that's not feasible, then I shall again try to understand that code in the form you've proposed. Gr=C3=BC=C3=9Fe Thomas > @@ -8660,29 +8814,14 @@ gimplify_scan_omp_clauses (tree *list_p, gimple_s= eq *pre_p, > } > } >=20=20 > - tree offset; > - poly_int64 bitsize, bitpos; > - machine_mode mode; > - int unsignedp, reversep, volatilep =3D 0; > - tree base =3D OMP_CLAUSE_DECL (c); > - while (TREE_CODE (base) =3D=3D ARRAY_REF) > - base =3D TREE_OPERAND (base, 0); > - if (TREE_CODE (base) =3D=3D INDIRECT_REF) > - base =3D TREE_OPERAND (base, 0); > - base =3D get_inner_reference (base, &bitsize, &bitpos, &offset, > - &mode, &unsignedp, &reversep, > - &volatilep); > - tree orig_base =3D base; > - if ((TREE_CODE (base) =3D=3D INDIRECT_REF > - || (TREE_CODE (base) =3D=3D MEM_REF > - && integer_zerop (TREE_OPERAND (base, 1)))) > - && DECL_P (TREE_OPERAND (base, 0)) > - && (TREE_CODE (TREE_TYPE (TREE_OPERAND (base, 0))) > - =3D=3D REFERENCE_TYPE)) > - base =3D TREE_OPERAND (base, 0); > - gcc_assert (base =3D=3D decl > - && (offset =3D=3D NULL_TREE > - || poly_int_tree_p (offset))); > + tree orig_base; > + poly_int64 bitpos1; > + poly_offset_int offset1; > + > + int base_eq_orig_base > + =3D check_base_and_compare_lt (OMP_CLAUSE_DECL (c), > + &orig_base, decl, &bitpos1, > + &offset1); >=20=20 > splay_tree_node n > =3D splay_tree_lookup (ctx->variables, (splay_tree_key)decl); > @@ -8693,7 +8832,7 @@ gimplify_scan_omp_clauses (tree *list_p, gimple_seq= *pre_p, > tree l =3D build_omp_clause (OMP_CLAUSE_LOCATION (c), > OMP_CLAUSE_MAP); > OMP_CLAUSE_SET_MAP_KIND (l, GOMP_MAP_STRUCT); > - if (orig_base !=3D base) > + if (!base_eq_orig_base) > OMP_CLAUSE_DECL (l) =3D unshare_expr (orig_base); > else > OMP_CLAUSE_DECL (l) =3D decl; > @@ -8703,32 +8842,8 @@ gimplify_scan_omp_clauses (tree *list_p, gimple_se= q *pre_p, > struct_map_to_clause->put (decl, l); > if (ptr) > { > - enum gomp_map_kind mkind > - =3D code =3D=3D OMP_TARGET_EXIT_DATA > - ? GOMP_MAP_RELEASE : GOMP_MAP_ALLOC; > - tree c2 =3D build_omp_clause (OMP_CLAUSE_LOCATION (c), > - OMP_CLAUSE_MAP); > - OMP_CLAUSE_SET_MAP_KIND (c2, mkind); > - OMP_CLAUSE_DECL (c2) > - =3D unshare_expr (OMP_CLAUSE_DECL (c)); > - OMP_CLAUSE_CHAIN (c2) =3D *prev_list_p; > - OMP_CLAUSE_SIZE (c2) > - =3D TYPE_SIZE_UNIT (ptr_type_node); > - OMP_CLAUSE_CHAIN (l) =3D c2; > - if (OMP_CLAUSE_CHAIN (*prev_list_p) !=3D c) > - { > - tree c4 =3D OMP_CLAUSE_CHAIN (*prev_list_p); > - tree c3 > - =3D build_omp_clause (OMP_CLAUSE_LOCATION (c), > - OMP_CLAUSE_MAP); > - OMP_CLAUSE_SET_MAP_KIND (c3, mkind); > - OMP_CLAUSE_DECL (c3) > - =3D unshare_expr (OMP_CLAUSE_DECL (c4)); > - OMP_CLAUSE_SIZE (c3) > - =3D TYPE_SIZE_UNIT (ptr_type_node); > - OMP_CLAUSE_CHAIN (c3) =3D *prev_list_p; > - OMP_CLAUSE_CHAIN (c2) =3D c3; > - } > + insert_struct_comp_map (code, c, l, *prev_list_p, > + NULL); > *prev_list_p =3D l; > prev_list_p =3D NULL; > } > @@ -8738,7 +8853,7 @@ gimplify_scan_omp_clauses (tree *list_p, gimple_seq= *pre_p, > *list_p =3D l; > list_p =3D &OMP_CLAUSE_CHAIN (l); > } > - if (orig_base !=3D base && code =3D=3D OMP_TARGET) > + if (!base_eq_orig_base && code =3D=3D OMP_TARGET) > { > tree c2 =3D build_omp_clause (OMP_CLAUSE_LOCATION (c), > OMP_CLAUSE_MAP); > @@ -8761,13 +8876,6 @@ gimplify_scan_omp_clauses (tree *list_p, gimple_se= q *pre_p, > tree *sc =3D NULL, *scp =3D NULL; > if (GOMP_MAP_ALWAYS_P (OMP_CLAUSE_MAP_KIND (c)) || ptr) > n->value |=3D GOVD_SEEN; > - poly_offset_int o1, o2; > - if (offset) > - o1 =3D wi::to_poly_offset (offset); > - else > - o1 =3D 0; > - if (maybe_ne (bitpos, 0)) > - o1 +=3D bits_to_bytes_round_down (bitpos); > sc =3D &OMP_CLAUSE_CHAIN (*osc); > if (*sc !=3D c > && (OMP_CLAUSE_MAP_KIND (*sc) > @@ -8785,44 +8893,14 @@ gimplify_scan_omp_clauses (tree *list_p, gimple_s= eq *pre_p, > break; > else > { > - tree offset2; > - poly_int64 bitsize2, bitpos2; > - base =3D OMP_CLAUSE_DECL (*sc); > - if (TREE_CODE (base) =3D=3D ARRAY_REF) > - { > - while (TREE_CODE (base) =3D=3D ARRAY_REF) > - base =3D TREE_OPERAND (base, 0); > - if (TREE_CODE (base) !=3D COMPONENT_REF > - || (TREE_CODE (TREE_TYPE (base)) > - !=3D ARRAY_TYPE)) > - break; > - } > - else if (TREE_CODE (base) =3D=3D INDIRECT_REF > - && (TREE_CODE (TREE_OPERAND (base, 0)) > - =3D=3D COMPONENT_REF) > - && (TREE_CODE (TREE_TYPE > - (TREE_OPERAND (base, 0))) > - =3D=3D REFERENCE_TYPE)) > - base =3D TREE_OPERAND (base, 0); > - base =3D get_inner_reference (base, &bitsize2, > - &bitpos2, &offset2, > - &mode, &unsignedp, > - &reversep, &volatilep); > - if ((TREE_CODE (base) =3D=3D INDIRECT_REF > - || (TREE_CODE (base) =3D=3D MEM_REF > - && integer_zerop (TREE_OPERAND (base, > - 1)))) > - && DECL_P (TREE_OPERAND (base, 0)) > - && (TREE_CODE (TREE_TYPE (TREE_OPERAND (base, > - 0))) > - =3D=3D REFERENCE_TYPE)) > - base =3D TREE_OPERAND (base, 0); > - if (base !=3D decl) > + tree sc_decl =3D OMP_CLAUSE_DECL (*sc); > + int same_decl_offset_lt > + =3D check_base_and_compare_lt (sc_decl, NULL, decl, > + &bitpos1, &offset1); > + if (same_decl_offset_lt =3D=3D -1) > break; > if (scp) > continue; > - gcc_assert (offset =3D=3D NULL_TREE > - || poly_int_tree_p (offset)); > tree d1 =3D OMP_CLAUSE_DECL (*sc); > tree d2 =3D OMP_CLAUSE_DECL (c); > while (TREE_CODE (d1) =3D=3D ARRAY_REF) > @@ -8851,14 +8929,7 @@ gimplify_scan_omp_clauses (tree *list_p, gimple_se= q *pre_p, > remove =3D true; > break; > } > - if (offset2) > - o2 =3D wi::to_poly_offset (offset2); > - else > - o2 =3D 0; > - o2 +=3D bits_to_bytes_round_down (bitpos2); > - if (maybe_lt (o1, o2) > - || (known_eq (o1, o2) > - && maybe_lt (bitpos, bitpos2))) > + if (same_decl_offset_lt) > { > if (ptr) > scp =3D sc; > @@ -8873,38 +8944,8 @@ gimplify_scan_omp_clauses (tree *list_p, gimple_se= q *pre_p, > size_one_node); > if (ptr) > { > - tree c2 =3D build_omp_clause (OMP_CLAUSE_LOCATION (c), > - OMP_CLAUSE_MAP); > - tree cl =3D NULL_TREE; > - enum gomp_map_kind mkind > - =3D code =3D=3D OMP_TARGET_EXIT_DATA > - ? GOMP_MAP_RELEASE : GOMP_MAP_ALLOC; > - OMP_CLAUSE_SET_MAP_KIND (c2, mkind); > - OMP_CLAUSE_DECL (c2) > - =3D unshare_expr (OMP_CLAUSE_DECL (c)); > - OMP_CLAUSE_CHAIN (c2) =3D scp ? *scp : *prev_list_p; > - OMP_CLAUSE_SIZE (c2) > - =3D TYPE_SIZE_UNIT (ptr_type_node); > - cl =3D scp ? *prev_list_p : c2; > - if (OMP_CLAUSE_CHAIN (*prev_list_p) !=3D c) > - { > - tree c4 =3D OMP_CLAUSE_CHAIN (*prev_list_p); > - tree c3 > - =3D build_omp_clause (OMP_CLAUSE_LOCATION (c), > - OMP_CLAUSE_MAP); > - OMP_CLAUSE_SET_MAP_KIND (c3, mkind); > - OMP_CLAUSE_DECL (c3) > - =3D unshare_expr (OMP_CLAUSE_DECL (c4)); > - OMP_CLAUSE_SIZE (c3) > - =3D TYPE_SIZE_UNIT (ptr_type_node); > - OMP_CLAUSE_CHAIN (c3) =3D *prev_list_p; > - if (!scp) > - OMP_CLAUSE_CHAIN (c2) =3D c3; > - else > - cl =3D c3; > - } > - if (scp) > - *scp =3D c2; > + tree cl =3D insert_struct_comp_map (code, c, NULL, > + *prev_list_p, scp); > if (sc =3D=3D prev_list_p) > { > *sc =3D cl; Gr=C3=BC=C3=9Fe Thomas --=-=-= Content-Type: application/pgp-signature; name="signature.asc" Content-length: 658 -----BEGIN PGP SIGNATURE----- iQGzBAEBCgAdFiEEU9WEfWKGQazCmycCAKI7+41Q4XkFAl2nLDsACgkQAKI7+41Q 4XnFPwwApbQHeta1GqCTcgm9vD1QfBY/IHubzhDC8csorOtT/AYE8UIjmuhCwJYH bweRV4JlwG9vH14ZZL1xpW2nw2gplPs2c62CIhpxlX+TuarZE3m9rom03v52lsQa m9xgYY+26U2QGdycuxONskisCL0xbGnuuc0sx+ze91NLXPCF8KcpIz/BnihuDNk6 ie0VtWuy2e8fDT4AMMLtzLLDakrprG9HkbhqgXcphfxMHkWE7ZKzLfd7d+9iMNrd PWpXAXT/zVXKXHY27FVqEbO5ug1JJ0LfnFppbeD6ZH5WBCsi2ZBYNMm/s2uROavm 5OtCT12/mcdixcPkvVIWp32YjxOTcBxcaRR16vQnduGhPetcl5oJnrg8NJjaMaPK ney7SpdmlED1UFrIrI5PJLUf4G+ocUuk3kmU5sWX8EqxkOvwQMryXDuXUrR3IKKv Wh5twEGJRTBZ9dw008VtzDMmJy+Flb7w9LUBcXetZXm6mPOAcqqocN7QhIZRPu+4 D3kYy6pc =KOWq -----END PGP SIGNATURE----- --=-=-=--