From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from mail-ed1-x536.google.com (mail-ed1-x536.google.com [IPv6:2a00:1450:4864:20::536]) by sourceware.org (Postfix) with ESMTPS id 0C73F3858025 for ; Wed, 20 Oct 2021 12:00:43 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.1 sourceware.org 0C73F3858025 Received: by mail-ed1-x536.google.com with SMTP id i20so24919209edj.10 for ; Wed, 20 Oct 2021 05:00:42 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:mime-version:references:in-reply-to:from:date :message-id:subject:to:cc; bh=8xGHgt4TXaq5S5HN/kbjxCTsKACAroaEiHGCaM58icg=; b=lMeEkqSV7xnYhGgZ6nyYYlR9u2+BgtxpZsiHVYUeAdSRA2aXaZeh+iVdEH0Q1AE8A1 sxy6Gx+LjSUY5gVj8R2Crn91UYEKrXbhAJMzdKTIR0jYn/OiAXnC/ow9CbIvfUpxItBE QfH4XxBjci0sOz8a72Pwnr9HMceND+2lfTya1RYTw62L8bcEsDTlp+Ev2vDYOW4uJWL9 TtmnVHOzI9JUBYxrEh0EcXdf3/feV3UplFVmSbH62NOCbT48/noS0o5O2lgXcURmWy0E QdlSB3tQoLggQ7gGLPZBnDisTmkBH3Q3YbHHYCNqj8czYNPGrXDqfyVRFmVGSgirUmwl 4Utg== X-Gm-Message-State: AOAM530qrwNfGkyfDh3HB5X+H3MBcVELGgoPP9/UckUgjIx2lmUy1Xx+ ntUvqAKBjyb5HJf/zPTdOyC6Rh77Z4o+4FZOH/k3BQ== X-Google-Smtp-Source: ABdhPJyr6Le1VS5ruAgrGuxHC9i1fDo2JJYCEz9IoDwjEM/PXjsJM5NP0E/S6qYvI9lCkGkgYlHmesDb58GbIbHGq4M= X-Received: by 2002:aa7:dbca:: with SMTP id v10mr63118820edt.280.1634731234607; Wed, 20 Oct 2021 05:00:34 -0700 (PDT) MIME-Version: 1.0 References: <7nno61so-8qor-n16r-444p-527o2qp169r5@fhfr.qr> <92r13pn-97s9-r18r-6p8-96o3rqqn9or1@fhfr.qr> <41ssp55p-1sp2-r9qs-n4po-poq797or90@fhfr.qr> <7069701q-n4q5-sr4-5824-53r8133q19s4@fhfr.qr> In-Reply-To: <7069701q-n4q5-sr4-5824-53r8133q19s4@fhfr.qr> From: Prathamesh Kulkarni Date: Wed, 20 Oct 2021 17:29:57 +0530 Message-ID: Subject: Re: [match.pd] PR83750 - CSE erf/erfc pair To: Richard Biener Cc: Richard Biener , gcc Patches Content-Type: multipart/mixed; boundary="0000000000008b0aa305cec78630" X-Spam-Status: No, score=-8.9 required=5.0 tests=BAYES_00, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, RCVD_IN_DNSWL_NONE, SPF_HELO_NONE, 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: Wed, 20 Oct 2021 12:00:49 -0000 --0000000000008b0aa305cec78630 Content-Type: text/plain; charset="UTF-8" Content-Transfer-Encoding: quoted-printable On Tue, 19 Oct 2021 at 16:55, Richard Biener wrote: > > On Tue, 19 Oct 2021, Prathamesh Kulkarni wrote: > > > On Tue, 19 Oct 2021 at 13:02, Richard Biener wrote: > > > > > > On Tue, Oct 19, 2021 at 9:03 AM Prathamesh Kulkarni via Gcc-patches > > > wrote: > > > > > > > > On Mon, 18 Oct 2021 at 17:23, Richard Biener wr= ote: > > > > > > > > > > On Mon, 18 Oct 2021, Prathamesh Kulkarni wrote: > > > > > > > > > > > On Mon, 18 Oct 2021 at 17:10, Richard Biener wrote: > > > > > > > > > > > > > > On Mon, 18 Oct 2021, Prathamesh Kulkarni wrote: > > > > > > > > > > > > > > > On Mon, 18 Oct 2021 at 16:18, Richard Biener wrote: > > > > > > > > > > > > > > > > > > On Mon, 18 Oct 2021, Prathamesh Kulkarni wrote: > > > > > > > > > > > > > > > > > > > Hi Richard, > > > > > > > > > > As suggested in PR, I have attached WIP patch that adds= two patterns > > > > > > > > > > to match.pd: > > > > > > > > > > erfc(x) --> 1 - erf(x) if canonicalize_math_p() and, > > > > > > > > > > 1 - erf(x) --> erfc(x) if !canonicalize_math_p(). > > > > > > > > > > > > > > > > > > > > This works to remove call to erfc for the following tes= t: > > > > > > > > > > double f(double x) > > > > > > > > > > { > > > > > > > > > > double g(double, double); > > > > > > > > > > > > > > > > > > > > double t1 =3D __builtin_erf (x); > > > > > > > > > > double t2 =3D __builtin_erfc (x); > > > > > > > > > > return g(t1, t2); > > > > > > > > > > } > > > > > > > > > > > > > > > > > > > > with .optimized dump shows: > > > > > > > > > > t1_2 =3D __builtin_erf (x_1(D)); > > > > > > > > > > t2_3 =3D 1.0e+0 - t1_2; > > > > > > > > > > > > > > > > > > > > However, for the following test: > > > > > > > > > > double f(double x) > > > > > > > > > > { > > > > > > > > > > double g(double, double); > > > > > > > > > > > > > > > > > > > > double t1 =3D __builtin_erfc (x); > > > > > > > > > > return t1; > > > > > > > > > > } > > > > > > > > > > > > > > > > > > > > It canonicalizes erfc(x) to 1 - erf(x), but does not tr= ansform 1 - > > > > > > > > > > erf(x) to erfc(x) again > > > > > > > > > > post canonicalization. > > > > > > > > > > -fdump-tree-folding shows that 1 - erf(x) --> erfc(x) g= ets applied, > > > > > > > > > > but then it tries to > > > > > > > > > > resimplify erfc(x), which fails post canonicalization. = So we end up > > > > > > > > > > with erfc(x) transformed to > > > > > > > > > > 1 - erf(x) in .optimized dump, which I suppose isn't id= eal. > > > > > > > > > > Could you suggest how to proceed ? > > > > > > > > > > > > > > > > > > I applied your patch manually and it does the intended > > > > > > > > > simplifications so I wonder what I am missing? > > > > > > > > Would it be OK to always fold erfc(x) -> 1 - erf(x) even wh= en there's > > > > > > > > no erf(x) in the source ? > > > > > > > > > > > > > > I do think it's reasonable to expect erfc to be available whe= n erf > > > > > > > is and vice versa but note both are C99 specified functions (= either > > > > > > > requires -lm). > > > > > > OK, thanks. Would it be OK to commit the patch after bootstrap+= test ? > > > > > > > > > > Yes, but I'm confused because you say the patch doesn't work for = you? > > > > The patch works for me to CSE erf/erfc pair. > > > > However when there's only erfc in the source, it canonicalizes erfc= (x) > > > > to 1 - erf(x) but later fails to uncanonicalize 1 - erf(x) back to > > > > erfc(x) > > > > with -O3 -funsafe-math-optimizations. > > > > > > > > For, > > > > t1 =3D __builtin_erfc(x), > > > > > > > > .optimized dump shows: > > > > _2 =3D __builtin_erf (x_1(D)); > > > > t1_3 =3D 1.0e+0 - _2; > > > > > > > > and for, > > > > double t1 =3D x + __builtin_erfc(x); > > > > > > > > .optimized dump shows: > > > > _3 =3D __builtin_erf (x_2(D)); > > > > _7 =3D x_2(D) + 1.0e+0; > > > > t1_4 =3D _7 - _3; > > > > > > > > I assume in both cases, we want erfc in the code-gen instead ? > > > > I think the reason uncaonicalization fails is because the pattern 1= - > > > > erf(x) to erfc(x) > > > > gets applied, but then it fails in resimplifying erfc(x), and we en= d > > > > up with 1 - erf(x) in code-gen. > > > > > > > > From gimple-match.c, it hits the simplification: > > > > > > > > gimple_seq *lseq =3D seq; > > > > if (__builtin_expect (!dbg_cnt > > > > (match), 0)) goto next_after_fail1172; > > > > if (__builtin_expect (dump_file && > > > > (dump_flags & TDF_FOLDING), 0)) fprintf (dump_file, "Applying patte= rn > > > > %s:%d, %s:%d\n", "match.pd", 6162, __FILE__, __LINE__); > > > > { > > > > res_op->set_op (CFN_BUILT_IN_ERFC= , type, 1); > > > > res_op->ops[0] =3D captures[0]; > > > > res_op->resimplify (lseq, valueiz= e); > > > > return true; > > > > } > > > > > > > > But res_op->resimplify returns false, and doesn't end up adding to = lseq. > > > > > > There's nothing to add to lseq since there's also nothing to resimpli= fy. > > > The only thing that could happen is that the replacement is not done > > > because replace_stmt_with_simplification via maybe_push_res_to_seq > > > doesn't pass the builtin_decl_implicit test: > > > > > > /* Find the function we want to call. */ > > > tree decl =3D builtin_decl_implicit (as_builtin_fn (fn)); > > > if (!decl) > > > return NULL; > > > > > > btw, it did work for me since the call was present before and gimplif= ication > > > should then mark the function eligible for implicit generation. > > > > > > > As you suggest, should we instead handle this in fre to transform > > > > erfc(x) to 1 - erf(x), only when > > > > there's a matching erf(x) in the source ? > > > > > > Note that's strictly less powerful and we'd have to handle erf(x) -> = 1 +erfc (x) > > > to handle CSE in > > > > > > tem =3D erfc (x); > > > tem2 =3D erf (x); > > > > > > So no, I think the canonicalization is fine unless there's a compelli= ng reason > > > for having both erfc and erf. > > > > > > Can you debug why the reverse transform doesn't work for you? > > It seems the issue was that erfc wasn't getting marked with const > > attribute, and failed the following test in > > maybe_push_res_to_seq: > > /* We can't and should not emit calls to non-const functions.= */ > > if (!(flags_from_decl_or_type (decl) & ECF_CONST)) > > return NULL; > > > > Passing -fno-math-errno seems to work for the reverse transform: > > > > double f(double x) > > { > > double g(double, double); > > > > double t1 =3D __builtin_erfc (x); > > return t1; > > } > > > > Compiling with -O3 -funsafe-math-optimizations -fno-math-errno: > > > > vrp2 dump shows: > > Folding statement: _2 =3D __builtin_erf (x_1(D)); > > Not folded > > Folding statement: t1_3 =3D 1.0e+0 - _2; > > Applying pattern match.pd:6162, gimple-match.c:68450 > > gimple_simplified to t1_3 =3D __builtin_erfc (x_1(D)); > > Folded into: t1_3 =3D __builtin_erfc (x_1(D)); > > > > and .optimized dump shows: > > double f (double x) > > { > > double t1; > > > > [local count: 1073741824]: > > t1_3 =3D __builtin_erfc (x_1(D)); [tail call] > > return t1_3; > > } > > > > Unfortunately, for the test-case involving erf/erfc pair, the reverse > > transform seems to undo the CSE: > > > > double f(double x) > > { > > double g(double, double); > > > > double t1 =3D __builtin_erf (x); > > double t2 =3D __builtin_erfc (x); > > return g(t1, t2); > > } > > > > gimplification turns erfc to 1 - erf: > > Applying pattern match.pd:6158, gimple-match.c:44479 > > gimple_simplified to D.1988 =3D __builtin_erf (x); > > t2 =3D 1.0e+0 - D.1988; > > > > t1 =3D __builtin_erf (x); > > D.1988 =3D __builtin_erf (x); > > t2 =3D 1.0e+0 - D.1988; > > D.1987 =3D g (t1, t2); > > > > fre1 does the CSE: > > t1_2 =3D __builtin_erf (x_1(D)); > > t2_4 =3D 1.0e+0 - t1_2; > > _7 =3D g (t1_2, t2_4); > > > > and forwprop4 again converts 1 - erf(x) to erfc(x), "undoing" the CSE: > > Applying pattern match.pd:6162, gimple-match.c:68450 > > gimple_simplified to t2_3 =3D __builtin_erfc (x_1(D)); > > > > t1_2 =3D __builtin_erf (x_1(D)); > > t2_3 =3D __builtin_erfc (x_1(D)); > > _6 =3D g (t1_2, t2_3); > > > > and .optimized dump shows: > > t1_2 =3D __builtin_erf (x_1(D)); > > t2_3 =3D __builtin_erfc (x_1(D)); > > _6 =3D g (t1_2, t2_3); [tail call] > > You probably want an explicit && single_use () check on the > 1 - erf() -> erfc transform. single_use worked, thanks! As you pointed out, we reassociate x + erfc(x) to (x + 1) - erf(x) and don't uncanonicalize back. I added another pattern to reassociate (x + 1) - erf(x) to x + (1 - erf(x)), after which, it gets uncanonicalized back to x + erfc(x) in .optimized dump. Does the attached patch look OK after bootstrap+test ? Thanks, Prathamesh > > > Thanks, > > Prathamesh > > > > > > Richard. > > > > > > > Thanks, > > > > Prathamesh > > > > > > > > > > Btw, please add the testcase from the PR and also a testcase that= shows > > > > > the canonicalization is undone. Maybe you can also double-check = that > > > > > we handle x + erfc (x) because I see we associate that as > > > > > (x + 1) - erf (x) which is then not recognized back to erfc. > > > > > > > > > > The less surprising (as to preserve the function called in the so= urce) > > > > > variant for the PR would be to teach CSE to lookup erf(x) when > > > > > visiting erfc(x) and when found synthesize 1 - erf(x). > > > > > > > > > > That said, a mathematician should chime in on how important it is > > > > > to preserve erfc vs. erf (precision or even speed). > > > > > > > > > > Thanks, > > > > > Richard. > > > > > > > > > > > Thanks, > > > > > > Prathamesh > > > > > > > > > > > > > > > > > > > > Richard. > > > > > > > > > > > > > > > So for the following test: > > > > > > > > double f(double x) > > > > > > > > { > > > > > > > > t1 =3D __builtin_erfc(x) > > > > > > > > return t1; > > > > > > > > } > > > > > > > > > > > > > > > > .optimized dump shows: > > > > > > > > double f (double x) > > > > > > > > { > > > > > > > > double t1; > > > > > > > > double _2; > > > > > > > > > > > > > > > > [local count: 1073741824]: > > > > > > > > _2 =3D __builtin_erf (x_1(D)); > > > > > > > > t1_3 =3D 1.0e+0 - _2; > > > > > > > > return t1_3; > > > > > > > > } > > > > > > > > > > > > > > > > while before patch, it has: > > > > > > > > t1_4 =3D __builtin_erfc (x_2(D)); [tail call] > > > > > > > > return t1_4; > > > > > > > > > > > > > > > > Thanks, > > > > > > > > Prathamesh > > > > > > > > > > > > > > > > > > > > > > > > > > Richard. > > > > > > > > > > > > > > > > > > > Thanks, > > > > > > > > > > Prathamesh > > > > > > > > > > > > > > > > > > > > > > > > > > > > -- > > > > > > > > > Richard Biener > > > > > > > > > SUSE Software Solutions Germany GmbH, Maxfeldstrasse 5, 9= 0409 Nuernberg, > > > > > > > > > Germany; GF: Felix Imend=C3=B6rffer; HRB 36809 (AG Nuernb= erg) > > > > > > > > > > > > > > > > > > > > > > -- > > > > > > > Richard Biener > > > > > > > SUSE Software Solutions Germany GmbH, Maxfeldstrasse 5, 90409= Nuernberg, > > > > > > > Germany; GF: Felix Imend=C3=B6rffer; HRB 36809 (AG Nuernberg) > > > > > > > > > > > > > > > > -- > > > > > Richard Biener > > > > > SUSE Software Solutions Germany GmbH, Maxfeldstrasse 5, 90409 Nue= rnberg, > > > > > Germany; GF: Felix Imend=C3=B6rffer; HRB 36809 (AG Nuernberg) > > > > -- > Richard Biener > SUSE Software Solutions Germany GmbH, Maxfeldstrasse 5, 90409 Nuernberg, > Germany; GF: Felix Imend=C3=B6rffer; HRB 36809 (AG Nuernberg) --0000000000008b0aa305cec78630 Content-Type: text/plain; charset="US-ASCII"; name="pr83750-2.txt" Content-Disposition: attachment; filename="pr83750-2.txt" Content-Transfer-Encoding: base64 Content-ID: X-Attachment-Id: f_kuzgou950 ZGlmZiAtLWdpdCBhL2djYy9tYXRjaC5wZCBiL2djYy9tYXRjaC5wZAppbmRleCBhOTc5MWNlYjc0 YS4uODI3NjcwZmI1OWIgMTAwNjQ0Ci0tLSBhL2djYy9tYXRjaC5wZAorKysgYi9nY2MvbWF0Y2gu cGQKQEAgLTYxNDcsNiArNjE0NywyNCBAQCBERUZJTkVfSU5UX0FORF9GTE9BVF9ST1VORF9GTiAo UklOVCkKICAgIChmbG9vcnMgdHJlZV9leHByX25vbm5lZ2F0aXZlX3BAMCkKICAgICh0cnVuY3Mg QDApKSkpCiAKKy8qIFNpbXBsaWZ5LAorICAgZXJmYyh4KSAtPiAxIC0gZXJmKHgpIGlmIGNhbm9u aWNhbGl6ZV9tYXRoX3AoKS4KKyAgIDEgLSBlcmYoeCkgLT4gZXJmYyh4KSBpZiAhY2Fub25pY2Fs aXplX21hdGhfcCgpLiAgKi8KKworKGlmIChmbGFnX3Vuc2FmZV9tYXRoX29wdGltaXphdGlvbnMp CisgKHNpbXBsaWZ5CisgIChFUkZDIEAwKQorICAgKGlmIChjYW5vbmljYWxpemVfbWF0aF9wICgp KQorICAgIChtaW51cyB7IGJ1aWxkX29uZV9jc3QgKFRSRUVfVFlQRSAoQDApKTsgfSAoRVJGIEAw KSkpKQorIChzaW1wbGlmeQorICAobWludXMgcmVhbF9vbmVwIChFUkZAMSBAMCkpCisgIChpZiAo IWNhbm9uaWNhbGl6ZV9tYXRoX3AgKCkgJiYgc2luZ2xlX3VzZSAoQDEpKQorICAgKEVSRkMgQDAp KSkpCisgLyogKHggKyAxKSAtIGVyZih4KSAtPiB4ICsgKDEgLSBlcmYoeCkpLiAgKi8KKyAoc2lt cGxpZnkKKyAgKG1pbnVzIChwbHVzIEAwIHJlYWxfb25lcCkgKEVSRiBAMCkpCisgIChwbHVzIEAw IChtaW51cyB7IGJ1aWxkX29uZV9jc3QgKFRSRUVfVFlQRSAoQDApKTsgfSAoRVJGIEAwKSkpKQor CiAobWF0Y2ggZG91YmxlX3ZhbHVlX3AKICBAMAogIChpZiAoVFlQRV9NQUlOX1ZBUklBTlQgKFRS RUVfVFlQRSAoQDApKSA9PSBkb3VibGVfdHlwZV9ub2RlKSkpCmRpZmYgLS1naXQgYS9nY2MvdGVz dHN1aXRlL2djYy5kZy90cmVlLXNzYS9wcjgzNzUwLTEuYyBiL2djYy90ZXN0c3VpdGUvZ2NjLmRn L3RyZWUtc3NhL3ByODM3NTAtMS5jCm5ldyBmaWxlIG1vZGUgMTAwNjQ0CmluZGV4IDAwMDAwMDAw MDAwLi5hMWQ0NTZjMDExOQotLS0gL2Rldi9udWxsCisrKyBiL2djYy90ZXN0c3VpdGUvZ2NjLmRn L3RyZWUtc3NhL3ByODM3NTAtMS5jCkBAIC0wLDAgKzEsMTIgQEAKKy8qIHsgZGctZG8gY29tcGls ZSB9ICovCisvKiB7IGRnLW9wdGlvbnMgIi1PMyAtZmR1bXAtdHJlZS1vcHRpbWl6ZWQgLWZ1bnNh ZmUtbWF0aC1vcHRpbWl6YXRpb25zIC1mbm8tbWF0aC1lcnJubyIgfSAqLworCitkb3VibGUgZihk b3VibGUgeCkKK3sKKyAgZG91YmxlIGcgKGRvdWJsZSwgZG91YmxlKTsKKyAgZG91YmxlIHQxID0g X19idWlsdGluX2VyZiAoeCk7CisgIGRvdWJsZSB0MiA9IF9fYnVpbHRpbl9lcmZjICh4KTsKKyAg cmV0dXJuIGcgKHQxLCB0Mik7Cit9CisKKy8qIHsgZGctZmluYWwgeyBzY2FuLXRyZWUtZHVtcC1u b3QgIl9fYnVpbHRpbl9lcmZjIiAib3B0aW1pemVkIn0gfSAqLwpkaWZmIC0tZ2l0IGEvZ2NjL3Rl c3RzdWl0ZS9nY2MuZGcvdHJlZS1zc2EvcHI4Mzc1MC0yLmMgYi9nY2MvdGVzdHN1aXRlL2djYy5k Zy90cmVlLXNzYS9wcjgzNzUwLTIuYwpuZXcgZmlsZSBtb2RlIDEwMDY0NAppbmRleCAwMDAwMDAw MDAwMC4uYTU1ODI1YmNhNDcKLS0tIC9kZXYvbnVsbAorKysgYi9nY2MvdGVzdHN1aXRlL2djYy5k Zy90cmVlLXNzYS9wcjgzNzUwLTIuYwpAQCAtMCwwICsxLDkgQEAKKy8qIHsgZGctZG8gY29tcGls ZSB9ICovCisvKiB7IGRnLW9wdGlvbnMgIi1PMyAtZmR1bXAtdHJlZS1vcHRpbWl6ZWQgLWZ1bnNh ZmUtbWF0aC1vcHRpbWl6YXRpb25zIC1mbm8tbWF0aC1lcnJubyIgfSAqLworCitkb3VibGUgZihk b3VibGUgeCkKK3sKKyAgcmV0dXJuIF9fYnVpbHRpbl9lcmZjICh4KTsgCit9CisKKy8qIHsgZGct ZmluYWwgeyBzY2FuLXRyZWUtZHVtcC1ub3QgIl9fYnVpbHRpbl9lcmYgXFwoIiAib3B0aW1pemVk In0gfSAqLwpkaWZmIC0tZ2l0IGEvZ2NjL3Rlc3RzdWl0ZS9nY2MuZGcvdHJlZS1zc2EvcHI4Mzc1 MC0zLmMgYi9nY2MvdGVzdHN1aXRlL2djYy5kZy90cmVlLXNzYS9wcjgzNzUwLTMuYwpuZXcgZmls ZSBtb2RlIDEwMDY0NAppbmRleCAwMDAwMDAwMDAwMC4uMzMwNWNkZjEyNWMKLS0tIC9kZXYvbnVs bAorKysgYi9nY2MvdGVzdHN1aXRlL2djYy5kZy90cmVlLXNzYS9wcjgzNzUwLTMuYwpAQCAtMCww ICsxLDE0IEBACisvKiB7IGRnLWRvIGNvbXBpbGUgfSAqLworLyogeyBkZy1vcHRpb25zICItTzMg LWZkdW1wLXRyZWUtb3B0aW1pemVkIC1mdW5zYWZlLW1hdGgtb3B0aW1pemF0aW9ucyAtZm5vLW1h dGgtZXJybm8iIH0gKi8KKworZG91YmxlIGYxKGRvdWJsZSB4KQoreworICByZXR1cm4geCArIF9f YnVpbHRpbl9lcmZjICh4KTsgCit9CisKK2RvdWJsZSBmMihkb3VibGUgeCkKK3sKKyAgcmV0dXJu IF9fYnVpbHRpbl9lcmZjICh4KSArIHg7Cit9CisKKy8qIHsgZGctZmluYWwgeyBzY2FuLXRyZWUt ZHVtcC1ub3QgIl9fYnVpbHRpbl9lcmYgXFwoIiAib3B0aW1pemVkIn0gfSAqLwo= --0000000000008b0aa305cec78630--