From 57d564795dd26c2166d4acf0c4a200db47e92c6e Mon Sep 17 00:00:00 2001 From: Alan Phipps Date: Thu, 18 Jan 2024 10:29:50 -0600 Subject: [PATCH] Refactor processing of BranchRegions associated with an MCDCDecisionRegion. This fixes MC/DC issue https://github.com/llvm/llvm-project/issues/77871 in which branches under ExpansionRegions were not being included in the creation of the MC/DC record. The fix is a slight refactor in how branches associated with an MCDCDecisionRegion are gathered such that ExpansionRegions can be scanned recursively. --- .../ProfileData/Coverage/CoverageMapping.cpp | 111 ++++++++++-------- llvm/test/tools/llvm-cov/Inputs/mcdc-macro.c | 20 ++++ llvm/test/tools/llvm-cov/Inputs/mcdc-macro.o | Bin 0 -> 81624 bytes .../tools/llvm-cov/Inputs/mcdc-macro.proftext | 62 ++++++++++ llvm/test/tools/llvm-cov/mcdc-macro.test | 92 +++++++++++++++ 5 files changed, 239 insertions(+), 46 deletions(-) create mode 100644 llvm/test/tools/llvm-cov/Inputs/mcdc-macro.c create mode 100755 llvm/test/tools/llvm-cov/Inputs/mcdc-macro.o create mode 100644 llvm/test/tools/llvm-cov/Inputs/mcdc-macro.proftext create mode 100644 llvm/test/tools/llvm-cov/mcdc-macro.test diff --git a/llvm/lib/ProfileData/Coverage/CoverageMapping.cpp b/llvm/lib/ProfileData/Coverage/CoverageMapping.cpp index 9c95cd5d76d21..c8be6f12202d2 100644 --- a/llvm/lib/ProfileData/Coverage/CoverageMapping.cpp +++ b/llvm/lib/ProfileData/Coverage/CoverageMapping.cpp @@ -582,6 +582,27 @@ static unsigned getMaxBitmapSize(const CounterMappingContext &Ctx, return MaxBitmapID + (SizeInBits / CHAR_BIT); } +static void +addMCDCBranches(unsigned FileID, const unsigned NumConds, + std::vector &MCDCBranches, + const ArrayRef::iterator &Begin, + const ArrayRef::iterator &End) { + // Use the given iterator to scan to the end of the list of regions. + for (auto It = Begin; It != End; ++It) + if (It->FileID == FileID && MCDCBranches.size() < NumConds) { + if (It->Kind == CounterMappingRegion::MCDCBranchRegion) + // Gather BranchRegions associated within the given FileID until the + // NumConds limit is reached. + MCDCBranches.push_back(&*It); + else if (It->Kind == CounterMappingRegion::ExpansionRegion) { + // If an ExpansionRegion is encountered, recur to check that any + // BranchRegions associated with the ExpansionRegion are included. + assert(It->ExpandedFileID > It->FileID); + addMCDCBranches(It->ExpandedFileID, NumConds, MCDCBranches, It, End); + } + } +} + Error CoverageMapping::loadFunctionRecord( const CoverageMappingRecord &Record, IndexedInstrProfReader &ProfileReader) { @@ -638,20 +659,56 @@ Error CoverageMapping::loadFunctionRecord( Record.MappingRegions[0].Count.isZero() && Counts[0] > 0) return Error::success(); - unsigned NumConds = 0; - const CounterMappingRegion *MCDCDecision; - std::vector MCDCBranches; - FunctionRecord Function(OrigFuncName, Record.Filenames); - for (const auto &Region : Record.MappingRegions) { + + const auto &RegionsBegin = Record.MappingRegions.begin(); + const auto &RegionsEnd = Record.MappingRegions.end(); + for (auto It = RegionsBegin; It != RegionsEnd; ++It) { + const auto &Region = *It; + // If an MCDCDecisionRegion is seen, track the BranchRegions that follow // it according to Region.NumConditions. if (Region.Kind == CounterMappingRegion::MCDCDecisionRegion) { - assert(NumConds == 0); - MCDCDecision = &Region; - NumConds = Region.MCDCParams.NumConditions; + std::vector MCDCBranches; + const unsigned NumConds = Region.MCDCParams.NumConditions; + + // If a MCDCDecisionRegion was seen, use the current iterator to scan + // ahead to store the BranchRegions that correspond to it in a vector, + // according to the number of conditions recorded for the region (tracked + // by NumConds). Note that BranchRegions may be part of ExpansionRegions, + // which need to be followed recursively. + addMCDCBranches(It->FileID, NumConds, MCDCBranches, It, RegionsEnd); + + // All of the corresponding BranchRegions ought to be accounted for. + assert(MCDCBranches.size() == NumConds); + + // Evaluating the test vector bitmap for the decision region entails + // calculating precisely what bits are pertinent to this region alone. + // This is calculated based on the recorded offset into the global + // profile bitmap; the length is calculated based on the recorded + // number of conditions. + Expected ExecutedTestVectorBitmap = + Ctx.evaluateBitmap(&Region); + if (auto E = ExecutedTestVectorBitmap.takeError()) { + consumeError(std::move(E)); + return Error::success(); + } + + // Since the bitmap identifies the executed test vectors for an MC/DC + // DecisionRegion, all of the information is now available to process. + // This is where the bulk of the MC/DC progressing takes place. + Expected Record = Ctx.evaluateMCDCRegion( + Region, *ExecutedTestVectorBitmap, MCDCBranches); + if (auto E = Record.takeError()) { + consumeError(std::move(E)); + return Error::success(); + } + + // Save the MC/DC Record so that it can be visualized later. + Function.pushMCDCRecord(*Record); continue; } + Expected ExecutionCount = Ctx.evaluate(Region.Count); if (auto E = ExecutionCount.takeError()) { consumeError(std::move(E)); @@ -663,44 +720,6 @@ Error CoverageMapping::loadFunctionRecord( return Error::success(); } Function.pushRegion(Region, *ExecutionCount, *AltExecutionCount); - - // If a MCDCDecisionRegion was seen, store the BranchRegions that - // correspond to it in a vector, according to the number of conditions - // recorded for the region (tracked by NumConds). - if (NumConds > 0 && Region.Kind == CounterMappingRegion::MCDCBranchRegion) { - MCDCBranches.push_back(&Region); - - // As we move through all of the MCDCBranchRegions that follow the - // MCDCDecisionRegion, decrement NumConds to make sure we account for - // them all before we calculate the bitmap of executed test vectors. - if (--NumConds == 0) { - // Evaluating the test vector bitmap for the decision region entails - // calculating precisely what bits are pertinent to this region alone. - // This is calculated based on the recorded offset into the global - // profile bitmap; the length is calculated based on the recorded - // number of conditions. - Expected ExecutedTestVectorBitmap = - Ctx.evaluateBitmap(MCDCDecision); - if (auto E = ExecutedTestVectorBitmap.takeError()) { - consumeError(std::move(E)); - return Error::success(); - } - - // Since the bitmap identifies the executed test vectors for an MC/DC - // DecisionRegion, all of the information is now available to process. - // This is where the bulk of the MC/DC progressing takes place. - Expected Record = Ctx.evaluateMCDCRegion( - *MCDCDecision, *ExecutedTestVectorBitmap, MCDCBranches); - if (auto E = Record.takeError()) { - consumeError(std::move(E)); - return Error::success(); - } - - // Save the MC/DC Record so that it can be visualized later. - Function.pushMCDCRecord(*Record); - MCDCBranches.clear(); - } - } } // Don't create records for (filenames, function) pairs we've already seen. diff --git a/llvm/test/tools/llvm-cov/Inputs/mcdc-macro.c b/llvm/test/tools/llvm-cov/Inputs/mcdc-macro.c new file mode 100644 index 0000000000000..bd2b979bd257f --- /dev/null +++ b/llvm/test/tools/llvm-cov/Inputs/mcdc-macro.c @@ -0,0 +1,20 @@ +#define C c +#define D 1 +#define E (C != a) && (C > a) +#define F E + +void __attribute__((noinline)) func1(void) { return; } + +void __attribute__((noinline)) func(int a, int b, int c) { + if (a && D && E || b) + func1(); + if (b && D) + func1(); + if (a && (b && C) || (D && F)) + func1(); +} + +int main() { + func(2, 3, 3); + return 0; +} diff --git a/llvm/test/tools/llvm-cov/Inputs/mcdc-macro.o b/llvm/test/tools/llvm-cov/Inputs/mcdc-macro.o new file mode 100755 index 0000000000000000000000000000000000000000..f10c849b844bd2b7aa325531d8f2f978b62097c2 GIT binary patch literal 81624 zcmeFa3wTpi)<1mGCJ?YR0YR&R1TEUitq}?>P-!5A6HK9UlToxSZ3@-iCQYCyYBjC) z7&6uwN1YjGWM*_;-x;03Q4w|2luHYEtEh{N?2&)l{Afp)2-y`;;G87Qq}fLKlfDrZ}KbQ=`1%Zip0}X zTo0A1`CWx{WS9T$rB?G2o?oJRSjqiUrQEE-l$z?*)2B_Tshm_(UFU6@)RZ@U()4MQ z8|x=u&Qu`1C=c?f1&fvoDa}HVFg3jzPhpCui;BjxV{`(-6i?-95pKt)AP_bY|8Kfp zuf419{*8nUbZrC3n`lh*oCNsE1o-a~;I&Z9g1Go=GVp=&CA|m2zf6Ez6W~<|@INQO zvlHk;bu*AYFDJl1O@L=4kYAgC|E2`^MG53wm4JU`0$fUjL%s!Z@mC{&f$Z=`0(?XQ zJmNy_Z`oD_OMo+ohQ(9YIUB?8}HV9P>?&>;E zl~7gR;HpE?n)*hU;H@jKWm$OYYlK=?ZKKPBEGpMkBd*Hhs;LpG+%DW!)p#4%lBBwd zh7Cla43SDN1XnVNP{UQXPH3#-`80YeU2ZoCr6i+85B zOBL1u8EI@t#eWLwnm+&iAMxn_4Ubj^xs498ZEzxWT)gkz`!Ve3g)2GsGz+H+D|py@ ze)SO2sGJ-RmpXq@=MC*=EBF>ZKZ)Sn8MnpZC7eGPhhMr*k+VAvpTY6&INZ+h19AAz zI4)90f=ks$4VT2>h15~tS{aX@trWN+4)4BR;ctq=H!oH2<~UqXhJ2wd4$mo9_}k;~ z5{^F@hj(*4_zxu=%@t^VpkBK*xH`9>xNZ&3=Dj?@0S!)lx_ZeP{8AMJ?bF~i#;aGq z2ER-NK{K`}fx#e(C6%y6gYzjKi^$U8>RgW^ax^%VS-tW!IOU;Ug&JI~dx{e^I2<~1 zm1yvx5fuKQ!Ozm*Wg0w9gRj-#!!&q<22a=EO&Z*!!J9R>S%bG}@ZlP~U4v`;{|7ZV zZ*nZvW(_`4Bj+&JD7r_3 zkJ0eU8l2`L>eZ*g$EqM`zXrExaDlfw@~Lqe+^E5|`Z>KOd_0VP(exAbA zMTOc~_@5M}CLd~M;lEOtswLFG!hfPLHStgx3;&kF)U-n-Ec{CfQBB3oTyq&_-G(wwMcqVo_ zs@h>!MoZ+&VB0RkBYgB&xua^bX>1GF75^iDwH|dyZ(c7-pNhUieI?6^tU>D@F;H+X zoG3i%yN3kf`)C^A9mr4&7@jAR-|ra(SKkjNa`hqM9@E%nlD&gdlEe6O?VM(udX~lIyb^Ns-?$QpOk5iIO1&x0FP&35)j~DU@zG zC3*X$<==x@MlPKBBiwcs^-&3Zx1178zYh9~``WfQf2uQW-PiG{Fyu|CxbHEYsg*Ur z9#Zv;^!}ng-)^&1)VD6xb+u(Kdb0ee732v*;XsUs-sD- zSA@-pBGaP69*!+TO02NaimGG3+Y=HJ?di)jA8eaynXEq`F9}4j8{}Z?w9)Q4QAMu?`gH z6JBX>J`#0hR8%2uS*4}$N{ce{d@qSIUw~V(&L?*leG*rWHf#=wzU_LYEZxzvbPrUP z?Tnk1We8aY4X^HfmLpqI=<_91^GTi@|CjH1*f`!O_i6&fiu&2p}_U9Zu$svX%lP9h3} zgKh^YZ@b#I!nSOw{1zp6P?Wwv{g_2xPoJ3GB}%8P$7BhzL}>?xm>*YA$`4E}cZ1m> z?G&X?(D}+FB5ty5nL;*dkv-sv^s&4yjArMzN%yL)Yo( zIBjuCDB{OX>09}Ybry%#~_Dfc4}f1Vh~y_qx!jJhAh8kFn7 z@05DPfUDO)VH^gyuPdspZ$WvHK_O zL!8||{tXb(KV~+Fe^Mtt3+m!E9rS`Ct|-Z)}4kB&oDCJP(+L2-MuN+pe>L#sP$-3z%wYr zZnA%4$I#5GaFy*kUbyyXc`&P8>GT)eh%Ab!JjY;C8!ONeR$)K-SoVU`KfWG3-bucK zZ$SlbW-$se)>k02&^gi%^0}fQv<6Kr&mtk%3lRb3vq9vVAIJginPvbv1YFAj<2J}b z&WAj3y)R@t!EhgYW>z?ePrX=S&xAwTGc9yyrn?O5(IV^7-ieNipG4g!qCfZDx5#sNyfM5h)QGy3WYT5u>{_qECLQS=g%5q_>|^frw(!n*h`AIoU&-fvk4C=l zc&-FFHfcZnbjCSov**EFVxT57N0h#X3lF&(L8+ri!gwc7M-pFu#&a3qF*$ep`or7U zt$nwmm9yd-QTmFk^f)++bYIz}&x@oVpw@@*IqL_#+3O4Z{=Doc`R)e}JB?q+AZPaGLD>#jVFYXFH|iFqy1} z-sEfJkd6#m2_>n=^BaaD9hk^4ChBm{CoB02KKq`D^Q8L|macR_Of*xGAt0Xn02i5B}cQKYaZfH1$?Y4drl;ykj2gQ(D)c#^kNA9!&K$FnKRN zdN&uf9yPUKu%?FG`^%!%W2Tl47V7M6L0zw14$g)?SXMGT`5jp{Xlh*x#|-HqPdWf? zMh>0_olW`P-NfPlU^pr7jtc85DCjfqlx;M)ib zm|FjWGWhy+zHUJ>e27fQFn|Qqc`8K`J^3G}Un^k(`E|0eSFTDwTIs z??mL{oh~28_JRDZjX=+N=shx`y+`OqB#_4Z5t3sgs8d*vSuYjUKWf)EYR)F~KY?N6 zp&|6@=pBr}i?9PU84pdM#&1zVxs`HkW;uF)(fcT5P2jQuxkJF-J0DO+1S(t#XeuB> z1bPUNQ#uKO4iZ=iS-ls4RAEYSL+lq9#2F zHd31O?|`78wkV`lAuALzMdm@WvNhHfA_q^`zh)wQ9Eu?|E3-CXb-V@$OMca(rN zjj=w;S+4-=%1}RAcw{^gr61*I=P=iSa12N<>5&od-4{WJXx~HgVa=43`lq0LasIUAOS=*#e>P%?*=lfCT zMK2=HKpr&N(#|8{D%l_5U}?j!Dx-7uR_D#AQn-#`4z-W63 z9Z|UVKCrC?o70~ow;?9gG&?iG3g?gb=6p0z@IasO4asjK0Y?{43o`rTbmMZz% zG+GmUOyC3AlpRanvYmw!A`=!P+M^;{9qnuI~ zmNQ>|$wv0p?-7eQIN3h=FNkNEenOz%aHm9ZhT|wZ8o;l~B%g&8rN z>OgvKmyby^zu}WMvVNXC7TJJ^C;@8zQm~_uU@%bJYB(##C-Tq0^&&a3B%_PBL{?gC zyj|)y{P75B_7pxnqvY9`JxV*6>1Fdo6zl+-9@Zj9MK{AjrrQn>*y0Ju?%f;h0@@?( zpDo$IaV2~S?SC3g5+8K1<>@)JJauGuIi*w3SDBU`QYMim>W|@uoisDsB2yY$mwxc% zdUs`&t;;@G?{fQsg8+8w2Mcl-ve7q~T0bLG2Xb?rtVPOSKr8b77Oa%nIv4vdcY#AP zeBMip1wNQce)9{)*b7$GBmP2~NQQp^f*Yb#yDaFDSw~0E4$7O6 ztwY*H%c;*H+j09(6lrRG09vSB)h4tzyVQ@a>Ogc5rm^-cQjpdD+Y3m?QKvx2e#qMP zGF4yi3t&5RCsloptVhvNVi`;^ebDGA`zEkI19nAf%_8EYdBO?k#w89?8W|WjF}W7` z)x*rCexL#eazAI{(R{f}y@aG8D|Er&)`C)@XE}?8y2$daJ@n&=nDBCJkWgPH{Xl(8 zT|W7}r;;X*YCmvUrqVCa$t_Wx+lm3+<7@(omhG8Gb1C#T$2?b3Z-ezHdYfbNB+Mo$ zI#WbvWG3VVQW2YBsFX49hERo*-ot0;Hw^hio{ikLQO6RJ2=N=PZ6#L2t6+j-+yE=d z+dfa=7@xp6n9q__zM2XELF)TiYQsILB#W(TFD-HAd>&O#y&ndkrGDQ454>i$ z$h>A0xI%wN)yP*uJ{TVdBNysG99rb3hgeOY1$!Zj!AJ*3lHOPPj(1=J#Y{AkY3i4@ zW0s0+9fl4RWx)OjDKzY^Wz7({>TqXJ~emn+fND$!%n)L|h}+TNQ1rq>u#9?~tMh`^}Z zKwzz5P=}A;n^=Fx^mkwzT>4HfL?kt5DEu*-&^$+uVUvPI);;n(Wap3uLEW$iV;lC; zK9)^`S+_kI4LG9xQm)>wK4a$m7nMJdJ3Xr2#SZ@!l=vcw@f$9VX!;0B2u(?0Xj*~% zc&ps3v3JaV5r(awVApSDZh$7rW~5|r)J$aEN)rc6dgcgki^4C7AeYibymW7tAE zu}hC8KoN(rks(inkDx`G;DA}$4hdr&_Jt~`O>M*w?w^)P-04u#iV@}*+Yr^7Yb1)# zY~>WCUDmMtHfi-BwMvU4`zMF)s8fg0C)j|-^7GFTh1Q%QKYTIWp_Ne37^_0)4i;(n z?snqIkf(mi?7IpYz`liKJ68Ry?PydFoexc-28^*E%CX)^eTE9OmJrj%z{mUl65Z}lzLH5E~_6cTF>qew>gu9%xFcI)-}3UqwX+ZSpFH2VT*|5 zcbHme?^@2l)*G~wEsUbgcgmmVk~4S8AJIrZV7Y!pC8jw*H$-{Q|OHyBl&s6NgcFJ-62~{EnP^7fOVgE{2LK2)Y?g+ zq%k)_E{U3jO(UA-R*|GGLkVEIXyn3#@e_FhCRl#MB&N$8rps7xhAzVgB_Dkul9Afy zaZS344p4eA;5|TEZN!QT9$;$0h=UH@bpQ@!YGG5&z;bvoM#aPOxp+*$n08W1|1I4F z{t4xQ7N*v9=+Q$P@L{K7D5Yqbi7|n7^`pf_q|m46nf81F{=1nZgDVn$gz7pl z>L(C1LCwl5^c(QQAlH1Vl;|?P6ZbWG8tVTbfhI5&AG7wniFrrvMyv{%qw^)va+1+y z7y%h{k>T!Oz1b)7-AJg-kA{%fZ&8G%D?(=|LNARIDkwrs$vK)aGI?P)gzD~2lcet-O8_kjCt<wWofi!A8~XX%EA+#3mqL_j4alD;mH2T(eYEN_=52GU)kj_ z{o^Bf14`~p#m*I;au78-b$z0acAd4ojCvlyce5zVK`q!A9{@c*) z&X6yLR7ZZNsr5}*-|25O$~F~wnQGX7V}|_oNW}ohLE#P5&}*!S%im>crM*TlWywRC z2|DEwpq%M0g~_`C40-Yp&M-X6a1P7|Dc+S}5aq{sHd~_E7&yZW(RcG&oi_&xVp?${ z8EcR;wb6`!Q5Gm0(?52RJ^WYZi8@SXf(_`V*PX+LLRbjT>(qUDY4;BKLgautxOL^i zK-$F%10yfSoB{nzhhH>`vz&QG?-Mq^n1j0< z@1Jp(hr2xQZ$w{Lp~Dv}wC-`__qliW2CRE}rRZQ6**~Dgmw5Y;HnJHulvg@1Z`eoe z2R%z$vmRFV7om>qnT5DnNjG`L{#(q&epiOWe_fV*P7Wp9RqXfXIsCVXBIW=V`F04v z*qMfoiMlgW+w~Ac(*yIBfwU>bXdoa}%o)7G~{zZ1`)bZg@`L5T9873-2JBQmo zq7((07Y3;zH{fx>SoXLe>M{<${$qzu|A~l)0r?+!#>;;@A2OeVW#}@Ct-C!R(xZb5 zZ5I7lg~|JY6HnioZ2q}<@F&Ieew5YJLJisBUkC;FirMd*+6thLn7S-e6m{FhS<5oB zOn1>Z@9Q_Z$2fGaIszm0&ipS;cYcXD~RDvG5m)2D=~Y!=sS68eUZbrD^*N&W|nB5hnTi5v;Jf=F3bIi?oQL) zX}Sy39Ud@@w9<`$wx}2L`@G%Q>wfYBXibwtI&Wq(J-cvPmF=vB)8lI1)I!J4XjN)) z&O#G2`RI`fbx7p9;eE_T%tvhgbTk0+eM{(7Jbm-^TN?G&eZ9-2?Y>WY#K5#{Yjizr zGTX1{Gnvz_u$j!u3Ix-NZrs=l%%&B1{xKW~J`qGmU=j0ALf`!Drj`ZaaQLwd%uS#X zY(#SVXfVT}Z>L{Bqj-p&mDniee+&DO1Op_5+K^oS8@B1Fm7^A5g`=ilG~otg zqJt`zE=<<3xFt6edq=lpQRmPNl0TmSZru*~BTyU*fHyYIlglz-kk)?B2d1s5Hp`&i z_f)yPmtxF5e;tyrsm32?<1R4jp*d_Jbj`bX9>%*FG_f@C_MOy^MLSl_1h*>oc{&`A zj$+7N@L~2K&E~sRk1pmvk)GDI`|$Mo5@wLdhK2kin^bndqmAM1tiEQI=o@cBlf!f^ z4f_hSGvyh?gBy&z{snqWZ1*Tne0qnqhj%%`ol=J*|MkYF=bN@}oM9}&m>a@_@G0n3 z)7tHro_F-<9sb$)cj_VYW9dt|Y8-lj@Gcwt_hS+asp#R-Y|?AJe?McK6{4-Rs=ale zXHDctgi>6a^tR}~&4@N{pvUuLsDP33Idz!O+-gMIuoUMX@m#dfKW)My|3!6dq9)PGP|DtN3P zBw+X>NSEPZeA0yjXq#~>jrtRVAL6j4^4NO3#CMxf@C*_CbHby<14!mCa1enJF9?sC zPPbi#sUUQ98La$nC7wk$6BJ!bC6)3CBM#Cb~*k3$}B^eN6~3=c?XNyDF*DBE1k4M>BODI z8F12*ks8cSXcvaYG3gkdvapr@!4lgN`FE6$Z>L#KIhz!1$=r<6%j0?AF$A!ia_3OQ zJxH-z$Tk>lF(-RGa~lgF8;S|?Kp_QoBjA)yP=AK(TQa*@xYvn9)PjoX&@N415Y@w? z9?6tJMZZ4NncYWl9}A+YdAOgk{VS7BDTrMytQFx_a1Qz0n?V32po{ML;b`;GqiMUq;&%(5eIlQc}9@R z*M#kQ;N0;(!fD8H;!YiI@(9K7-c?xDV_tsRE&C0pzhQZLR^deIVY;XKA>k-u8z@o$YsqW}1@s^Y zT^O()BW@JF8NuivGL*SyXbxt4U54L-g)U#g9dw7Mg#Ln`<1RdE>6=W(G9t>LXQSIL z!xbQObs1*!JL{g%H`qOj4hC57p-*k14%$c^4}6CjH4ST20d!*_wL!B;6m{o0gyt!Q zL3fLQ$f9slqTZ}jqMey#K-aPWTBw6Gc& zTc@Ew<85I~r2-{*?+#LY~nB2NwER%mPq}YS}%e4 zF2fE)&}9w!hds-fmOqA*^-(chMM0_zF3NXe@cPlHe9xKk_G8)CJB8*7xm7IomIvjJ z#vxmO(PkXbhg2i(CKw!u^aYKQ!KrXPMg_#|qIe4%*~R?brdE0qwMECC!noRc&$WJ_ z9Ai3G)S}x)+L~Hw!66m3%riY}_fCT)KD0~EG{JsS>qdO~4PWDMfq&TN_>8mDUV;+Z z=^=`ZwbN9^*HpBF;bT#8IWJ%W2Z++uqOp;(dY>miKXr zjV*6FEAQVBK^K+xVcgq%UHzhTUBoZg6w;-77)>B2qO8}&i^CRgo2m5$IAqm4ACwoo zi$jyqm$JgoVcaPE*0EIhTQ<`X4;*U5^x{)_?p~Tx-m;mdlm(-}DHU9RPZG#QnOY8^ zbD}48PppI;ddHwY@q6zJcRKwHP<#V>cD{ds&yJ^q-uuXS8E}_(r5)INTG);W7gOcw zBV-4tGJ>i54Ck%m3O#M|8cL?GtkE1q%+x-48-a6iZ*(vwsx*ffD5Hxy$#X*~SjX z+f8$SL|#zD8JJW{%+i-dQa@#!B}%Qt4cpl|4(a`dg^2bKE5s)`=^|8|1+|8=Wy3NF zOIT~idP!SNYxb_{GMoUY*4RU&?}uz~=N%_XcnDrI6N8`Ot!F4dY=!mW%Xax6xyOeN!k`q3uF>#}8XH0q#$fVwAf6V? zGqvkw>pq+A9Vv+Yyi{>qpTAfy`Z{p;ji~Dob+2JxFU>B6Am8M>1IhhG_zI9Q)w}0; zsytu6-rI5eEot<7I@>Tf2;Qgc{#*3)fS_nF*=D)fZra*I3q1=v)_qVe=nsb@Q`igV z1x8-#+ivuo3`fo88G}qhYhc7Erdi)(E|$g~^@uR4ZnqOl11zs#=FmUknbu&4eiw_K zS?M*?`VNmQi}SxWwOk0;abx(uwlAjT%)X6JV}n4q)2aImUvJF+5cVbeQ7qYaxf+YD z*;g2Y$@fRZ!@RjM`w`YXy4ND+wPCKRF)(cj`gW#4dgEFfRw6b!=bP$%mF-57ad+Bo z-m3cu);UP<=WeYekN!md`wq-tItNXG7h}_OkgtD= z=VP4u;9mp5H+kCqhP%NVUC&AdH^qdPvweG14m&VITLvkzaVM>Vnnuu}n0aEwJCxHj z$ zXGeS?uhV483rX%5oifLi*A&VBosR!udF9jr^Zy8P;tKt5^1lb%XuRHYTqTZh0it0zreU6gAMXD8xV7Gu*yIHRK`5VK>mv8W@cw}(x5#>^d6wXrL}Psh0(eHC z9^x!QMy)}+X>m`HbSbqD4~dWlDJu(lcFCU1#qOoC_N;t;4*I--sf@CJSkxN4HOCQ{ zufq&yG^@U-|AaeGcrhHb=XczaX4-1@ot)z7ZQbWRf=tf@JD&OiyioeSn;8m&V2Ara~G(iD_7v>$xRdQ}M@j)Y54jWo2t$msgm zmlI*dBiI2>8eQcpd6YGX2-AJRpJ}QC?VmBeGz0=MR*VI2w5ZB? zDSW??@2WqESh1qd5tuz44_?IMAB*FTi{n1VchJ`jf1Y$w%5!~41S8wOgw3hXi;ATE z^c_OP^m`i46A(LPF?fm|2lIeb?L8-{in&ci)Pk-LvEFO%tfxx+tQ>^Ph% zcATCgW*Dk6^K9roz5(drOM9eCKb z$NP2f6Vki4e{mX9CQQuz`frL+r zOi90X`t9G~++@(Ri`nOl_}(Y*44O5M>qBFa5M|QVm*4Q^!PxQYeF|gl+Ctd~fdwXC zPk(egP{JLD^}0S(NTGly8@?d1h`N3Nf`74|N`98_gt2i59>@fHYw?^x+KVSvRi>}^ zScCZ7hyNfSpQ}uDs|FkKSvfeZ%2f7Vm8l&6r{BW;LEPj2^iE9HFdf|P1$cUUm8oI( zSGd`Yn~vqU>8LW@8Wi*QdN9Q-#3aFUt`X1g@vJBRP473@hv?U;G!!Zw>%9U0O;MeW zMRkG~)~(86`sDl@eLC5rwZ!^#YV_G?Hsaf)Tpt+D*J1JC=l5j+u zO1I0d`-zSA)PmW!a@G2dng8P{;3d+zG?h0>i}k41Yo)i)h1vtv$p7m%(tfcyNKe3Q;T0BSPg{vbd)vk=oHfKLrZx~pvbEoZpqvtjp zw7{q~pS4o3rP%{zu+|}L4vfxp=8P+CM?N~fmkJ+U!!%HpFu6b=Wlkvz1 zdt8UD`>+lPFU{eP7j-)w;ayHhZbG#Vw($D{T}i*=6`kE8XOp?gp^Ja7p; z3aWvm4mccZebn+;>x<0qs%&uhbIe34&l#Dx1#XAOzv+E5VGBfa>mVIG7sk$qFirNP zoAF~5;SOwEdHXs(<^6@O+o20OC4DBDkohRDjT^9WKsH1tn%SkJj$N|pRU={vA?+Z; zss0LUvBWST`5YbuL5aC-HRN$*N4B2_QG*~7 z9oup8Fps)ejBlbZJfsm{4(;EuO^4aNczc+3;n!b;egZS76QUJn>{!PbpxPVCPUc%Z z7;}~JQ2`*tZ4v{E!=m*KjMVvWm>%HqC76RfX~AIm)K(0CaG}fS`!eG-Q?2)(#T3`@ zD!%^QX?PPyC3FQex;C16&-EL&0%bur#@$B|2%~zmKatZe75tK=e1KA-f0O#Eq-6`H zMeP?@P^j(iME?SdHmuGc(acRP*CS)me?7+B4?I7|SGDnQ`#To#I0dWpYCw@*JBVq=6&C^bx;1V&P zgwAwl4~4>eLPV*rI}IDWkCHSObb<(86#MT;M#VNgJ0Ej^Tc?YdEx4lgj`Sk!l-FCV+Uv`;~Y0?%^zZZjkNXM{2FdjbUKX&lme zV{e)$ps!cQBX$G0}Dv{b+|R%nTJxcld2A17y7*u z)*$$v%*QOY1<#7g5PQt91lj6LElUy5C>yfF(vkT+dp1E1b2c@Z);*|ty5XL)2DV=0 z*MEmelBwktvP4%Wq~SLJtikqTsS8sn#a}Lfzu?>*`3wI0PH!*vFJO}__{+ZhQO}{! zrn`Pm0{kULF?+A+&L1csl^8?6MN;N3SZ8z^{&0Y~%&$P0%iN5VXSmGwipxyE&I;P0 zspV>jD8?ydsS{>^%it)TsTGeg;4>$f+c^9y$!*l4wC17=irYZB(WKm+6@ZxAj3y1d zuBh8Mq}Sx&Q}p-*J7nZMrk2A@_NAh3vBrTO2dH(RUn2|$dKko^+g&UzFoyn)d-#wD z_X+)p?(u!Rr67vm_;9<<<~Kb2F87=JaYKG{6Zi%#A$IbcD{(dfesdJW8jL*m4HZB| zJlOA@6ZM+QNVeiNm*UoR=NuFgKT>g~%XrT{X1Ex+={)ICi5I}Wkr37&)V~@+zs3pb zm=5-0WTEL`4WUMG#PzT+Txb>GXm3OFH^YCTP|^O)e>HZo3m)AMrKQ}hAf{&*Ph-c; zZY5ihbCNMdX_SOWYw#s2Pk`Mt54-fk)`6wiKcuKlucK8}{%+4Cr{7S* z(6pd!8#qy0d+59pCf00y6b=?+sR7XYeeXZnXkdDF{dDT}^6-UE_+Yz)L3%y1Jy(&-V*)0ar_Tmxj!FLFMp6NSL)%W%=g-!ELLa*ImpvGit zn{8y{{WqqTdGKo5KSva%2XDL#W@sGrbXn1SG2UUjlCNZb=zR*S1+VWQe$ysuVK~jt zkrrp1JM}r_Y85G=&skzgtulFs~ng2;-dAvjctC`VOD6?u(t@plok~nGR@m>dyr& z*sccc=aPm6|BQx7#ezRY!=xjA-YS2;cN;C5&ZqUJKlgUVunzLhfr8sH9CVa;eCrYMg8Vr?Sjt_14@BUP0Y|3Cx*fV+JoKOuB)UH-Vm$!g8;NOBVA#V* zh&fh=k$&VrzZ?55rk2|v!Y*}5Ctz6{HXvcyW4%SbFHSiFb91c6OlCR(S=cSYEBJkn z=Dsg_56Oi%C)uf|1Jh#uaqmvD;l)_>(+`Gq9E4oh6EaN0^_O#AGx@_2?R*3K6|my7 zc9EtiH2?B1$iSi=zrBFrjGD`Dps(nkVS0Ai3Z)sh0jTnwG&T;R{g>W4X}|Aq+}c(% zAHjNZw2qdyI(_2FH7##Dy>BO+T%+ahr{yj5Gi{x1)%DZaSe)(rc1OFf;JSTK2)`e9 zk)Z^4*d*5!ud2P%kPlQB>7P0c*~A|SO9dAq99`eXuD4|Tk|26TELP-s>~4pABPe}C zp^=4m$v1NjqkKDy>6Eh>-6dNY?JCaxn$A6=s&>o~eV^g`)nAd!kTd(BXnMY9w&VEQ zivpG7jZV|tgYq!M;qeXOreAdg(j1Prj>!G^T74XN$TKhXEqVppG$^+nVkIJ@);JB0SC zD7}Lj9~})ANsU5Bb{M149Eb0VpzK7R_^z;+9b$zLkH1qKsGO)2E(dXOR9&}*K^B@bNWXI+GxaB3glD;taAniZuzQe;YJil@3dd1YyIMjr; z$qL4{M){8k(Jx8{=Huri9?=;Qp_!*+% zf3*L`_Y2F3QF_mr{SB|j{R;!DrW!HTeorn!Tuf2Lw|bRdHd6KsBl}qzdBgvWydUr_ zws?7R&zaz7noN}TjGv9j*6d%=&uMDIk>il4U3R|kT}(gds9GL9YRhqS!3O9LUC4@6 zMJhSg)k?@A714yAeLo+O4lHJ)GY!7Kh514D+hnJ~A|~H7|2UEXY!t(2^-1S0=`oOz zeVO*U{osWwM%pL%^Jtk`h*RQlx4@_m-XaHM&&qM06o@|NLnCifuseJ7D!s)|3M4T zdtyBQ2#4Q{`~Op1I6nTqxcDsyV~fGLqS#X6uCKythAc(&I-Z%9`Q->yT0HfZ@r^?T z_R<}^V#k6v`qaBOOpZ;msNUn684*xf?kTs_)q5=T0w28Ohh&iCnUFM@M7dq%l^fL9 zSV?DO&Rznm33JLEmVmZ(oiw07DiMP&E4W9D4N=tPeURC6+b=7&;dxb3P zT<%7^U&vBh-B?@hsaOlSuBHZ8g$Jb_UpdjT+Uv34g+;g@I-u;RVKlm3G`{g7MZXwz zt}b`iRoAVVX>r1KZm6=3zum}EUuD6|nrhb7mNqDMFRk>}Hdrdk>nt@e57`VaXXu*({A4>MAU?^_4Em`nB*JO~#egjr3xs_)3Xb z*iK$oTfV`v+694bx3__$S9+QKR7Qp9bd_eRa&xS@qCA~sFXfpkrhQt<}O~UfRRR|G^wTV zLsfUyI2+16Ye_ZoH_N)}a-~Vd)P|CBG2Gl;4LjD?L>+~t)+9YsQl+b^+*{+BOqsgN z*9+ro6!jx|MeM!2j;ezsP-DS6$Sm+7W<%y_$O;}`NBUWoHVNmlKyucPk5vaZ}+O@*9jal5MUny|VG#a{<5 z6B##AnZ}Q=ur#8NsjjL<>!e1G7RFpvMJs_+xTrO-PBNxOBc`DyttR+yiBav1mWUR% zMyROAd(+S-QtK85Dyo3jtg)WcR^kwr*WFlGzrGIdLL+q|9=v2(sbi62S?S_M^WvPA zw+iZ}TjXqXc%?3HvkQOJufZ~cVTvA)7}DdEFn zG4BJ>6SI~$zR^;}hDfC^an!9tj?t#Z`eZZ?>Tz5``D%fFtIy?*%_35<@Q6!27J8GO zB78l%aitq9Up>IE!c~hpG0P=l1yq5A_0@Hi1IUS#rlmQHuWz6iHd-dt zlAe}H>l!BUR@*qK!R4ORh}Sq4%&xnF#){}Xk|rEXXv98hA`1*e6@mt9p}uIcWvGA& z9ZjSx^_ZNY1>yylp6Uv4v0kN7FbP$7J)~7fpE`Q)rS5{%S@bSqdUz=OIvmc?3qsig z;qXe(2GDNMcF+va<_E*!2GGr*?VyFf4~Mr94l0B8ftqoUzUL3&@NCd64~N4opyoe? z!*7E&fPN3!4LTa9b2tA-INS`H^H?~%8MF*^8)!S|0nqOM42SVEokHQ`*t7&~2dxBc z{(CrlAB9051KkYzFVKc9;cy>l&XeJ=1)G#Tpe3LdJoJ5)C?3_0#8K5PpoO4?IEm5( zx*2pcXfw|3%b@1xk>60*HF&?+r#0< zDGZvHhWOp#FujSZ8MFm7_!{g5+6}rBvBXB{K=VMmL7kvIpk<(apdL`+ z-Eg=K)C~F%XxV{qcsFPR=!c-qpnah2p!(sc7tjpQEua%Y3*SS%f%bqd1MLH)H+VKpz4Pg3|loyFqt?_JAG$?E^gm zYB`AVoQ-s!!49CCL4%-MK;H&6<0mC$&>YZHgo9>|MEUU3n0cTLpiWSW410hUf_gwp zK-)meKpz5a0HxoQYQ~S!^;0~4g065B;z5^zHh|Kb)Y?ItL3=xchlXE;!CZML=2lRdj>&EFsDoQU|I1p}2FQNKuK^_@@42J`_r?UG}QW}`DE7FZrpN}BE4e?YrLUFno zF!O_d0pAS#BEng^VwP+X;)(Y|#BV`-0m@48%+I3rcnj*$mNv*N6e8M)F>oiwr5lkZ z#{Q@-DkQJ`J5y3uq)^SGexntLB;?CZ$mn|nho*3^=(C#XGZ8_0LuBTo;qVt)T^2@d zmwKsARfoD#;X&{p`b#*B;gVg1Jr1l#gXI7V0{alyE-n}K1E03T?exD$g|-*#(k<|F z#nIr6q|5h6)ASg=R!Wi)qokn(_oSqtH8Tj#VnHggp{TclBSpFukECYWV z_@_s8(zXeEdResGXcN~D>>6b$O#?*~rI%F?gd<;Sk2GI#{xux_4)-zjsIANJhm(r`oiYUnD$^Z-1L0)gzq~!EgdKOw2D-H@} z%miy2(p7H7JcXx2o25ofW7AdY*hFz#!1oaN=#<@nHi>OpOVZa~lipxUZE>dDa13N9h+Bz&Go1QE$WMi@3?P3&dbd8N@xGXTKtDGfU$sC)YNl==$u>l>{;>wK z+h4%k1)>Ez6iT_7jWg8V+7S0W;%4!DSzFMIEvc6nSc9N`@M-WGJHlZQb`iE40eu|y zAu+^ZeZWp({;o}{$DF@E4$A=ceH=CsSYI4Q>xd(9*fL;p97b>OJrsv+1lFU$M5x;i z>_cGmJC6g{Kd$dg?HOL;3zZYR=h`giG?V$)H*Y(cuwo#8Nw#4f^i0?W`~)IS{n zHWJu8;zC`epl*n_54aOJEtlvbUG!;a`@rTB5aTCGwW5nEO1EHQ!1`dN<&dn|NY{XL zV<{aj!b*T`1cq$bMOY=UCSY2fn}B(MY1`o@E>BHMb+H*(4ft#{X2s~1nyb@jMESf5 z-uA9oKkfmxDGvJ{SX&%s#Jaf!7^2uk@2IecYw!mztT2tq!Ga3gULAu>YCy{(s2biK+B5REJaj;>aPFO_J zBama>6Au48QQxBJZ!vXTnW%3e+vH)t!2U{X{W*aZ0=tIv#6^5%z%~J!#SjJa0NV!a z0*;ZtwgKA-Oq~m*U?D>3Hv><5H5>+E7hz8$U<9W1o!!9nz-aiOi}*gIL>i37&pu$M zkk3T20sLv8_L_R5PE!f+e$)@<#W7=c5ul~9kU;WFupja&_H(Ah$VXkp%r#P9L=LPD z`DB~K6`cX08__aRnYKXwLvP@8ChqAXY$vb-z_j)_0PJmG*N`5#h>!MaEZFlQd(%aI zIz>zbM)P*wr(W0@Lce30N==+YIbqz|^sc%KbDjk~cWf`Xa`UQ@$FgJ&>GJkkgF4u5R29 z(5~X=!_N;S2O zS|DkGqy>@|NLnCif&U*_pdHW6>1yYTff63Rbe)3F;MC6P&p4$eAYE*K2vps_VGB=$ zvE{+87Pc8F2K+8Gk?1;KA;LBuKbnWtb?OhN!}SC;;TalT>VCrkzSzQ} z26k=c@#>z}Ke?jnS~-LB;W2&8#gk#7ufTly9?4H#L#u1Mb9rjoccV+ivv|g;-dS7_ zwuITG=8vBnVC4bGSWojXor9qZzlFf!RXg|b@ZCKA1P`nBQ&RoE=d*{`W4uPwxx(`~ zUBPJ;r|USqlhgY-{R^jCIql?hKc|N|J;v!Etg-1jhto?qozCfePFHYR#pyau@8tA; zPXEH`R!%!P-OuS^PLFXqh_|P6IK70^>735zbOonXoUY?k(H>v-d{Vh9e2UYv6^}Ry zLU*b^bziTe31TW@&$L)9*YXh?MBCQ1X@R5#k`_o>AZdZ51(Fs>S|DkGqy>@|NLnCifuseJ7D!qkX@R5# zk`_o>AZdZ51(Fs>S|DkGqy>@|NLnCifuseJ7D!qkX@R5#k`_o>AZdZ51(Fs>S|DkG zqy>@|NLnCifuseJ7D!qkX@R5#k`_o>AZdZ51(Fs>S|DkGqy>@|NLnCifuseJ7D!qk zX@R5#k`_o>AZdZ51(Fs>S|DkGqy>@|NLnCifuseJ7D!qkX@R5#k`_o>AZdZ51(Fs> zS|DkGqy>@|NLnCifusfg_ZC<%Z{AEx*7DWfI*-?4y?pZ2$vKm(UKX_8dimv(bEai; zSg5EeuUlhT=W;hz*VkFBd6RP{=d7vrShCi7JPnOAr%XX$t#|e0iu&3qH8ty$k4X*g z`Wsvop2@_S@2Z$~d1dajsn*=fUAa}c)2-Iat=7uQ8Pld$S#zgWOwY})nlZzbm;HZ3 zUQ;WprkCeV%c-oYthDBpmrq4bIhW^@&zL@AYJMd$EYDkAIn7$0t=LX|p98(GLVc&g zc;7{LO_}79bUHz&8#GavfjITO4X@yZ3hKKXRK7Hw<{GLSH)NP@lCGe@cHWrbqijW2 zEq4@W>Wni7r|5Kp1)~nHav4S+BO)K?X5n=+gN1W*#-->CDY!GH;e9v5Mhe4)5kv3> zh;wrW4Wrk*;Ladq=vtebn~esYK|sE$z$`tb8jzoyb|jh3q3|%sG1G1Z*}bH(WSZxG-nb`Kdw* z-Pw`Jc`1`f4n$CKahGD#QMl+rJrLZb=2Lt=-4YXC%7Z(dQ%|4g5vy)EeGa~gawfJ5 zbCzE;2=DSia2aLlV3`(QLa+BhrmHAZ-Bm25gFXfI{Td1VVR#zKpj_&^Iq2O$DR{5Z z@F||!hAFibl@*g}%PZXVlPfsm0EFJlp%=b6<9#2LuTDr6R`M4HS$Nuu67bXOlv0HB z$orMl*SpM4z`ua=_o$2r)8)WF$uW~a%|-7%CR}}QlN#m5jZPRV6rzIZQr|OjE4v>R zdCwAy#0R}!nCTfOpI$$s!`o!l_cp2g-MAUZJ|88(zXeY63nwcQzEg{2+wi;E!m0y_5D-b9PgtS1>?Gr%XuF-$+2)bTpgj0;~5-R-xGC;%PG5Dk;7l# zBT&b}>Scn0zn~D|GLDx_Q~;_!x(YciOj5$rA(yTdzz3?YngsZr3GhE8z=xT5J@Rr1 z7M88>4ES07PE!=&u+RaV%C&i(!Z(W>^j*&1!1>h*_$)!bI<&)q%5_cx{8HdLI8`No zuaa6X3li|_(Rq;m4Y`W`Dt}o5{&h_LSi!^jx%q{AINlV8|B>Sx1NKOgIn>c?K$D3CxfcoCFSsZWY z_&+#*F~_^P9Mum?fe%zK>wuFzABijPZ5-bmXP*ZW$Vt?H{*%c$TX_6luAqhtq)!n1 zWCx*2VPx<4#_d6lH*j2izuRe!_lOF=+I}|Lg7zEn65WD-ptF( z-c1fXtl~=<8)hWRHDZubu6CCaR^R70jpOEP6nrAuEnUkwUbajL|3M)_4aYZ6RRABi z+dV2j*MB(Y|1-yPXh6iJ+W%#aH*@~EO0@6+$1QRECpcb611PR3Tu%!MNcCmra^@+~ z!ZcQJt{lgR*f@V-oc!xJ-czM8!wuL~$MKRl{x*)YfgYS{x&F-Y_Bi`L$MLc_IrKh6 z(%-@rZ&tDuzT&t!j(;#RBK~GxkLr6IGgW++B7mDi$m6(WiGr(swUp!Sixhl4&$pW6 z4FwAD0LPnDey0L(cN8ArcuuZ@A3}ShYa7Sa_u9cN+10JeuTa7Wvg44!|`@*w-ek?uIBibixvI??ixSmcv+l24{*GJ%Te`wisQ|3 z_-hE94nkC(8HVuWD1Sm?L~br-*n(3QsC#jzIZW&B^(#Hosk{8Y6$1|T5?+gyq(Kw=M^IH zL{Bh&%yZ6G0Cf%fR028Oz=x-tFO)s0@N@SUK1#rU61X{K_!;#(0u6Z}{VxG-;ks$b zX>?E)%!>+nzG~cDk^{Rn@OEM65vvo(_i%m-4bZp_D@3>p`0$jmg2?Cjs$cz$^PAy{ zbRATPu$S?lFRbMHsQhmcKj+bs&$*m3J`Qf;ktY-I4})V+xy-yB@orAIlyI$Jem@hq z84GK5J*BePfKz>~jjONa#GeBGr&Lab)+UhOOgQw(S)%Z%@74VS$NRXRYQOh9!%c$v zeqA+}U;_DXaXIaLeRM5P@NEMAR7{CTpUo>3M%Dhq30E`I&`jWDhmyGZvH~BMG7h#- zn8))pPT=O0(ZaSkf2&L&e*>4JW~s`#kIA_}cqUHH-xA1qIRXAo0{jcYVTWM0lJhR! zFAYL_A%8B6TgQzCK9GH;5Dq!rS1EGFs&)WwP8lQQ#ra8v%Fp|;cFunX$1N)q;OE?~ zzXwkGWX0+8pPavh_j_4f&RZPc%*&q^>`2bSMGhW5`;h%hbxu0iH z&iQ+I$Cl6ey}-#&?7SaV_1VPv%Pv(Ii#Y#gj&J4}c60nyj&I@qiEfr%pApXQwS?Y_ zJPs*ZxSy^AYrlx*%c};1hr{3LITJCKU@c68u#^rHUPR<#a zqqM5JuDZ0`?JnO?>Z*AErMI?r1CnS$rQr0$u*N)kxgCp@0xzyZf*LO?i@n@aF03daVj~}l%eJJZ+*4KWu63dwn$E~#xu?43 z3=lwEO>w8DmeA-auWg9S!%+wCsw+QJ5>pc5)|NLes;{%Vs>;1J9)OJ{F85N@IYlh> zlzXZx=GCL2;Zd}(*y~wbwFutQcy+nE4i(Wz#aGI=#8r-lr}4Ci5qL9Q;;N{3R|-p( z@f%d|B5y6@BKx4?DA%jqolShNTOwTX9io(IR_k=@}K{@|6Cc(yiV% zlB|fgxYMPG=s+T{5E7T%=x+V7zRY8f$F{I{t+j6f38{Bxy2sP(qT62$S6LggkOA^tXtTLKZ)oDOn^ zS)QDa>IN})l>$#j07vFZPlj1#9$D|hA{V2ZY{E1yEXV?909KuNDVPEy#pNhT;5cr{ zbqwb>(-EZ)mWvVyVT8%d8HqP)Eu#dnTmbiwJ^(gN;7IIwkKh&^&a-rKi>WM1IQ$sd zrMc$?JwZ?v6)E-m*}Su&G*8U@pQQ72RHql|qNwi4wd(8Q@s$E}qdY-6bWFUf zT1`~xWQp%?R%yJrO^}HU`voO2B>rL%j~(!ni@7-QfF%fL2$QTHjgdwtKJmtj4VgEq z?Fjfg5kh5yA3f?{oE`B3P5_ZEwFvZzI0lEYQ*)dpRQd#&ou3nq*e5K;O1Gofx~rVh zfPF?r-28;Bm;-z?{>S$KZe9n9mu2a7hk12WuEc_dCyzdik52`9PX|wYmH2o#ygI&) zultAR#~nDPxwYX`QE6Qp@pR5ZUoqO#sc@*oybLp@b~pzoc^&9ezr#LpAm@)T=V?(l zRB-S_9wW}lX^-zVfY>^%Z4gezrC74&p^2e#C1k}q(tLGra(;Gr6hG)a=ZyFhw%MqiYoJc5|E823_r*NS?(EZ@9-*+SERm7t12&Igd!leSPvx8sPCJi zjQvuk0tEo`d{W+frf%%n^+mj{@vkqAsKURd2(jyJ0qFvOTt+US18z?BiX;vaEE7#S z<7`wzt}B!581f2ajv315bei2o$9eLU>ZE8o$(wmsV81Nq$PUfylE=d^)*8M*gevA-d_E>1t5QUZIVJo zh>Bf8ind7+tOdUdCl+GQI@a8d!qxG?cv>};07vtWk!`_nGOL0Cva4b3#+cm-a2*d0 zKiJ*d+1@*TxIY-|4*N^zQD)gNMIF_7S!H=M4VbR^9QBX(`iFbN?c?_z?r#g9&@&PF zVAE8csZDj~74TkCAO<}~&7@=s*ti(e$D7gM9u(O`eUjS<{)>TM#b><<=th+D5crM> z=62Z}bt8U&%fp5Ce%AH7XwwyNUJd9CeA<3vN*<+W_`zeUOSroZO*9M3_bvq*3xRARv zg_V)iMLgqz1lDcC-1|FGeD)ZuQ7XsF8gN}!6N4jesYO>uM?r0*yFUll0?4RPoAsX6 ztQ9X0$ce0SDQnn1Qn<-vYwdI$%_(BhwfuBS)(jTXbzT>{nkHMoiPET3Nm4+eZsX!g z0p+qN9g+c6rgfU$8hL^vd%F+zcl$g2-Qfq@!<~nNC9CWzZ2+tYod1QY6z71|q(Is> z+{bk-p1oM+D8_@wlr`6T%(MCm+oL(XLU5=bEk?;IGeGSW;lj}eGsUSj5GjIct`+Sb zU@EG(rW>Xgl!xtfXBk$bk7BK?yEbxZ#kf;Dbii$LHP{I_;wNk`uNC*MBAU8c7-py&{I-s#Qghs66R7^1Xu$PGw= zyntoYtM3=hXp9yp<=UCvIj}3EUS2e5?J zgCDm|#ZS~{+%WkO<5`u?M?@fZ<-Cb{Zh<}A_HGLN#4AVq@5+l_RXDr&g=&@9OK0*T z7F*%S|6*SJMwVIVJ+UF-;OHhw`4%%R8j_2iAeN@IEpF{}rm+K~)-3FJ7YIEBeMEns zK`$dTkN`8Nn_ItVXa0X*bRI-!8**$Mee(@wsqMFo1U(1QZaPM$Gc={&7kX{CbfC0) zuA|+1xM|b>Q0TSY(t*_5|vNi+tH=%pN+!I&xk&wdDWW#&+$DMUE1n7q|RUEXnTvX|7p?x zQ|PrlAZEDi{JA%ZKE@3#QTe?iA3XV19;ke~{+|l{p)kCZgI{gc4n+Sg{Im4GKp*LZ z=I1UwHLK!JwJkPlwR2Qr_7aYPMxXH zN70raLpP^y^2l8eEd1EouYL{vr*AR+I|0|O{%MpE;V7O9{foDm!FSORB&dANzm)D& lcRZ5+e}=zdq-%xm1=<()u6qdIHqrlWn@9e{5SX9Qe*t|B#j^ka literal 0 HcmV?d00001 diff --git a/llvm/test/tools/llvm-cov/Inputs/mcdc-macro.proftext b/llvm/test/tools/llvm-cov/Inputs/mcdc-macro.proftext new file mode 100644 index 0000000000000..952f161f56c58 --- /dev/null +++ b/llvm/test/tools/llvm-cov/Inputs/mcdc-macro.proftext @@ -0,0 +1,62 @@ +main +# Func Hash: +24 +# Num Counters: +1 +# Counter Values: +1 + +foo +# Func Hash: +395201011017399473 +# Num Counters: +22 +# Counter Values: +1 +1 +0 +0 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +0 +1 +1 +1 +0 +0 +0 +0 +# Num Bitmap Bytes: +$13 +# Bitmap Byte Values: +0x0 +0x0 +0x0 +0x20 +0x8 +0x0 +0x20 +0x0 +0x0 +0x0 +0x0 +0x0 +0x0 + + +bar +# Func Hash: +24 +# Num Counters: +1 +# Counter Values: +3 + diff --git a/llvm/test/tools/llvm-cov/mcdc-macro.test b/llvm/test/tools/llvm-cov/mcdc-macro.test new file mode 100644 index 0000000000000..d59055ad2c29b --- /dev/null +++ b/llvm/test/tools/llvm-cov/mcdc-macro.test @@ -0,0 +1,92 @@ +// Test visualization of MC/DC constructs for branches in macro expansions. + +// RUN: llvm-profdata merge %S/Inputs/mcdc-macro.proftext -o %t.profdata +// RUN: llvm-cov show --show-expansions --show-branches=count --show-mcdc %S/Inputs/mcdc-macro.o -instr-profile %t.profdata -path-equivalence=/tmp,%S/Inputs %S/Inputs/mcdc-macro.c | FileCheck %s + +// CHECK: | | | Branch (2:11): [Folded - Ignored] +// CHECK: | | | Branch (3:11): [True: 0, False: 0] +// CHECK: | | | Branch (3:23): [True: 0, False: 0] +// CHECK: | Branch (9:7): [True: 0, False: 0] +// CHECK-NEXT: | Branch (9:22): [True: 0, False: 0] +// CHECK-NEXT: ------------------ +// CHECK-NEXT: |---> MC/DC Decision Region (9:7) to (9:23) +// CHECK-NEXT: | +// CHECK-NEXT: | Number of Conditions: 5 +// CHECK-NEXT: | Condition C1 --> (9:7) +// CHECK-NEXT: | Condition C2 --> (2:11) +// CHECK-NEXT: | Condition C3 --> (3:11) +// CHECK-NEXT: | Condition C4 --> (3:23) +// CHECK-NEXT: | Condition C5 --> (9:22) +// CHECK-NEXT: | +// CHECK-NEXT: | Executed MC/DC Test Vectors: +// CHECK-NEXT: | +// CHECK-NEXT: | None. +// CHECK-NEXT: | +// CHECK-NEXT: | C1-Pair: not covered +// CHECK-NEXT: | C2-Pair: constant folded +// CHECK-NEXT: | C3-Pair: not covered +// CHECK-NEXT: | C4-Pair: not covered +// CHECK-NEXT: | C5-Pair: not covered +// CHECK-NEXT: | MC/DC Coverage for Decision: 0.00% +// CHECK-NEXT: | +// CHECK-NEXT: ------------------ + +// CHECK: | | | Branch (2:11): [Folded - Ignored] +// CHECK: | Branch (11:7): [True: 0, False: 0] +// CHECK-NEXT: ------------------ +// CHECK-NEXT: |---> MC/DC Decision Region (11:7) to (11:13) +// CHECK-NEXT: | +// CHECK-NEXT: | Number of Conditions: 2 +// CHECK-NEXT: | Condition C1 --> (11:7) +// CHECK-NEXT: | Condition C2 --> (2:11) +// CHECK-NEXT: | +// CHECK-NEXT: | Executed MC/DC Test Vectors: +// CHECK-NEXT: | +// CHECK-NEXT: | None. +// CHECK-NEXT: | +// CHECK-NEXT: | C1-Pair: not covered +// CHECK-NEXT: | C2-Pair: constant folded +// CHECK-NEXT: | MC/DC Coverage for Decision: 0.00% +// CHECK-NEXT: | +// CHECK-NEXT: ------------------ + +// CHECK: | | | Branch (1:11): [True: 0, False: 0] +// CHECK: | | | Branch (2:11): [Folded - Ignored] +// CHECK: | | | | | Branch (3:11): [True: 0, False: 0] +// CHECK: | | | | | Branch (3:23): [True: 0, False: 0] +// CHECK: | Branch (13:7): [True: 0, False: 0] +// CHECK-NEXT: | Branch (13:13): [True: 0, False: 0] +// CHECK-NEXT: ------------------ +// CHECK-NEXT: |---> MC/DC Decision Region (13:7) to (13:32) +// CHECK-NEXT: | +// CHECK-NEXT: | Number of Conditions: 6 +// CHECK-NEXT: | Condition C1 --> (13:7) +// CHECK-NEXT: | Condition C2 --> (13:13) +// CHECK-NEXT: | Condition C3 --> (1:11) +// CHECK-NEXT: | Condition C4 --> (2:11) +// CHECK-NEXT: | Condition C5 --> (3:11) +// CHECK-NEXT: | Condition C6 --> (3:23) +// CHECK-NEXT: | +// CHECK-NEXT: | Executed MC/DC Test Vectors: +// CHECK-NEXT: | +// CHECK-NEXT: | None. +// CHECK-NEXT: | +// CHECK-NEXT: | C1-Pair: not covered +// CHECK-NEXT: | C2-Pair: not covered +// CHECK-NEXT: | C3-Pair: not covered +// CHECK-NEXT: | C4-Pair: constant folded +// CHECK-NEXT: | C5-Pair: not covered +// CHECK-NEXT: | C6-Pair: not covered +// CHECK-NEXT: | MC/DC Coverage for Decision: 0.00% +// CHECK-NEXT: | +// CHECK-NEXT: ------------------ + +Instructions for regenerating the test: + +# cd %S/Inputs +cp mcdc-macro.c /tmp + +clang -fcoverage-mcdc -fprofile-instr-generate -fcoverage-compilation-dir=. \ + -fcoverage-mapping /tmp/mcdc-macro.c -o /tmp/mcdc-macro.o + +mv /tmp/mcdc-macro.o %S/Inputs