From 884b584513ae36d61c11a76f4bd553cd1a9c29f8 Mon Sep 17 00:00:00 2001 From: Eddy Westbrook Date: Tue, 31 Aug 2021 12:27:50 -0700 Subject: [PATCH 01/98] fixed the IRT description generation to match the recent change that made the translation of bitvector permissions to just be bitvectors --- heapster-saw/examples/rust_data.bc | Bin 203136 -> 205856 bytes heapster-saw/examples/rust_data.rs | 31 ++++++++++++++++++ heapster-saw/examples/rust_data.saw | 13 ++++++++ .../Verifier/SAW/Heapster/IRTTranslation.hs | 3 ++ 4 files changed, 47 insertions(+) diff --git a/heapster-saw/examples/rust_data.bc b/heapster-saw/examples/rust_data.bc index dd9d79894d032060ef9fea7fc9fab8d99325e5c8..eb625d453c4cbad040cd2a0fcde7b5ff9cb6dc99 100644 GIT binary patch literal 205856 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 Zgl>npTzuB=;^9F1c*@4#UHvfq`w!4YE+PN` literal 203136 zcmeFa3tSUd_Behg2}uYc2`^0`-~^Q-qDDaEX(tI-s%Rsk#YbzP$f8Ayh;M5r2@tfj z8=s4{kD%6~RhL$4)!H@zv`Ep7R=a4e3l=T9YN^#0UAy}~ck+OsUG07!|NsB<`{l!9 z=FXjS&-!ET+;9y4z~;?0-v z=8@t%O7U$wcR?Gslww-oR3f@$6?=hZwqI-R9n=cCT|iwR8NOUDahKCH|rZd43R^EXvVRO?vzP5ci6 zNzK?w@;DLmVVN{4GRi!1W!=oR|NmJ%HRHx?`a;B1qSIdd-MsJbN zBAqeNEEtP~%Jri~Kak?f7T$7+=(<((gHp8I!n-aJ-R%B1>C6knc}%$C~xRTCYTseOT{TL_@nW1BG@Fs9@`{_Rx+R`E5$vQWM&# z65qB4UQ~shSI9f{Va=*At;QH^w{YW{Y@*UScIZlkQY>K`a=9bAh+nOekpPvZR80d> ztB#*m)`E~sVM03gAg#Z@7mCkeja2l9(0qCVijlxX_{sDx{`bh6d`r zaxBq+RZbT%&nB4;SRJIE%OFr|n-7P(j#yp8kCw96)(B&zMsbs{BGM?#FXpP*Q)(p9 zS~kI_UW{bH-+9$Lg>G&D2Rd>?fdjx99T8e@3+-$VJ+BX}*N4^X#db^Bbz0Plgx74M zPSW>2B4XDPNo5Tw7GpwFL-GY2;A^BhfzR#jbXkjP8!T&fqdhP-XalA${sv2ZPl}56C_7;16 z$bQ)(i9W~*%cquM8ItVt8ozv!drc#oOLArQ0RkI~g(z-drMiwr95dm&RT3>RO7p35 zG9l35WlAU$^8K=n>N?7AjhPs>Rfynft>5fwy|j_~qY{)rTai)KE*#`NuuaAFro4BR z`9&+(11sS~;@w>47pE|8u3fN{w=9yEYG*Gjeol{E<(gAbr36mg#{iUXo?T1{F8PPF&u~ zPcjoXwhBjK8}FZ9trvFoA8RI1vqT6tm8r5LSw5AjqwrUx`U3u*p^jIte!{MhUm-#p zRbdy~!!Cf`Q(^V(SlNHh9dNoPv`rs+uVw(8f^WE@2))gC2)J}iA9^u2?3ya9xn{t< z2kZb0qAyrWXg%=|u%~UIS8C)PdgrA+V6j!vzE+o!T>*^+40ZC0`q0)I`7wRi>GseI zx%ghkaBu+j+J>p<2bS6dmYUnI6MR^W{JvEzQ3ebJt7y_-^VqLR+z;9fmS9Xiqrr}- zqhW;Em~wWG=(<__IfX%WK{&7r+S@P? z2nu&80dBPNIwhi?XwfB7{6n$$CiEf2?Zr4od?*q9Lix0lqU&1GN}78|$1AmRbz1Ra ziZ`c?w+fEwzIfh(TL40x_#bA`4J5v97yrrtysQ*owJ`ArE-6LVyF@=}#kaJgU+v<) zkRJvXXu-($0SnGuDZWgKZ#ypa0n6Z7gj{Gt%E0jLyDm)oWu@r0S@c7j=qI?>K?NMx zMeWE*_)SXmgIxq+qn#3824dTIwcXa3F;-!)HWrNR5BAt*%A3_hZ=F;Y9BJ4wiQ5nC zJ^MB6C1T9PbK5u^OA&;aHI{iB^w_H`+QyG1(aYQTd0I~SHvSq3`?YPHJWI(274|A` zZ4+*=8ikRevEPCVHKuHEYFo-~O=1&v#?jzK53*Ci`cFM<3Cog2Qex4j^?AFUlc6H-oOD(E8jkJ2s54(~ON3;Mf$_Obm_#*OyPRWp;`i zSG`l@4r*>|0h7kof`TvvY=`3C?4#=kz%S`U`R$?Cz_fD1?xWNJIbZNx@O3=LP`Zfu zzl|6SN4UmPh^`>txI&(9Q)s!)mJD9p!24*MB-(5OPyZA6rw-Mf$Z}y9$p-IrbL9Hq z-xH9AY%nI4X;SOhsTMVkRU3>cV2C#@#N};52nAyb2Y|C3lTZB`N%(XQm|d$6&!>pZ zt9!^l&7?ixQ0nz^@Lb?QIv7U-ylp1J(i8)_!3{b1-xk`&TTXLvPRx* z33E72@IH1GWKa}$07BwI@?9OF0)k~))i^CXDMOZT;mfq@H6%OTu3n>sc1;Y$jlEj$ zQXGBChK7_g>|{GAjy~FX3`vArWmG+>RGlWFqapbWI~BZKo!WVf6OD$H?Zz=1G{JD} zc7xc(H6-KIi%2fhi~;?^Ll8rq$C@Ec#*}U%I4s;~lBA8Z87d>y+!%5-1W~_9Wx~qv zbdnBl3V&B;6Y_x^$=FE$bW7RT!hy3%1kpKk2#3J(vp+S?#!6{I;uwn=g4I$p@!EFb zTCk4VL9tW7dckXeZ|VZ?W)^)1Mr##7b_-T|wM%r976ohbcuB2#(PHX}A)LVgZ-aJR z7G{r|`rlxWlVWxV{ebhXs`to_%2*5=T;vv##*LEkK<=g{ipwGY)ROJv#u9J^KX;wU zxIc6q_qb{#zD;6(a}!YS@&RuRo(WF(!fBh}4tQ=W?+*QNN4w3_jnzQsF41>d!7Wm} zislA4=>~JwXVsAr9Fmr1M8sbHAJYy;dRGa-up#vzsDmxiBL&n%I@0zHhLk4A81>wk zgT$%)h*YU*iP=;FiO^EsQj4i{DQ^ir_HrJ#vE$qw_`JnB(-JApofh*=E0>ypLvTFR zbsUe3%d1VLc2h|P`$?)nliwxz@M%SkcKsF!U7RNfK0|Y3EX39A!syoH6DpsG)jx_A zJ(|$VP#%^c4{OqlX;LS)U>}{jfzb!>-CzM&CCtyPu^HY0m4I+Syer8jX<;L!-h8#k zvEnSLCahJDQ<8kwaX0ck4OxuSP0KslLvPwbp~Kkr&{lnDbFREo5qi-Us)nSdJ@i;j zV228Pt8bjyHm))$ zT>&I4ki6U_1-PY71VOv!DgcC@TG4k73s+)$*^fJ8m=OGb){5{H7W_gRuMp;dQ`Oob zUOrpZNLH!e9$3R$@&^x{rq~m>+G`pCMTG}Hd~F%9xoO-~essA`H5CGZ|9DxBIY=g%w#H)I zZJxHqYS=BAUg1a5XR^5cb`KufxGDSt-LMDY;g*g~F)eL^G33EOJ(^1%f&u25iBo`^ zmJKd=@eqUX47GF!n}A_Xk5}YS2*PQ1mVhN;^!P3oxFMLYOt&-!WhiIsR9X2{*$`Gx zK2wWljJp1Ua}TCa5A?aD1T#hxK<_Xs0LRwq!FeX{Fw4;VkAIc*OK{>TUQ_p zbx0Sqp-bRAw(<(y9Uk9Nx^I!-G!G&JsLMm^9+1I;y7*32Zy3V%iP8u^%=F_^!upoX zoSx{2C*utxoaF{vwB4A3C%z4d9c+h*7l4Uxm%I=gTTLw3!5<}IFWbS%ChZXLFs&JJ zv6FiAxEDU}0b-;GF7e6Jfn|bs6*Npsjli_b$%3d2W4STaM9q%C=ty5IhO7xJdpNIf zWI%9VPpeOX8Udrs2^Ta`cI<_sVS@6eCb5eM#+3q?;4}06?J%(@#J*ozA4`_AB86GI(L6;<-) z+?+G_(+2cA>${`O$r|Bg?Uf)9ouNW$BfF zjLjHRS{ZKtgD`u*z$O}{9~2kypGI8e``z~oqoHf-$oVJWF|hXl|&c6E-au% zMrnNcB=?O;eg(z+U6W+|V!q7&nqa{@nkGuPVOvZciZ@w8H>!ki)16vr9#pMBAS3O6 zER=zpHeb@Hqc}by1$(4qt-xl`Kp8uKySmOA58V|z1EageL?if`EI&lD^Ri@xYlDz^ z{Tk}k-I5KUkh>-H_Utm5-B6od7Hl`{&gQ^zU3P`6MaSJfcwi^Ro87ifR7yP;WfYcL z*!Qwz@HbRjJ%7$0E6L||HGJ>TWV@pne4Rd)E$C-{nwMlJHXi54*j0*?+u5O=v^|>> zYF>Q?{=T`owY2$r?J1w=Kt)ZyBb&DvLpyc6jvaY*Z4;90dKjxXD%}^4(n)u~Jx5k| z!rwFW_0ncjb|Z7=?A~`KwG!<+<J zPXTwo9o#9-X|e0a$1po!JgOtd3z1lWmsGooJE(T^-f6X_#cf8%U+h1?c`)t-dlAP0 zb`N#_;n|R!MuK|~PT}?o+{G>Hdv7&6(S3{iz;SO@wy0CLqoCilnovAlq+Hcxm@z`3 zUAZP0Kt?xDx?LMnr<*j&lJQ*qM8D+p4ayolcdCV$uuBqc34}PmF^cUIIfZ>V8w}NJ z+@u}gcE_FC0dvW5lir&@a_y_q)*)NVyhG#aSdM8rJqF;;B(ei{g*Tz>xLx6hM%lYI z`%ldCveSXwrwGYgQF2k$_N=c4% zZ9eruRJ|}iecu~HqP&&>3(f3=Hns=gE_NKug-2Va2N6>aY@IO}{Qa67Md%fM*d-+D zrh`uBg3*bw0b0R=AQx8c&3HDQI=i>>+1T{mW)Z9dlpx+ptKcfsfLvoUlO*!lj`zbY z*Pi9c;rAs!rdlPd8VvF311Jx}WOVR`-C0l`MrNC^a2ia=2|fgD z?Y_e45XVGsr`yM|Wi4skJ8hz0%pxcq;iSVXx}+7~EEZpF6LsLc#^)o~)z7tpZl&ll zBsFGSg6hO87m{JY8Lx6!<<(eM!=*L z3PKy$W9)3f80t(^1=eg?%KOvv_k_1td1ZUlj=9I2_l41&oN<*i(qZ1+G~=j_2+P;8 z<(4w*6i#SudE=By9BaprB|$aZSaM;|R&FfL)1Dh_;p}{0xZiSASoz!>L~pjbOBh!9 zd1lViSQB&Kvfh9)mk%nu@l^rjw^O%KH^9-C88g-;>$D& zmj>+?#zt0)J9TBsB=&3iF{-!7OtWvNf4=v5&YZj*vF^EOF_i2fdoaG-YAP+{E!CM; zb>d`V`BKxYVpB=C*McVAa>zL#v5=Inw3te&d4VZqkz?i6LwXj8E<%BbnZrStc;0o~ zQ~aSI%JhSv&`kJ>*Al*+d4W}%cet~gr4}BBZZ0pOdCS_2%dIfwwT;VoAFjMLC<`!*JSFUlRI4YcdR&=xp3^3bkB4Q z6xuBQLCdTiSOv~wNBNBL4u6LtT4x!zN6xKN@)N5*u&GfT0_a$q%FroTotoIQ?c2!D3Wmmv{xygx5Q#vQpn5V^Oo~@ zW0Vf3fPO5Bc+xG9-;k}dZU&f3jzVQg3!PSes7%( zTytB{*Wi~G$Ty?#(G_=h>B-7Y#j7~_WLR6jZ-8=paveS$3a1CvP=-o&>|%hTT;DnV zzpbW1Mu6*b?BK90cCh4B0n0rLHZGwZ^HUtGo^>6Mp?;4w*P51P@LrBI#W9vTZK-K- zBo7j?C*sI$C(ih|P3qw#Zu+rpj#*Ls$t=3370vk%G^9)Lce=s^mRh!d^U7S;D$8$J zs@<(2k1|laOT%H-3g3q;Q0oFcR+SZj4s&;#H9i16*-7|j%!z%@%_~^Kb)r5rMh66s9_at0m>N#;K+qrS% zt`lhjw*()q?OL%zf&b&eHR!{i>qLc1E1|eHb<5QtH~$|lDYvRTh8nv;{d-Y5GZ#0rF?w_UqioGRE~sb+)=#`_vC0OKFtpXBt}_|W47qQYRoq+a z>Y)#;Za_Ek;g&VPex6tO;`ULoE3IAw$UkpxXHWkJ($9++^9a>o$7Miyk6p?)Eu(k~ zK-veHbth^05=d?$O$!_=QG73E#i?(aqM1vv{lCfF`lxVM$mAS7oP++4y@COXz%aPN z1j|-w2R6@tY&Q4s%o5aG6AC`ymMRc)F*g)g+jA9k2e|9GA*K*_#tBWcD(w2hOgzd? zx5Nhwe}sv<*PVK;rR-NH?#J6`##FNK?!Dc(g3?o92Y?X$Jolab#;Tgz4YVs@(^<{D zi02+5>)#XW{$oGk$b&#JvcAduY2^P>+d1g#SA!F$)x*aiYK2`IUn;)FL8jGtl$pBj zF1r{%`B8qI2;Pp@8U9n5+J^3C2PfDKV(o>3lJcH8hS^kn&@>CYGG6%YGv9ViMIhmg zG|kFjOt{tbvJ_Y1q4p0e05C0ws#FRjw!I|V13bZN@lxIbxYWfS4clt%7Yg$JUl^LB z{k9<3MGM3nPm-s>OrIfeVH4(nwh)J=J77on+1Yk35|DQUY@t3#~>cL zrVbe))&%wvSa-!ps9-~igc!^?K!J1_@?&11|42#>JZ%QD>SXsc*+?VHT^ zdR@Z%(7Jq}a)B3^`)nI4#(UwMyVR7PThX-QrJlyugMTqzoW2A@wBa4-e9Px2ZkIzI z@7NE+EXCb7z}g_*p9~vhVL1&JOj$#MogEbx&g|3;Jh(agzsaq;gKUp~ z|926yIQH(NHb3;8fb?EuWDhGdCcy6A2UiCFOEVX3d%->T%!Lis`>^%9-{Z~QGne0^ zzYnQNB+0-1L$68nZ&+2|WCEKpHl|6nrUf~s5~z<;%z7dqgA3(GFch3&R+le<-M=u2 zZiL_=KWggKL~Xh1p5s4!ECx;&E}S^0V<~CeILj9&ZvW;M&OUZ_1*}SoD|mO5qQ7fJ zx0xc|gEm*#d+(%~3+A=vLgtD`g*Qju)3=1B6nJDmz0=4xo-^-lqkP6t>$i=T>QNr~ zr>A_dA{pf$al*sQ8a(msUNu?9k@rEXM*~&z>CE!*>&M)IRHl%=FEX zNI}iv|F7GhsW%1=Kef5wje?r6^Nz(8*WPM8wWNcZZBXH7D%4F2V>jBO&uE~C(USzg z_RA(%wP?Vr7K}T@$KWOKwgmkEXslBwR>KUeT>-N)(Q3EMd7~Uw z0vsz}Frk2H1-5B(d1(T#)WVA^w!pOH?1{jhD#&k59APgtAPc60lQ%~(qlxA=9^TyO zp5*;jJ;1Tw9rlY^aV60)fs+^7cukASc5ObG#jI5%((Exh4~iYLTjxq!cX>h+J1(Uo zJI>O2V*f@cO=*&w2zeJVbbA9l8Zy8ku5KpxhCS~4jdH7Pgp~*mD~SrWUoSX64(4+; zp&bt{!!hLtD7>9liQ3xwUqZg(#30|=#j*3=h27_NQOSeraX`LS0G0b2B(J#3rv!>R zZ?55%ezN(%V-k`Gu5@BLyZPJ98AF_?5(DbgNuY_2r(U`lz1!fT@jfdQwC}yG#Etno z_5?anrNxegMVOL;4#GxU%vcwVt7=4`dXrDl%SV4T)rG2+=U8D}$v7L>CJw6Nrtxzf zuW)J8&O++*Epvwc=ISQ6a~F-qSqGisXnSmNv^mAm_1NOL`!0`qiemwC z67t2C)sIO?r7^)Fk#QF@XFi@p)bb`LEw>6Tx!K-#g}0At>6}7&V|2i?k0%rfuhgMk zw~su&nbbPv(s`osG0mh=?^Lh}FGcKqJOxvTZaPJ?{P9IYJ4N%?EpuLAEWPp}E9j7q zOwEABdQ$>zoYln6#wOnyU~l%xR^qLfcD%-HSOBaa=4{;LuCj@=KZ3K-JsW4aePaIyj3WcAAL5!F z&Kk(IjkrKWVb^?p4R`-%k1eDWw~)?{4)}r*68PZX77{pb5YjRSO`mTiK7DD&>kLic z>wlXj2ol;FIXocY@S&Gn`tZo1;PF zK0wgBZ*c0vp9`s9T>9{^-6$?w;w6GDRXg;d8*J$nmp(i^x;bo#iEgEC-raEN!=rcy z!H3a@HqeKEy7b}Uq1vGjOsH;k=)?Ur+}oc!^#QQ{ZKDNpyUUXu`Y`Jh%}Q_@?IVRm z_Xr97!D+OQ6w)n+(Sneo+A`&g(LPd0YLFtM<3LlXb#nsah#pN7JV?v;i|~ zK2lB#$R4s-f4Jl@&PS33&po+C#XZ^RFx^Lrs*wnFxFb+M@tdn1uKbbeS7}UgODjC# z@vV2UTLUK)M?9YOuENpDZB@TRU~N4DQ=v&xgtr8t5Ury7U+^LL?0Pv&q|VpK&!e!5 ziqH%2%#G0sUkW99iK(Q}2$8E;YFdO=wfFC+34^U)s|dUd)d-JG!1HUl@~;UJ z9^LF{mpALf&gAGh+se(8(6Ox+K_ebl3_Bo*ToKfXZfHgG zkoX7K+d|>z2`D^?K^*+JLnS=+2~S9C5~>=K(C1yScTEg?$v#K;X@g5peT9buVH%Aj zw|SazFj)D9?{Yw-8z&(N8uK; zZ)G@#@ZU~E7UgV$Mz2mooHbrqg$7YU4B8d%`q7*OwnbpjvA^R}tZWs{nL`)p-gZG~ z(>1WXC{{Gpe>)*B$_Xbj=vcIiq~fFfi9uEwnj#@X%tQFBK^g3Pw%XfqJGG0!$KqQ# zm>GRPamYYYhB(UT%a34Mf{SuKbm9Yzt0Rzi9gNEj*)$CKw+R7xgRf72XhhGMxwUn~ zRmbh+zLiffw?`G}%74I|=D`jtQpjHjbrC3d6tb5tHI>3c&#>l(aMg+++Z=nuYkXaz z>@J^WHo;TT%e%dt3INA^sHX5}Py@4RVI*&Pp>Y9iT8mB%up@n){BPJa$_fZ?PzmtD_OVRq5BitSdF4i_*zsgRu9z<&ZaUqMZ%m{yW4s<3+4ELY>()*cGa zhj+qmL;~0Rc{FU0gCc*VDc+?#ZT(l_orz(cuu)0BBOVDIUbrzrI)EY?sX|k27u1A%Cb|BZOX;i$j)~#v5MY^mS7x(hn z+XMvG77DXEJ2%LI|DgW`qo`9mjY1i+ZYm%TTB?hW-it+y&Gt-1M-U>3lO*5lD~#qi zeGB4-m~)T;d7nn#&`tG>>e3u76eOPtqEH}JAOLxxN2_!o_r=?DDuH0dR39VF@laT%Go#jM= zk>tlKKcigMdO&}-oaMH9eu5CI9})d}`@nt99$ zJYqS6(RtYa&uA1qtJ`ZC)S)e=SuQwClvqshQr^;9p0my)qJ7H}5cQ!7 z7XKM0lm81NauWGyKv6=o9)S)Re9IF#DoIh~NfqCq)96KDupw(oB?feks%^kHiRpbc zIVO_NN9bvY<4TC*0Tq-qLYS7DDXDycsMesHdV&l+o3s zMMj0Urb`&WXFa{an?t0Z=IE&iVPo0^X=U>pN=g5C6}i`&HFAQ~(70K`3E+fpAtmQI z`p5`=*+><6z?)^8AgP>RFBx>PtPL)m<>-;oTaCETQwVUvxdGg*e4{seB)5U1fCH8a zw+Ih-Ybb7kGM8*>!`%$r0Dj)n>`~Q}L|4b11MQne0iIuS^g6iZ6hOO#yKRMTqnEN1 zDvjQTkRvvZ4V;ysjavf!FCtL{zcD0JYN!VwP4dV9j=EaOQOBytD>{ROA5fv26CqTM z%9OB@p#9ZRxqPz{A4oHmhNHXK$p-;#?Sx2vjI@gsM+iBxR$G~#H0IVz^3Rtk5UdO+ zIbQ~6N-N7ZD<#hX*q;Gx3-pOJ78s~58%IyWU1xX!T$b=QT$&lcRqLST32s1{?hPep zRTnRy0tK$~*0k~d3INOJ7^t#(j-n05Ee5pHgb@-VX0@$M!Ds)$AQ=P_gwE=^Oo`#i zYHd}$VQqaV9A^O!S_= zCxZ(kllVKL8pl(OvdzP`P(4nf&}* zwbCbmJH7R!u3qbNpx7s%a(bQD%!B3LX~Q~L!!N*%RB0}B{$ot8rTjTv1m_6GYQko% zz5Z*T&$^&LI%myQOGE)>QzRyDTLN%kWHs5uO3Wk;qqQwMgI}fk?1qLBnNrsFHz;_C z6c?E67s1I@Dq15r^<_HHihLb6fc1h}o5_FOo4qbFfSWJc;9XyzDcJ<1y=5!2$|Lw! zibVmO(hQTg`ckGu@?15Ud4^+?pUwr9;P3U;CuQ8NEeP8c-I~8o_@q zR*?}Q%(#@vx9ZfzAn0^q1Rs=yzsXxIiwodJu8ZIwSE`m)c-IeC2C!nPNwZCs$sd<% z&+Q)>1FWa^bFlAT;l@=ugmd?PqTN)=VFQ-6@NNXJ{E zRDj4hGT~A)4~FxN;Gb2ha&~*yON9YtU~zm_tfJNEO$^ACn4hdB^J|r=rv2V5nJ|D8 zV+B@F6ZqM=1_}2hr(HZT*HHX!Jx2v<#==_KxJ3e5l&dm&*I&*g8O>2E!Ss}Nqqkn3 zDY@VF21%=9R2hvrgLYZ~M_V1i2X&HKb-t%{YBWK*DNYO4nlA|8)QTfGHOgEn0)#d5 zJ*BG42*}KAEo=8}BSjIMV!+u{TCF^y2YCr5)xJ^EUGB}wnjr0W6iBFq2Vw(aR$AG~ z-CnRT7tiM{rSUePc-UbJ89+5}B^0rWjmgFAgjOy0vYmUw!u!F_y$VYV79JGt=jlXC z5xilGS3>jVwTWPF{sJ9rp69`uAHJ&ef%)T7%WYbsNX&1_SnEd(EIU3V;?IA%I;*5Q zZ1IWuk^6F@$9{b5`@=p5G%QK(!FL8BL;_BHiOy6;9w2}HrUgtUshqs+M#TsVOb zNztKM<+n@4gi!KW zTkj!uibZo$b`YppZr8R!Jye%PG>y97n{|eO zMrnR;OxnF~3D}XnFd3v(<>yM??F}R+)rU`MRS^77k?QDeLhjO&Bggf(Z2DZRWAScq%MpR@US|YdtC(w+w z3q#OEDTNbr`#U;8U--bdi(c0cZ3SrXmOqMVLjdqvjJbRzqHWNC5u(8a6lYg+ch`xL zQVtCO6~F?9Z=9w2-6IeeP$Z!ZP=KLlhuG_%L{=Kkp&h`IR&&%V#w0#yHjs$h;RCcB zT43i5B#^Z?lDig(?pX#QlmK1aNS1%C8ejofzzhoC3zvjDo0B_@8xd-QGmIo$q7@sf zc`swNa3RUC@!lPa?^qV1fl89;h>?tj7q*N+s2CbBl5ojtUUQQj*9v2JAo=4eiu(`b ziDZ-{ut^7RkMTeJk;19ra7dh5WhVZ#lY4&D>bWWHI;Zv>(it$Ssl}?xp;k#z(`!})> z_G=`xBStzOM0XoA0_lUKz&0A%09CAMA6vNvARS;^j|%nc-;Chh z2e_A8Iziv7WfssM=tV(0e1Pzx=OWo3!MM=NEuFKU`OLNgk{Qqi6V4#XTG1}N0MY@r zkxUzw&U+&)#7qDOy)cs7*jU+?zfvRa0CHS%WXLH>XwuI_)?(=8Ca1Z-X-qAUKJVP-8>0ELou|*u+#van-g@i6;W8`RE6j}Zq1)yx6Nd6i&F?T>8B!jLQ zqwWKepd1w71GEFrr>@d^o$8C^4e>5AxDS%|RBG{bKvLl3Im5|A8AnvZkyYp9IfWHN zFnIOoNM8iAK}O_wAZgaOgMZ|{2de52IkaI;{xs+!El0XKIK_&=aB|AF#*poxd?0cP z+LTF5&#b{0+eRVe>Ive|WsLfBV~82#>gCmoVQme<@EJJ8%O2xJ^(#;DF#Mz*S8V3u%0^=gFZ!I!cQfv zLU5j(Dbnn9(!3LxJzDP>b`}eek^d%ynBvAKh3Z zdNroAuOqsgH;KEiXLJYKUx{wE^mRm|Hl@qzKsey)G27t-%+&5vvJb!^FxhR78&~uz z(1y6(3tR;&+j^>AIJYm7%cob{=Jk-{VCKwMC*$xG(_1&*nsMQ*Z*K$UnH0Rm?xjwSK_yx->-hD50ck@ zc=g$XpujFyz$ow`3*qx=Urx@7%gY_)mN=jaYI$eV*y#J9z%DCeI7yw+mUjUMJUF>4 zc$Xc<$cOttkKltjIqf^~`5u>!FI8mkdy!Tr!`*PkfnSD`b1Qr&VNS;N=H%HA6@u^J zZW!Lp$z5CGGip-$aPp&Xjt##JyAuJVh0I2m*zLNF&G@U+ zKS!3|1)4oL`H!%bTF_`PqaIFXefOR3O*X24;YobA!(XkW8&&~{z;8Dvqy8*T>;!2g z_2%TBU-Z0xf#(MXF-T(1ziZ@^1>tD`3dW}4pVMp?zhZAJf>U589^Dymv;F+a{Ru=0 zp%qia=*H1?O#?Q7Ddpi)_;q-Lxue!5CHVDmnEJ>p-V>m$y&dMRr1bl`c%+j$5pcxZ z6GQz4FZT^nhto3@>3w^)kNEI`p1UTE?Q8?0T;YttbJ1V;p>G179_sOR@J?e8LFc+C zBC)o6U91e<%}2r)oD?C@&N_O9dP0SmzsN`b>Pv^ls`Q?Qkn%tEmC(o6K? z(gG4I`|9VZIe8EG_NYY@rq?_L@Li(=5D04XSUyj}i)z6iF{6W~L0(iAFpVF8&>3hX z;TJw&!iV16P+tuJtheGdzZWn$5_-lv@nm4GU1AWV0-n81I4b^`pA{1j%JCTet(RGX z`Jh^0oy_Qtc#-rkPGAQI(EyZj+GBZGOp7W6kq04&VLk0pyle6xtrZZs0IekaIugjU z)1tOppFrpc;7UQOBLwfdlYQGV!Yxy0blbRdD-U$f3SE1FeKsf+1vwl^57;Ruqn6tt zynr<$=gPmY`c$nd8=*=k6P(tUy2oPJ3Ft%L zUSOMNsJy1YOdZ@Swmv7eA07ITw;Oot;uzcp@%`J4sgP57di&Qty~W!LJu$LauN=Jf zf5j^>AMgTC(Tlf(D|{kbAuB3|)*dE|llRxwJ-~#GIm0dFP=xFryp8&C<~<7D6kh9+ zFOz)!+IgCH1auo_eGCp1#&*rK{h#a#LelHdNWw2r2ileN$$kA^WYs#E0BArcY5w-I zxYP?(xUi)WQ*9jGRJUdcKP8KVcPr++OEw0j{g z1UZJW45}N&PzM?g??-c?3J`=lOV{qisH(tW13(NJ$J}+9p$7rg<OwMYnECr#tdOWPQ!A`0a0$e;8{P*8y`n+)m^LOA9L@H*0mFnrOHa=;vK$=8f5taD zx&q9&zg#fP>;rS|ubXGkz|U@1Pe$}xTg{p=z)xtzFeyBGbM%%}Gnm>vS5F|JBD?)u zH}NU7xH!*Hbnn#I!0W&d;8PFnQx3*2q`}tj1K|{0fDdq~@W2P`Wdv$-aUNK$%Xs(j ziBLNbYJols=Yd|$F3J3x^z#UHx|9TPlV-Iq2;kiVB>|vr8SN^a-$~8tGfz4D)r4TM zNYBYs<|otGtB5|6sg(@w2ruZ7WFw3C?j^gq5XHw%%l818pd6t%B(oGst& zC-Eg+#z$|zKEwhsZmX*&!=;2p6IHXp>jJVgTyQ$H?rR&^U-l9Gt|f1kJdh!*{&2Er zIJ-|oySDqS$uz{c4B#>eK;Z-A-@LKi(1MT_ycB{9@Bw8$yzr@@A_y~+@hQ`Y=ci4{ zyLFJAJH51{=iHaS4|+iDQ@Xo}li>B7X^*4l>7(C^mvRy933K9@PupS^ty0g0<*0b&B2YXKOd9nrvPN#V~qsh#>eqJyw!@&o!n2~__USEkvRQnMQg!NTMXa=~K z1ZPiRAe7gd$Ns%n+{c%c+jsq~Fcf?N?O~*C@|~K$!F3OoX5E0*CV+{#=Vocpn@@dD zLtKMG708JBfJV(9Q^Gq7XuF~qV|r5z>ynQ^%SX_QVH9I}%QjpfiuxF7(A(>hA4qzi zpHgDNvC;$P*^k#Hw?Ip=2h35MF4jP-TQu?uUjRqTbnmpD2T&0R^hH zL`~h32w#)a$Mp?-adSN^gOS)KfLf>T&H8J&DUgM9E(91<&mQZSxEn_9fUZ3VR3Er# zDMu*MiGVZkS?0Y}?*m_@10dZ9Tx%SbQwa!wL#7#|Fsk1kewP;us3t;-yJysuJ*jvS zfEP7LM^{jl-7o#9@&%ZlsA{{e8ADj8%>&gbYn~l&0dTwmH@i`dT6^SPTLm}@4_^Ix zc@ZxWMg|YmgFy3`KPR^;kQA~z8jsHel#i~?7C_k(GVWeI=RQB8q!Wn3lK>KTWmM(k z6*cu@0-2qtLL>Oed+k0!^`Ik*@G1N{XLBe2lvo7?gTF(I8`WK3f0k8K1&M;91mXYi8>%y0K!U!u2@)()a%1((V@ox0T*2`B3SFc@^)*V z0)_HGV5;mpBRCck_}YWOqSHA8E&u{oJrFp3>>l|?gv_2CP`rM}7DgZ?*Z~5L!v`39 zYvFbAJwTuopE8X&`T6{XSGoWJyjVs-qqF$@*%$vLfv#Flu>bhu9YZ9jmIv7Sqr$*d zeZdAzEU-}Hz+rmORUG@1*QP%C&&Ib3YIM-kQv^3h1$bqHO@nvo;lRd^Ws$Z1J*6b9 zb(&rGPuQv9ebVWmW3u2n|32w-R^oT;XIZqu1(U??V#;aR04wyo2LmyBMPQirllRaj zq-%1L?@;W!ORn%f|GzRh7+D^J>#Aq_2631p*>%7lR2mXgw#X(w`b2#e**vSq8(6@W^JtF z@(y#56=EPmJ18fV^j{y9XdevoI2Y}VQGdVNrW(=Lr|tMCxf^*n3=+NFck5pNu}wT{28;hXT(kz{#!88_&JC$TAV`_fWjWv%X_5W+B=o zdY~5yM8+9%YXCz3VweekusTI$U+ALVMySn$e0|4Q-ffV126V!rXUJbO{NvQRC;FoL z!=a=4F$9u;o-$%$P-T7PE4~e=u7yT7szH0_&$m8<&<4dkwO$^29eRF&<6vIenv#V8%pIv!Jh+zFtyno(eO5 zPH$AlR?jeg#6l$Kbq`UOkG&bWAJRMzRHK$&`MGTm;O?PRdq(}jT?lh=aDF{XHSXg> zi3b5ySheZJ|6wN&5wpN?dhq}J!jryu+Oi4m@8SR9g$K#$kp6g}s($BvuhYO)4^(Fx zza8GnmU#02(g)v6^x@Os0GuE2Q9&1JUI4@z;H`pl3BSxkukPXYrZ2 z1VMWCJTd&mVI(SW2p&TKjr!@_oIPF~1QlNA2m6!sPmUj;`F5hG>i*%5>ScmZf@4N*e(q}cL39f^ zk9~lf^Fhh0R@Tj;(1u>_E~7{infVS6nZ2+$p9BCgVbzf`zf5zLcf?c2I2sn^8))NG zGP6*S$FXqMScHOiqsNt(Dp^`lIz?n;FJ1fomTe&`WS{75hei%H>J{t#e7;l~4->~M^b_nh0bPp^=c~-6amWpv%svu<#xOG0?xUbbBZ-s-& z%#?FK@N5v?(T6`IaL^3@&32~=T4Ab0K_jJpn&|*@FZd6!0(plzf#9`+LC`QL&IzP# z0~8D~APHm-_``%D5EzmnulxM8_Rm<8n*Krs-b|L1Bfm72l`~1IRjH|x+|tt7^NLH! z(wE5G{CslBoYF$_rNy&L3W{D@vYozAf8|PZN9XB_7pRu{)2+=-rPP(q<~B;boYEB% z(##CsrvH*4=lF!IU$JGyoD~DHBzZcmLPb8?p1ybf>+`SAzRu--e{8pqTah_7I{JwS zQ%iJ(@QH!~VFfp0cSY5e9aRNmg~xVZzcPE`{OjezCKO$tu=o1ls@HDJgR|%#_Pl;F zeg5m=w5>c&Uu3L1bSNhA@cz-GCHv~)4#dQSN|b>IVq%lbZ-+?^?T?K+9H{h?NN@{W z*^0QbbzbX;7bc;##tGj+Ew2glZ|<2mf44CI^7G* z+PUzP^*%<;(*%3jLbmrpHZgSFdN%t5pBLUAIxt8_4fGjbJee2koytFkmLN#<)=<<{K$4nZ~s(pe)rtFYd7jEFY7xu9{<$O zza;Saj%!ysk3D~EzOHzFOS4Ybl;2oil2_8ylGjw6S8z;MsH>mbR5-u6u%J=b(men9 zD;>w4Z#~^u-`aZd*z?z$kIn4366r1N%ov{$m$7i$(De&_USJPdzkbE~uZSV|99Xb( z;rgLIAsU~67lyKBD+Uf77@@NcOjP`7N8FK^4~HZjIy^FIIg2|cD=?;d;1C@ew1`+e z;>_efdfihC=8PP&{kTM`l=`#7y?rw(Yu;WyRQoy1!O;g&_)cT^AIqoZjqUP+Kq9qL zlTg-BrDmR8Sy;V5cm;{!I~Z@%qFA9i48AQBo|P(4dNJLMAj{ zYd<>$zCsJWg`uS@5FX-MQOFyO9~$J1rtyP+_@U59-r{a}eVb_sZJGto1mZWts@TNs2JFf{I1A}+PFn=%P%9|B(cpF1=F86CQd`pfd5gv_$zXuxB%RIs^wBfe{T_eH@q?6!HSxIjilUuZdoP@x)n89nEswZXMHj6O_!sf#J zq@CaAg&$`HgcYG(x!mk>V?s*6YcjtYQM_$o9Lyz?2JpDd}? z&-{*g=NY`y=_lnt+iCo2*8cF$M|jm|L52)oG7N8Q34wQyRl!$ZHKZK0CBj3kXV@t% z8T;|e?{vHc_@PRZ?3-hv>pJm`HZDAn;{H;t`4Z80@FfNC++Z6Qe}#co)QwGk8R>A{ zC1Dw)rcx;LE{Vw?2kNWVu054zkwoUFjEqsgZdPoQN_-iguYFoWX3kzby9n+b$X~8} z68=!|hrU}yqVHo3$nqDyL0*Ud?8blg|Ao&oj{z-HwxAYLa#U!T)I!RegsgQfq;yRc zCn9oSeEcWze>yPw!=wW-{bLW*?K?Dy<%M>F4nsUj87XLu#i3~b>$VUPEeVk*J`UM#D3#|CDBgYq4Nu`KyP!(->O;Q!Xu@=H}LjL4H zZY2g?_VhWveqD?Ipn=?D)8M?y`&{JlXnjcra*usj3uA9>ry_u^O%v*br*Dt<373qS zcY)LJ(%;^rII0PMWBG9w&HDzI6^@B(5{sssCkO@_mS@jamuL_|G7w6!UOCtCVbu5R5O4SFL{u}lrhNs#( zV4Eu0JW)BGERu*In}Ey$?Z_nW|Li4HY2Sg74h#;EW*e!%1q>!kzVQ%v$OB%ZC%jFW zk`xb^KNEqcIcYfYWj?ti&QmacYDQ0RPMOVY6T;8Q6+R_={Qy!a6Kej+ugr~8pt10r z)+VxgUL;3%Kp`>s*6X1^PFKGMyt^^p-^8f2(_#pP-}u~Sj=rP^a|bW*zyTbVcOJ;P zVg|^z@~F30eYC1hm4GL@=zt5(7J!q(z;RPgjC9PIXK;1XpeysqB>^5BdBXG({CB~8 z7VtcV@wC2rkn>-}Q^??1U#TbhgC6{h0@TX!lEMTD&K3JBIjVWhoU*j&qaFgvC7B(P zKwo{O%@5yqS2EBDw!#UnY# zc!P}fHL@xs2`dU9smKpfDQI(;Yw`5h+`w(#gz^oN<7lyrALS?ACsa$WEAxt*u-48! zTc!_`V+63@+L5VE_)3+=oj~0`^vsMn;>Yh-y^O8KVRmm)KO*07Ii;9D#W_;2T+*>l z2r~1E0sdkqQ729byzk^M_G@mPo#CkiaEY<0f$-l&57t@mZI<8`$OHV~38wec1OvHV z0F~^2SuG5as429MLwLuKrSKJO4!<+2^BL0Zcli5!D^W{4M~$`6K@-;Jk5dDrC&U^5 zVqCxzN{)V>om2nk-U#J4b5uQcju+~B+fkemD(~>=FEUg~$%Wt->!y#GB+)yh?y#F3 znaXTy3Fg*;Of6q@Hgi*^Qh3_odKiO;`*TUhBH(YsE(O^3>BCil9k*E;RiDaHp}52JUU_Zxrr{k|UK8-=d%v5h+iR!`Xyqt~A6?Xes>?|HB0ciju2 z0(AN*cTD5Z{$wc3)MNeVu)3^Bt%9vC7d90eC1zW+QNk%}q9x(%mpaq`gN>Ksl^7N_s}+ZFI12U7$1 zudKqh-LH54@C(itn8X3+3tOP~PdL9wLOt=VQU~ZWpIp-A|FQoX1mCI^xTksEVgMNM+8|oOg^b z3w9w1e2r;K3}n7Vl#cWRsW$*F`ZQ!7#EvPVvIzom)s!MCU*U(+j?;kQR2*UWa{yEe zDv(tVviKr}QD%+SY~yS{P8R{3rB7fupjbb?l?IA6sDWFy#Gg=(x3q)^75$Ji;HK&t z;58)~0MSOFR2^GZRwi?t?Bk^2*n}7IrcPAeUo`I&r(xDN+zHD2cU~5xNzU9JCQ)hs z`UPaZ^JcOAICtiq<)~+G8Ku{r{l1v*L&Tj~$fRQVUvcXHI16&iJFaxrQyrN+7N@T` zkNx!N0RHD9MlZ3h&8V0&?SSy?hefhz!?~E1oPDz;?5*cwti-7z*%i7FdN}O%|7<dV>EyMh^vaJy<`W!**vy!aRQo?%*@|8xf>@<=c3A7 z_EtViw~4MEoKqkZy&(O6*n1basLHK>e9z2g7<9nRMI8ingJ4*g!$kxoodHBtKr}N= zix~ve0wwd(<)||ZH_Z~w2vd(}X4U7TAd;9(0`ILLJXZG#6tjl+;^?ky$r{%m=7dlZM6VB-%;6{;Z{jkJ*mOSK)<6dJ{ z$+(OrQ&K)x9<0lDTRladRc6@8GoebVmnC_Uj=ePiVy|I0#NNXlJ;uzV{DCFESJd5y zcXjCBqGu&xhGRw%(Ex1!qwO&IH`^h#^LE(yKdT)`$9wa7rvDY#htCyanIQVX)Q0Yl z-st+*gf70ZG^P!rX_{E|cdvLYfH+J;wd~qhwLC_|e61FAU)8p(R-6b6(_Aok_>`FE zC973KwLWzw>=X{&3RUYV@b&omQmdr;)_cdl?~!_@R@fOo3`b-mxkcWV7LOD7VHyu# zM2-9R#~j`>z+3DVrz$w#P?ci zX6mzfLI~YFn#ZhXO5IHYJLtX1Ze3)P4306QG`AZw^i1TlGrPOu{qG1z!=o}8VzYa# zS%-Mp0*8c=##;OH3je+HwvPPw&Z~6!-RE`QZeLWmzMjwpy{tusK!zx}ax5GQ94fi< zb~Coaat5+?8|kpy$*(sZwb_0P>;}S~`>@SncOZ!xse{!+N zdzXGvG@Z-#lLwSXsN_R4by4NPstfK#LRZuA0#1`6(Gv#{Q6*=AQEyoK7H)23(*>O=#Y}j_d4@-PSRhm=RuyW>M=1|AI_AiRY20OVnbF>KaPLFBh7;>&^VQ1a(rr0(ab8f<~VlQ z$0%~#zxu9$4$S?3-@D><9sSxS*Jf-cpUro<5%yq(Xj;5U-%@C7GO4=A>x}BLW=+zF z<7v0^^=3_7iP=c-??7XGJfLw&?vhv|InKsYUrFFnd(-i$%IWaI>fnQUR-fc^gfjvV~S^> zPn3}J8Wziw>>gV?Pz>^hyIP;u7tzh1y89o9Xo9 zv?=8^J7WrnH3UkyFLXSx$ytJ-0qkmiLcE@fWIDE|e|Sb7hll7FFua!H+bpm~b~v+F zq!OO!q9*D2!C+Db^ja5xPMIB{ecAjkGlVzeIO6`ukM3; zSRY8XxJ}oHW0(Us$183i9CcGVwb6_Z;=K9SF znGgUQRt&oO)~hCNvulpFE?}e1HM2_Z%hcQjb-rQG*}OVKnOT$XX;F}@aJ#v3(?Xyv zMeZt>E+$EUTrB=!WwzV0Sza9PX&JCId{zG^;W71iT4kDr{N|OGZSLQ%B>R73F>sos zY&S0$>h$fDd{YmuK%LF)P>&Hh0NnA{Jia4LKq0$ka`%dz$h^hsP^*^*$zZaPt5Sqa zrxXqXx_|hf9fF0RrZ$R6O$YnEKCyNC1sEoYLxW}+- zAN%AxvzVUGMA>n5BA4VEtdp&kN&WDatsmId)MqdCL$#&PUatXdTl5Q#qhD%SzZgNw zUc~z4psinI`r<;?FWFB0(l5}dU%24b4_?0@^^4|i^ox2wgp;A`_3>{^$X)%tn>*(S0Z+I-^h zc7680QMawY`*`z{9JX$dMc&RXi|`z7iya%V&BUCy>$+UnZ9ar4J}z+GnZZ;k3xkG( zr3M3Tnpm9|U%A>EstDsVDLT%(`yL68OfFsOzM!n4JXkv+pn4S|`xyo@@%Ftv?0)Uo zJfWZC!0}-dwPTSKBpG0p$J4YFhpt4D0du4{Mn?3tMi=g zwk^lgURBDfQ5|TTfLNqPF;#ba&x)oPYwNjvFktUrgg)Z)!r$<(a)kZ}l(x z{37+*HG|EqmnLDZyf+?Z(i}wJ2p=b0fj&kN)9@hzGkzz-zZ1Ye1b7iRY4BC<#Yg;(X_Awd7%Z>ioZpvPnh$odWu#o(^gUQ_--*lcK`AAmH%<=djij6?`H+}ZTVuQ z9%DG}DxBsQa4c|CUFrB!T155M40(KvSo?l^m%sBL%gh+O0B`No`_r_wX$&dCc8OR@c#fWO+FS37I=yg7K< z*;#Y(xKUZzgNF=>ipY+d9u^Z3F{J(D{vlT!Dh5B1GiTl(|ERy(5Pw9s(NkyTWOMiM z$q$8PHtme7-`c%q%LDf)Q+G^K_g;{z+U_pjovR{d3doQ*HcEL**)|;{ZGD>zGu-lh zzS!aGpE1L&K=PAxOZ!fc&jVbtU98U5n|g=ozCkFvVpmR_sz>mOpK|*1O+Kp1e#)eW zA^CSsN>!N~&d)75TEeZB%NEpf+qw$8<IBI5L6x^ zyLx7L#tFW5#jQHYQ`CE_y?>bI9ExIjJIxX1*6-*V4lGis`nt;JmM2vz}HfUlEo;IDw?#?@F8C#rrZ%jA&dy|j!IboPvO@; z{P$99v3(qEpAt1v?~y&m%Mf~S8KipBd>P6AeK&n)F_x6^ssSe&)BE3Y%d#MYO}Wb6ph%H5cu`LZc|v zQsNpc7*75MsixfD%vrSE?~MX?H-d+eFHiSl=N)p&ZSEv6O80A*zj{si4aMQ@`LDKX z6t<)t&Fth6*xYIN&ZiGvMsbhh88GH1R)0Zb4x7f#--MpQIls594-5Ld;Wc0$r>e!E zrr?Z@vj-jN{Rl5&V*}1WK=i~2sieYD3V~lpbGzO1E$7|a_lZ4zy=$PiPk#L17w!y- z8by14sTAiSdnUo;iGMi`*d!8Uu_m2uj(7fs(sM}hr;c+=$_Mb>N;x4Wk@Kq6QGi8( zYh#AS-fv5Dcg&@t_PGGkTzDcfJ~F5K6fm+*EvC(_c3a)LiG z0C=MLkN!XwQw4-!tKYW!5#Q?R6MI;z(tC8H%(4*V22^OmLYhe2_nzpwCRhZD9w-9r z%I_jCmBP=Q6#qp08Tjlk$k9Boq4Nx+j`9SL!x=@ptaiwc_O(5o)C&DG`SE+_wj|T_ z%4JP$adeVTorop&oRTd4Rk?&-vB@QKpj|GtMt6`)G@h7Q3M1Sx7^oreF^V1MZsM7L zb?!=fq<#F-*3Xfh%{$T~zegstmnn&#|Etf{?)-Jd|MK~rzt`O?hPqEFw`UN9B?Qs+l^JKohIn4iZr3cwg-RKYTN`0ozbhNOo z#Aj)tFnQvf4=Sr`B4BL&q{G39Xs!6)uJKYLauy1{)b6NPA@!f@=ASV@SLN6KKg-2$Pb5(AD)r?$=qwm8ydYj z&UZC~3-_Q5 zpw<+7KyXD9^;9L= z+km>|qUFWzssPdS`SaGlxITu~|Jlq%`qNT_Tp|FCsw~n4pCj?UIojN6t44LQjEo}3 zRpYnb{QZvDPmm=pWCW6-gn=|_XiNYPV`IU-orf_Igt757jz?l^KQ3+2!_^)hB!p-#YPp0ulfO@Oi8ZVjz_Af?qh9bi;-y}LCA_eZZXlPz zpc2XL(YQtRLg{Bk#YorbwH1V@eEUUV{uFsXg>P-8>^RTsmaFSrdcb~8rBVo2Ldni6 z0LS$L92b+z!uhh~G=AdQhJ^&-5tjE7^zstI@?hZNi^dzcMbzvI zR7p*xCsni0WB0rMxW$4w|KMxhYKTfnQ&;m%i77g4G!ax){SIKgl&Qmj@a+PM_{;jW zgY_oOQ2hDcdi?p>)F^;`MFjRe46u)cJ3dBH@`b6Em+C@`ND5yoK27?S{7jlpcqEc3 z|7f~j(d}R|DZz-@TjqZjry@c$wFd~1E{fL&(G@EjwIBX`&3d4=487qCICN- z*WF8Le4EnbhT7^7cg(0I;wuKIjS|8g3u6DV3kEcTuuG9SbrE@dS}BijonF`+NCGf( zPe7@wwmeHLLRM_ADDlq-aph>M{+*p3zGz@i{fNbfu3p z-;qh7*})%)95u@%Zkqge-Kd68Yr|vOq#v~1AdcX|PrNS&J4d4OY}tc5_=ZsZiy2a~ zX8|7Yd4EONW$2wCUbjx2G+WcW`0ap;#bHv)?sjiV2h)!h5byR>4xrkq!?ry@1-)*^ z`=V=KC0wK1ChsF&k&#MUZB|eSE^w$K8084up)jFl0uvB#@R}px32CKs*zNNzgdG=1 zw-@=+8PY?QldYfixk2?dGKg7}@S@D`b5rnSN*hqh@kdKV@C5_=qdYj8<ri#>7h)@U63VF*OUXVTy{9_J74NIP++ zJQ^GYJ68gef0!m#g8P*5W!-MV7fO1|T6x8yfyEKttX0~^JcmqP&&@PGwPUq&v;~vF%E9el&>f-iMxH_)1#umQbm}CoIOA#ED7UZwJ5b*tk+8e#p)?s@oH^{)(Kc-c+ zitYds6S+mArAIfaQ}N;JUBh#}w;dju64(>cGV#&%h4V&&nc$=LC7_nfZa1WkL>D*Q zmkBvbk!P7FGGxd{o6#;8rinkW1O?RQp%{Jf#>HMz8@(vfJXa`f_{b z(RoRbqPD_aDfcgBwG|bOhL8gR{$xE5);$0CWbCZTHAsn!ggTHT#alsoL;djJ;7>|eIUb1`hRKm-PnPuM8hQaGn0V;2G27$yKvp!A3Zl_Hsv$T53N8+x&x z$;%dXbxyp<``Mf2e9Fk@?3_XV19s&^JZZ%YoESS9Go`c}uN|v{eeq&!9Zg6LO~}bV zm@pyDdb&ZhK-g7(w9(+)GyMDMXNKpt&}K0y#{Ga>WuYa+CaD018&Z0&d>L>J~$FUOcreIkts85-%b0w#K>88l0jqi{<%!W@k; zVdq7;e*f~CP}$>p>kxjZ?H8sI=CHA8EK!=UW$N$2=0mA$tY58FNF3~>UKbJp$Sg!(4W0S8+Ow+?=a7x%N=zq2>_cUfTD%wmMxhQ zR?%QhN%~JNY;Gz0`3r1rt#ZsQlF9T;4r3n8c!+nY6ceR-b((vmGw6|~7Mb#@)LqVE zmwk+)w5XS}T(EN&^;7bwb;%2y6=9z#s8E$ARfW@}0`p5T;YW=5h48E@)UNCv=SKlJ ziNuCU(6%DI-*eAL{}b+M$7eGpqXBJxC$-J5`56*E+aCMer?ixImBGrfciKN-88d{i zEl$)~{RXu^$y{oGY}m&ra$G+4y!o+A7LZN{o<_VYfYU0}k~AQB@bo6hU%_}`ev8)j zw|(33d+B%f{>uXjL=>-X>WA14o~bqs9C*W``3cuey4cnhycF(i)vX^KPLj39&ve7z7EMi z+6LFBMM~Q+mbxxy`5XF8u1~`@1LXv?#I`=VBlo4855B<=HO$9rqKnqp37BB1e>qHR2^_%9z1bN+8U{I3}g zawt7-K11jVK}E94Sw7%TNj5M{6LbDIw(y~J9_Ps-Mjd%Cb)2n^+|E^a&-YQsh@{YF zKvlbkG3h`R6~k|r!U=;al?<_x(-0N4c0(+G$OP@!G>0KJKjNsDMpC-7XF_t^(6={Et$ROVF94BngF|xVs zIjoVANwDZDdyYTRbEMsLJV*6I8NDccG9VfrC<)mVA8L`H_l z?c!rcybSi|dHyf80N$d;Rvh)x*`Me2Kw{15#lyy`zTQhctJEup;(U4WqBn%D=pErn zLbv73aUTp%f6H309C+MILVM=4dd(#-_>eiUs?ngzjO&l!DayhgvFOX)hDl=e-PEF? z71AFoxD(wTsq(#?86j3@_Yn-E)TQr2kj{MbV?jRRqGd{c(I`n?jyRQF#;Ft4%Ra`} zCF|2Y3#a63%Y*9)e4%xlZoqz>|80XZl{QYP)&D}~^b?6}aFNl`_KQ7Gv1&K$%qqrQVhPY~{>{OI_}BVcAt2ezzG7mZ819et&NQ0yVOU-R)U zp;5pAe$4%je}B$*!*g3{vpDxA|Ne@G#kt5zU-Bb?w|hSE7P?oSEWbdB;6niDGvj&D*%4NUZ{%>JT9&tQjM_;_dp=4-nfInB!OG=SL0)R~h*6bZk7>GV z^j+D_#wh+Z9xeDWa*OlKG;A zWE9yt!498XhV!I6Va7?eS!RN)DG;$Ji>?l(zh-qtdAx_*xJZ4&4MJoW$(Z7kqmd`v zCrnE*sL#vSbI9~a9i36z!XfGvCtt`fL{Mtk6nQ)aI;mdiV6tRx#W+z8^rz{8L}rQq z%>l!Jm_*B;ODIowcwHNi{{JqBOVrkA&kGF%v+aX<2G%WUK1uD?o?C?KlMzFJR*`D2 zY0mwcAFzl0b|kaW=~`$DRtHCUv?2JL<r0e3ypB?-}&aCNKVG*O}WzBU; zKFu{gmX$7jHDqQ?rZy|mn4KLlI3qeTD>K}YeEM&lY|q%_kh3}Fp|FW3cLr?j40l5O z1~}9#RuJnO7IKQE-&X8e_5ZV z<5ro~b89OmvvfJrdIT|pJoFSb#8>=>CPQg5g%w<&<+R|Bnlx-80wtNE#ovCrystjg zDPts&bE_gQ9wxvvQoZVVADV1#W=?%dcNY9q@1wR=%cJ8~kr@V2}xiXWCG8vyeBv~z&B1{5cYow6vTwvh7XkT+>1{Cvr| z{#Mc9=TnOj2*~nPrb=YN4O^rOQkGy+gwW`mA!-yk?i-xr&8IRMLULHjo74HOmJ@F7 z6&coyij!kG@zuIvNXMbNy;zn<6XA*cKc>&^+qqk$zvtPu_TOPnv)|db;0|E=Ut<6M z@RNxrQS(DaCxJLK;Pz|#&x}ujCF)7)yR?RdW4g#M-qovQVL1#-Kv1CvE5R*w&D*^= zb~1MAMMWIIV3yD5;{Q>&5N~5O*RQBO`qfddkb=*aXBw8Gel@g^!xg#)aEIn4hF8{3 zc+D+5qjV?qyll$Wq;7+|x&|lew%1_)_#3Z0)+*-re7dv|Hc?yw_jxUZVHYnRO@Z zUWPR+!?2g`Jh}C_XHSPCkhH~|ST!m`l@Ulrv@XEZXQ{qavYQLJp+}WbW;JSIr;sc4k~KtKbr!VK63n)U)N$`zZJjKc@ML{Z}}>J zlX)CJJZx+!p05(mS3Px6fa^2W{gjD0c!z7MZAd>4BmEK97|sWafn z?8?xo%IL{u11ZYDgQj(ZjesQ&?;1SAWtrkr| zC2z0q65rZYX*Vng4<%VaH1y8x>qL*i?w7;vC)KUfbKCN2M`qaLMhy4+6Y>_MJbRX} zP+LHG3%2Q8-!J9`$;OwF$l5OhrM)>%e?S5%Tc!p>d18Tr+LZ|D6eFY~3$v+o%}Coc zww9ZoYk&`KABm%zVvixsNm9}KtV2hk$`AT|48<4@+spF45fLGHo8(Fb8^kU|^uAMZ zC1?k)4&%iS88?7I#QfT5be+XQMM9XNZO4`2e)9Qwm?#(yn`@?2@N(3keN`s_N<=G!xZOKXut(Vr>C_~>=C8r7F&o@BsW7BBwsfIS< z?iY|0_e<_)xz0ZsTLPxK!d}khYjs@r;Kd zEJ#+L8yW@cR z*5?GaD`qSkr_%FZ#!(piF z!(OgN)vCMgqg~xe00}Ejcfeu%*g2Y5A>9 zTDIPd*Q8Y-lS;H@QX$z2ubWX#jOvCCgfkZ3)d{2Vt(6$nYkbQSdP#rm;73IZ#N&_+ zSNq-c^aE1j+(2)2g3lVKRYx)@!)9s>WaaQ&MEIE&-ZkEv|M;IUsIP_o{SlXU(!Y`I zcpN6TA6NyUas&%w{Qqe@s+C zb z9sVRssr^%1df^NnC0siSVpiQmmR+m`#%KWXP9RW&*PkF@gxPVL;O4tLfG7|Y=3!5B72 zmyk^?jp1`-6SFbQpZyJ+81|O9;q~0tJ{8tkkdMV*G*RhLDq9aVEo0!$S`I^nNs<>d?M5fi*UUt*Ubgzw& zr`Yo%5ZvdO1$QVu5`$3 zl|r&|^E7(o+nrSmhbTh-=KRblnE)wZMRjqN@IhqC5K693#Ns2KXd7pd;EN)TGpABe zaQDw(6D1_hdyBl)FQ(IYb=apx%aPBO-LCydb>9B%{RrnAa^dMp_z~Xvi`KhW9zZh$ z@vvsp-v|)TwI*Jt>^8Maj;_d0zFED+?_@yld`b~_)ChxQrDfuV?N4)>+Q^k)mCaEjF+VUthqP@+*M2E{o_G!E&4>f4uS zu$)=D4dU#Dv9i6-_?q(#H&V38lB4V}M@T{bIEqTB$Zci-A=OebfRKd=}%p zFILGp zb`-JL5@G4#i_2;O1|IOZ44SK?*A7(fsYyWg#%l*!sui&`O!VCPE;ZiWPGQE8DVK(0 z^^{)gGTK&WBlNpCQ4@sXMA(f(yDJa%iDH?bRkqB})Ap)~-XjWRY+WXU)(QELDeoq! zb8xR!$iPa3EZMnU5mjnUT8?r{MgBx&Lwa94E1A= zRC_;0wV9Q_-H!-5N5gPx>r297sV@&Y7NMlRl(-Ck1E+G9S-eo7Yj4v;q@pgs* z{wQ%|A{1QrZMrKdE2sJWDE^C5ObcuDa%o!Bq>nD_yKA-suNw$u?G4Cgn1BYt)QlY^ZV44SR6`NCl!LcH16R$Yy06Cm! zHeR4&B&IlS0ArR+dkm!}#BNA5%1l_nXqbT9mS1@=7wh7$(rsb@5;u2YW${%~FRWYTuIiKO-j;6(REgl!?x{Nm|b*K*4rD`HGmU4)77?YmE zl9}O`<|xKQA%@OcGm_o8v>WbR+U;inR=_PzxkH`cN%EHLoJ4A)7w^b(VTzITAt}b$ z$5;m4!`|wb#!Zc~<~c9JLvoe*?8>EN*07IJ1sOZ%x+A$%6v(}L+rLj8f*<~@6X%W z8i8wyxuiB*eJb;2qvh$M& zVA1<=amonO6lJX{a-VILNQLHhjf5=PYcwTfae94c$RfbR0td3F=(Voa8CjI@{{Ae) zha$`KjSEtBx8HNXjN_e>#kOD)?S9Hz{ld7lfEmB*;7*Yk`jwE3Uxc|Ow#}bnapK3? z`BTm~GRfmR;%CmbCHw@oZYS&$*p?7O?c->9=w}v3v*TW)$v>!x7A60H`LdVm+xrL1 zmv#6Do|DKw7+pNi<{zAr!9NIkb64(z&BC6VlRy~0Yb8_0zz~M&_`#4{F0#%28N%=< z@)R;6^|D0oGV#5t+!@WnNy{mm1N;l;Admx8;ik;z5^IxvHBLna|MKT{ zDq{7|dNp(DG!}GZ4*<@D{2g>9DL55e?3E;pm@-7nXpp64XKrXbvQ*I7hQ-ZBA z?Nl(0^NpgEFK(}mB>Z2>gZ^fd>$?+?TmND%@-_C1-Onq=Yg|`_bZv<4<}=!7>#Il= z9Q|e%ktBowOVK0AnQ}ggQbb|beF%-Etc|ehPVPdXa6+yh?e3<4*>h{dvHK1ZUY6L4 z93a@(8pEhV*EMD1^xY45t9Yb@%U3o>nspcZIDyyO|FiMI5cahtS&(YR+e$Rq`GfJDokO_YyT36Jwc>kFgGgJnMJIn3 z7+!^@i%;W_Ohk=T`RqQG!tK!ksMHUhJOFODCpeSLkJE!)&L4D8U-Zx+R3x0%@`h6L zL#Qa9oG-5!IS>n$Ce0j3JQZ>9Uj(cwL-7}SUg|qi>U-b;cgPPXyP2})_Y+qZBgpyD zIU7@IoBx(~%l@x=t~!+U8ZrXDQDio_!$&~xHQu#uTAukA)eom#>CB0Tp323~uh3W?A_18pLwMh+kjtMn;K3v{N!}5y>m@k;fY$+oav-`DqLRrln+nf9? zX`Dj71XF3k?P_hpo$`h1Pdjb<*KKnP+k}pDY3yFxTtY#QjC!Z%2(;7z;uxj=D8u|X zMRE;3_x`r9g467l=75wJjrCR8`<@RRWF6#qUj?qi0zpn^8AXo!8;*B;UaEsA!|`@} z;-;?q#IEnO&^_AGUWfndeBx1ALn4Mu9}*Fxjf#lL%+7MuNc_75<#$}rRyXm7Kj^R0 zbN@T6;>M^5V|Gl;;LND$S%ar%hP7{oKjeyk6i@jbkLuhI4nFaWdhMfymEaSf4L3>Xv<0tpP^0xKtAr(Xyc zPCF$*cGb(ctw|<0N(8I)-oh_e`q^hA;U_d-r!G5pQJ8bsB%Ub?jH%|_ECUPYmdL`9 zB`JN3BFFveeEo|}Ct}-izM94^$9$a(-KXy}-vbgXekhnO6mfUP~Z znO+VyO$ewG3o}AWR)s9v99deKG2eLrXk@p!?*0eoXz2iY!g&u11cdd;y=Us(OF>RmTTlEqw zh?)mbOQxMRKlc=Nn-^gBIwcxEaITDwQgxZsp45i+H4{m%*~gXrd$L*V?M>g?`87J> zT}`G0eE7f4mtcMN&+hThzNhi+ZCeAGWIJ?3vhz)hq7-lak3OeehcdlXSNIO}((mHF zcARG>-Frow2>aB|M@xF>&MHNz?K_+&{@(Mtv-W7u?ZNC2)WzAUJuZYp9U_t|FmfiT zPLSG}dquwDENVxIHv~1AD~YTqu-{z=?8PXku+KYB#VAjGZ4m^U%4YQm z2a(hL&bX<_>9*A~-9@FDhj_iwDcmE80yZA9+4HyAQqDDrcjG%-P2yPWauulYa;UZ^ z=FJTcOQ&+gS-E*RLG#14K{!OqctjhYNY8j`Ue*(|ghy0{Hhak6h?tD%=x}3LbepdE zH_x|e*n43rbf``I&c?;Ki`jq!q?G`BE+!cvP;CXDr-fMH0!*RNRqMUtMUO9ZvOY<# z)oM!_{+v@2&SIXnIzjXpNKU4~C~A6kPbBO^5#9k54IjLNw}1hS<|C82v%G~7 z-!@bc{bYK&-PdAhl2jHp9Cj?LhM}6a=HYW~wh-wHiZxGF%28jZoRB-fYx6^818edp z;vhaok>mPe>&;93L%tL0Ik*AB^ik?AJ5V26y=FWX6~(H7@<`OfE>_G33+!2WKE4Hi zN%ii3fTT~efDxn8_^z_qavl7fQ#kx?7%i#L39-FVw6FEkR%bwRp60$Zz764Tg|{`@ zQ^NFN-HTeJc2~&}cjoh=(e9LPP^fn+o{sJ~!5Dd^T0g2ms2WE#2+dMZUlJy;u~pRy zRb2tSGkuJry_Tj1?jFsDthk7{w(15f4D~L0r_y6qCMZhHZ0!uPr?({MMK|aZs0WH8 zdMBK3yrZ~~O^`b#2i=b(vt5o!erq_luZxYhN1Db=KT36@&a?M_PTxsBnX`Nf=VFBE z&vaL2^yCpe!3uo)Fpz|`BYg8S%0y;Nkl#nLX%FmvX{>BXuHb4+$t4Zkv(5}=_#J(W zqMa+&*`}bjs;THIWd*SQAeo2$h%C51C}H{?EiPRr2)}V2?-EYph|5(<>yAh@1A|b8 z1gP1;Ju)|{25zODBVb({_lWs#trp@QvGp0fADg$(&m$OKLt}tdnMtGXV6q{UyO3rR zlkELc*>g#;RMNd9C;gU_O=;uLEPamh2UrdWTf0Eww|e8Kv2AWZ1-$Jc({D~boYL?H$%yPtB=Z23L4Kl@ycfcODTiR^G`LcVt4-RiDG zD-^&r z96o?#lLG7Tq_v}Ogx^CQV#7MfR%A9;2Y%3w_M(oxr!=?d!fkm99qW~#+nsBXkBJ{p z#j%|cR8wqWd1!5npq`59gE7f27Cu}$z06SF|E#-^psIP~l*?1=3RIOKS9fsPtQYb> zIBr{wa)M&X>M8k#4w-BI3k*~pp~1@aIZu8XASH=|d?HVjutaSVDH+T8#vUn#i3Qr2 zwdl7 zpRP|Txr!N1;6)Qq-D;P@WE#**;A0dyZXCAW{Ah;z*>m)KSN~%BETNSfBn*(nQK2*1 z;;F!pYwU}Bzh5asaT|y!aWEgrUR1$q(qw243o4nrEo083pJujr%B&`apV=6(`tan%(i78mLIBGpA%o|kqVlnt(Kuu0&nbP0hBe!oAEVfQ{Ug>_g~XuHX3K33Y|~de+zT9hjHJ8S1F#{BC7MdO zSd%H4x}JTEqMft0%~mDd4I6Pb(@S47j!nJfmKpAajaGVaKQTA+axCP-3B2MR-HRDz z23U-x=}1N`(TNv;1M z+1R0@w%Gf4ql3%cjvaU4bT6?;obE@~N_o2#%WNF)w!aadXEoHw$6#C70m$#g&`OG> z^}o&0l<^sIMaOMsl(*aLNz9u0CKmBFIg*$)v!lO}VZ@aLlwaUZ8(f4s~sCmV!>1|lRhC3^FQNTX_t9$!4aZBTV0fmb1-X_g240)EY;+Bp@oO2NYw zv?eL>;Vp)jUxBePzW)O^*KBJvlzg+Xk3{^t<(Z2_{G0d*YYHZ)UN;*{LQt7*K$rXuRh|`!HKjzYz~u5)%bGgkPS7CJK-Yy9g&B^%?lDd> ze8#PfMEUowJb(b5L|s<32D^)z@pO$hQ~VFaaqibOQQ*FPwx8rw_(p?1dP}lS zbPs>n*}ZI^^>)T8@V5fg`s(xp0#EC=IQ+|^2yxxOc)!rYW#(=md(m}~SY?f(z3$v< zqtY4`n+KzSWGn6lnJk4~;1HU}GR*s3AaeTUN`n%<^={ka$mqS8Y%9vo!_U~q zD01MDqUVy<6r=C$ek$4MESH9Rx_-rxx|YcS|jq?>T;hs zU8M7WK9d#5RC-W4b*6dum4$x!bJHM{DgsQgtyO=Y9iQhxOB_V=rAt{g+2>{=D#=1g zG$!bU0B)v?iaK;2lBsXuV_}6nxn=&W`Sg6&hM?9Y5+1izP%AbVm<44!p{$OoHs&i`5GT7ohk7Jj8j3UQ9 zgFWYV0v9r^Yr)oYy$9dfFrQ@Xa<5b{%x5sxLY*^x$Xw&X^aWX1-gJU-;iRnT5*bx| zke9giN1=uHYa71`SM20pzCVOyrl+j4A&wun1zrjhx^gQG@w(zlZ64!WM zyurgjOYG=hJ5Xwhr@YNd*?1m3s)cNFi9@QIf~{c<5=shwU9R~De;9SKrz`mk$u=hY z8>Jw(t5!^wN>D-i)HHmqe57#NhT&vFId7oq@9U_4G&G0b(J3pHX=leC-qwHlb60XN zC*FJc+rxj&3GF}X?#sts&skoubXmc&%#xsz^Cipp8KLTXb3&iHchCjpb6c_#v$GS` ziTyu#Bk^GW&^PK{RS$aZ*lM?4V*-oPxjs5we}Z$^{3aWFs!|60NCAGP=U@4h5jdrR zpQ&0TY?3}k(cb40Z;-=wa?~(q>7q2YwdGl^A=I3t~Rn>O;xQkX!fZr(#oUwoX-MM~}~s!r6+VZ(Dxr!$P54?~4UX5V{RUJ5B;G4q$;7(*0s&+qv@il;NE&G9(3E z3YWr^UFC@?2l(HJ0i>TR!|wdq7qNS30e0=Aei%Y?{Dz=v7o?RJ=WArhKo#J-l-A5$MVk@&z^f5f7y~_6pm#ALeidIWo^I%y1 z@dB)=BILsbsyZvMk{*fVn#LO8Ld=hKsD?nUn<#pdymrWCWqXdiAbe-{W9fH6mQ^-x zYE!G>nS!pw(NE89kKdEAY+thw3uTonG*aiA@BKI-?+B6CAJT$<-hVCtztV@I9uHBn zC44wHT*DzVd!RMVcPm+|aM@A|#nK^eef4YAcSw!|fqwfHH18kYKYM?y zchR;5R~P$xr)^ugN&4HqwSRB_+rEu_rTuwZZRgpyf8XL->4W?1v>mr^;WM%OEw&xE zZ-4n0e-HV=u4BKReQWAdJs~8>mlI*E2B@%r*QR^iz+l{E-qpk%Re^sPb$jy9 ztIp)AYV&>YrXM~~-F)Lccm0%dGN0_HY)Y`(toG-tqO>KZXO1N{G`rZ8YcR|O%efoK#$3m!O%w(qp;|EJamrgBavM^MLw*h zwvZ(^?@f%w7?kBy6Cu|=WsT@}jb7f)0{xTP!A5O`up)j3L&Z>|!V7^TopJ~N5Ild6 z-787)wE9t(tW(TxkuDWK^rCWvbC*<>4y`yaKn({O%Vx2VQ|Yk#Uhw!vJ2p?b#>3Go zNtWw+#f|ZnX~loZ-TkR>J28n}B#oA>7`Q6Y@jPa~yo2!{SKXhhI&>}wlcPHJh=oz; z8+F}YB-;DhY7WNf&tEJqGT6ED4eqv9PFw%p+iqxO16ZD;%7dF6jqm$?@yIp7Pg*<` z@dU6fD9-)a+Be&+MZBd~k43{!3H98{;g44jf1>o4%Bm}m`pJJPU5b43k`+Hm`R1An zAgpAo&s^I${2K}jvH5z#Iy_IR4=oR_R2+L@X7hq7ciG~LD1i~qk6Mg(1frt8b==!& znr^LcqZF>UmRR2=-m=$U89FNf80>u56iNqs@!c=hhFW{0U8#q3;WzI0wuZ|3*xEU7 z*yece!64Xk9qsLC=O)Yb-_Rnwv2&+wC8whW-ro(FJCsdWR355QrzD z6#S)|+uWJ@o>7r)6LS$<4w`o6Z<1mvuSkter>X1gVr>*TCpy2KjT2W^!dAICr86L0F} zpf!A@bjil;1a?)4oZLOE6wwNDVKTE`)LAreVJ2w8v=hnZTF~^>Al>w`3ZL%>Ip$qn zmrK*TT()%a?ZwJQCckhB&c8g$=*`Mci>xUI8iA>W8zWozRB7I&7Fr{}$c(bjyJ;=S z&+W_|)hrwtolEm>eZ8AB?+kbCAw%9i?*_O##<~7($Gi(p=!1Dz(Pan!7wy=}FLQ<2 z5f?wro*hdoUsn$SG{E(UKKe>z^JCi5gBxy3SGLS5IP@f&L8i+j89!YmQQXzH&)vi{ndVMl#(`HRjwzJO@fyb1)ZqItlmmVc6ux1)gJ>4rq?T>5DomV` zLfZ^^^n=2>S7Ni>G6O!0cg&ETmBV*b58qXK;qj^~*?#$xo?4Mw7?9Wf!Hp(v^ZiDR zVdQX{Arm#n;wNPS`JovyQByyC5}Phcz(Cb5sXrz)FWBj>fAjPx%#fyKZ`x+ao=tt7 zX2`mRwi(g{fLWR$PbBuID8+6xQWromf4Vm2EeVRL|KP0x71J)RPeCbEs0Y4U2PJVn z?)8$>RUbeT6(+12DS62ELP_aRfEEV>=3uH;RXzPP9;IHX1yhEZPY9>>lbL+*5d(2- z?b_8tli+i6-s~C|rRT`upH0otUp=#X+*-CtU;B(%pRh8$`Nl)^1`xE*#gCo5&ySYx+c^L%mAO+hu)F(s52C)@`7zsEcUtrh z4D?ltdV*2@M2b-UYiW1Sec1i1 z`8Df!*|X!Ccg6J59t*!MMckCLs-q9L4r1QN)H(En^v0?;fkCa`0A~3ii~53D{<;~= z^36Ttcr-mx97ikYv(px{7t_%%~u_1w`dYe_)%&;y7NGn%>2ee{#{?2|~+_HwC@v%m+C5e0o58fS@K;6Y?7;QhR+snpHxJLf zN}I(t&lr^nBQ{K}u(tm2-qoHyBhqi}yv{bey7%;lfS8}s9A$0&anCHY%m$mAxfuuE z`&#1DU>*gE@^IsxS9{UZ?Mj)t$=aH{vNs<2 z*sYxbY_n@)j}S||OV_J_;v_$qqAF91!o|%4<72V*g1LXmjKh`Q1v|3pyMFOW_-Wku~`R(971k;b)gKL2|G=E_$l+@hN2k z74PC|8y_YVH~cVxocI_;j`7Fab5(5EXIpJEa?wVIWb9zLtA5Zm8}8cL)m2ieo*ri@ z$jyq9OQJ(yq-q6S|0pb#pbv1JE17GCBi4;D7OT$swgCd<-!hDrrNK7z$1J=Pqg7hk zVYGyK{_1mLtw7i>6_o9I&IrisOt6cZd52j*t|?fIDK&A-{F~{~xsj@!8vJ zZU|?fd=+3nY1P?;Ga$yr)@KB+fNg^&N0wirJ70A9e5;KMDrB*2qYhk9GO4>SsPn~@ zO9-PAsmwU&Ji&CbVS?`NS3iLP6z2Lw1v6P@)(4=76zrT5g%n%{RfpoujZYUZ1ltez z)t;_acI~s>7OXK)k{aPR6zgMn%LW8GY;qOB2%V%`Rlw(7%~)m*;4ehK9Fg0U-Kg6(T$8)Vt*Q$o6#EbAcyc@ z6U)vwrBW3wW#LS>uQ}p6BCmf|b81yUNb#%ia*tSTD`_g{<-uh04Wsoc6lGyc16uM# zj$-mvDK_kIsxzD6Q6B5i--#MKf;_}V)Cmd4B*L}^csrRmS@zT%+{y_P%m*(=kF#`) zK1LC7Pc)1-KaIsf?c)M@OhR`yE(-co+jwj`-EvQJV-Y_Y?~3hac(J@hcGAkQ)Cxv^ z&`p-9pk+OliGUPYj^bp`cLRW^oh{QBQg`l`?kgw6mP>SHION3b*gzLO*z1o}GZ1}!9MCG&jbYX`KS)!ZjpuM=-p(poXi zl@e=;9}2$K`JRok{55xWH?rSV3Ruo?Wo=LQ@$qc8Rd~AKYD1ZR3UVnAgu>IAlsSLT z6nXX@nR|GcEk1oF{8>X;i`2K4zm=?y6dVY~%l2%p3)5P3s*?x;i53$rNIWG!*Rixk z-)O{b;em%GEnO`M)ey^zGYPXwR11`^nVz=g|6}h>z@jSK|MA%vhSgyaQBV$uhJ`vH zBDl@~A}T2Qnn_qNh@|BJnwnYa48vw_xI~!xHkg|AT45q;YBGRIsf9~|p@C^?sfp#j z)bDdYXExB5w{O4i|GNIykL%KN=FFLMp7WgNxu1La+@IT96bYlj@0)KXq`NO^L zCEZHQAI4K<;%1I~6i=RQR*%%VfRsXM4{8X5#{gFMDfPqA`v-S83dW#gMpK*}#>0=z z-G8PK>^-djL_h;79oF&_w^F>W+0>F>;7zGq-gH;*U!+eGEwQcbjg!l!CN9 zLi0eff5ExOd(-E+LJPk$2;ta^_6Wy*n1XQZ&H3&)_#goXZ_gfGNq|Dqj7RfxOTEZ$ z|2y@AHA`qSU-K(nd%ot5BtCk=Zv?Qq3&K!uD)Ew0gfn106+Dlr=76b-0REkz z906t(?~*v5k7WX^a4azNsC;m})dRkH8kJ?sccL0l;WTqd=e??C9!_&xNeo!xb}c+< zh5U2kN&!I@cT`MVr#wN{xOU$_au7k564laH3~J!HS;TqmIx|z3!q0}@cSGTOt??pG ziYoZ|wzs3b>%R%Y2Z@wcYjrjBbFml)W&<-NImR6~$I_@) z`j7=g4L6K9;>=Vyt&2!>PsonZ-W>8T#D^?%C!b>J;#ql)MzHgoI;}z8coZgou1J^DS(!VGE9lPhAim4CSk~vAfQ3=vQ*d9is0g9$!?y0_d}2xbXVz`9LM`fK;o#g&3OYPt6GgZrHcg<$>E=kD9ZB z;qug#Hu%Ec{*oGo|3=pmuEYXzARUeV)ZF8)CHe=i#cJXHt#--LKHFz}T+S752c`aD z9Uy0R9puOg8BVr28n0N6Ok;}0lL5<{#@-ZgA7dwE_m=T8Rbm6y4TCH>Y>E$!v2x@@xM0Xb#4J^?5hwLs{Lnu2P0?t#$es*hbaI zRmv+>)}T;L>{r&HkWSHn-nCT-$0;lc14ALK1Vum{{hml zJN66kvtxq5U+HH~vM%9Vp;oZMg~d2#&UVgBbPu!!BCbStbU`?0`E-r}gmnU3A~Mc_ zw0u)|?dP;5qJAaaBG9h>sSDqP@-70yxU2bcb6VVc9X%CtUKqbef`{%PA2>}Z$5KDr z`E`ZIT$1`P9Bj7ld(;}7HV!^<6fSvgUFYba<{Cdzvsjl0osS7(VGO3Hyt;Lm3PGko zoYkX6LQM7iSv_t@dQhO?REVK!^jf@=BF9vnBTTG`%9b*rN+PK{6;f6;VY4;FT-0Hs z=a#Bq9e%PWC#js+ePt3zbs9Ja2;!&#Cts5f6wt=)YO_L6?(gNiZ^;@p4(&hd?irtS?C$Q1-F1zVvAbs@R{4bFP?di|WlRZ`lG;vnrZhe%AXUH9h~0I`w7cUJ zcK7-~>8;=MJ$64#MjhDthdf{!tS0-YBF6$BP<9}_)-*lPgBL;g0pJsBSF9fcKB!$V||2Gf*-#j1-;j#0esEm~`f-ow|D=)Od z98&$pP6eK!c#B;Kh=VX;Fs&M*l26!9tB*bFs)B{bG5JLkoB3%~^r`uB&3U^T^1fVJ z+Tl`82V2=_rJJt7K{a&XoZ`(xfq%n~xY;8-egFG9S{iEud% z3HhC{?YCvB0 zjmRA~!bU=dj8zSXk%O}k_aA9FYvd~Xk-UVgta)`$3|1|VOF{x2*ht8_nz^+kuFVTv z&-RCFf`wn73OSwo+6kgYmPv{t{7q|I-NHMy4wfEH^-FsZBjbZB4%U%zCuZIa+spN9 z-%=B-!{u`A=4%18q|2q5FUKu<=)DLdBlwO!*mh(bjbhPd^T?QB_d>|X?C+no85uoe zV|wBjSiVoMkBQ5*85y6@$k?)NQlXRQtBcI>QugBctWO+DkM{%_C!b`zr^6b@iu09^|jPalpKGuEp9ZO(y@>c6gxb zW3jtavy+@rUK4RN^E2#Tlwx;h=6>v6i>0Gkwb;Gw^_=2Cq~=Sz>UZj;*xjZ18oN!g zbTqR8yBBZK(adkLdu{ylIGXhxc5laGx4-5GyXueY^RfG><_dP3!c%ZG^JnZ{EXMAq znYXZeEuW5NJ;d(q1K1s)(MqfL)fZ1uJlL(t$8J+Tb_ZlG!S2NabTqRFyVr`R;%HVe zc5joLx`OiD$lzR-48-cid>r}|g%y9xJcq)HYmnD)`>~ZMFT#niqzO)hS@TiP^u)cP z@GM+=0{*`vP4NHC%33R}{;E;>qT;~=O$m07pTu2X*Sv?_a~U}LIt8gyj%N_!mcqa( zjVB3ltGR;Rb5imdWZuQ@G?cCvMUiQvBnD# z6GD81Xy<%cEvVUQT77=#>s|P~0z0cU5q#1TL&@^F80I*f)mM-+husYSsX3lc%WOxJ z4MDM)Gu@F(PhKt9L}VjUJIvR?F8dvCYg)Mn%=R}wv+6qZ_=EbsgjZ&^b(>O-|Lr}3 z|ABjOXv^bmNIS}rtaaM?I2%&>hc+achdW0nQ$gzaL`h?4;TG6{n5KI#?zRP)i}< z74D=%)Y?hg`N)SV1$#SJ`;_E%f(!0P+@9mjQyauP+hjPQ5Lr!y&bj6`Mh46cPSty)A^pYrFBUEqpVqn*d%dRZ#u?oI{<_&&wFfYjxl};iq5%ad&9MC-=(v%ulITiSR zQK3?WMb;pIOXU1_%it2(ykk;o-qr}Hoc`RRt(UHPPb>`{Te@wM?C^S~WmLj8UoVpx zc95bwCC^PCMedZC_fl}N_jgPxvD==Vhk9}7<(_4B!RbtmJ)e^gNfN*bX4pX+_*n$# z_XHV0c&R^J^`5Qjl|ck8y+pXz9Cfd0j1LNNC1sUPAQ*}9I2%6Tm`U*m+th5G=Ymz? zb|hAXbGNZntn7)wE4&3Op@`f#=? zti;j?3{h$r5FdJAZcL?&ckjjSkw!8_KaB)3>m#2u;a2(n^d&gmRKU0*2}^5h28lm# zF<-#l!Zp_+{~I^OCn{E)r5eQ8)L+0dR6)y7)++KcGU2-z>Z5oL`wj!=>R#U4 zS-;BF5wobDr14Zp@Rc&xb)Ch>U9a#H9y13M9!OjA0TzC_c_4gZgVP#vnVvRLYw;_@ z-_XvQ?L2N!I;l)8*O|Kkq#c{>0gS!0`HQ|Ix%1sjI&* z^wSmZ!9{n-49S$uAs3#2FeTv$iE$nZx04BS39aw5HCJhwrN~?b^?1rP>ioW0C_bHX z+g32HhE`&A6p&NA0`807GEbZ8KI76h>yRzKiMwDp%R|t1$OW$XQr`1qvgieKU8Kei zh0u!?GR}=D_a*%5#^=!^o;Qwo0;0cvl$(oR>)PDIJM*=(`TyKKcpsvb9{}qx@tBz6 z|2!U~BLmD{XelEAu$}_NRUKZ}F|4amP(VukseGPep@AcUfXA)dw)c6geo;QH&m7|| zlr&=16_D=(Jb`>~9c32)f^ncX5t$zj4>Z+4IIF~ac-(y+<>+x2^x!ga?b(ISHNA)x zL*Yt}s^9tjWBYuuW_QCs*yoRllTiNC--<{4lh^vEVjKT|Z__{deE)Z^B_bLBx5gE% zAIRxu#6jfiw3U&xR?wfCGsk7Dc7utl+GRzgCB2h3@9m_Vf^A8sXYY40_E&lq>Yz`Lq2+bxR5YuodSMK*%q$l& zPSqCnrDU-fiUD`S^Jb9m`!6d^yZNZoEs#ac(tIlcyrcp#_P!=k%P%F8P`Aa*w+=&o zflruF7azmuqP%byRxPRt3+ErO5$uH*V4thSHq2kr$~NR>xS99nuDq8GhY;y6SToJs zI?T$pvgYt(QpMgqpZ71uKGw7#@h3*667_LIE+lZDecbR~KOnm$mh#*h;y;ib2v!wU znJSzckb9H=vZ4UFHxc&8z46XXEjHBZv)1Uo4cD`JB)eFK@U1;A!u|sh%rA2Nfxgmhq=tMespTO{(`^8L)Q|L>$x^B*-u^7zgZ|VUuQQvm2sDq)JSS-uo|9JmCKy#J zR`1NsTc|jqL%lg!Y*U%T3Ja%_+&;Grr_#|}v3G)!%G50{5R`OZ4(bqT*8~ud7)*J? zr=)SLIBo-gW^;b>2MkU$*Hj}{u2QtA!t>_9S_1U3Dm)W@DY5|i;0|E@M*IkU=Sd67 z+!!mUo-_ z?vJqwQLfj_vFV>ju?%*YvmZ|K>7DkWK; z#K)`qdM{1k(1ea55mCs|5)6K@38`#3+?%gVlS&!}T5X@=1etL?98%Oa3eJP(89q#e z71>nX-oqwB&+en<1cENuLoPX6e}vd4{}x+wAbTPuQ&$##b)j-6>C-wvpK-zAg09E9nHbaPeh27&0ATz^fqTBZxh*2V+86n0t+3C3c>l5~D-B;=sI$4hmhNAP z`>T9D9QIG#zpXB5#;I&`!QvJ!i6KS}UY7H?gn4Ejse*D&boMx&oR?q3&4}?Vy?%;! zE|O1*@ENUe5p**C)SP+ls-!pm;`!0|T^n3{koeQD2%dxY1>JzH75sMUgBQT0dJ~8N zfxnvr{1yQmsvdC;446Q5@=&1;q%l)@S7~SXG_-N)(;M6Olbo+i$eM_3~kY!PZMuR>}j*nvu_HHD0IZr9U-i?ZdWx4hBFg7KKj6 zpPI9t-?q_VVxT@OYJ`hq$G9tF6_$Xe}PZ+8QkAoEA0`RlD#)z?XVqJ7scZ( zbv;XCZ7E`TPR^YR<&b&92)Y^7#ggaCoqQqnoq&~_H3i?ui^LFpvO(o?p5ZpJ!&Xd@ zKr@U|*L#};$(D5nv6<=ZM^?VDQDFj{FZL!3rE%ed&*9v#!+S+?zc(C(`7-5L@5cFC zQAiEEUNUb{+(<@AaEF?LQpJ=rRE+g*7O{h;5K%Z%>}*vA;IP0mOdCHA!2Nk^Qm@xhgM^O&l_p2OXY>K&;Y-dpnvCa`lC(~I{^pY zkc^JGTy2b7qkU-5*=#;|b_trTs_^^~>g70kv>3nIx}s_*x{_;3!4E-cm{i0$Te4&? zCRJfKnpEmy14F|O=@-#@N@X7={4WuWM##!;4dF<08S%FRcZ1cZt z*AggTmhlg6k_u#-wC8qa`}ec8FLQnO0|LwyE6*wO0ko^Q!P6H zQZrS~G)2Y3wCGA#4@~_teXGBBy{Z)UtmUh6oXE>WmhRA3ju`f{dcQiQVAm3${}vyk zPW12KusBK7^*{SH&zzQ@U=`QILU_=y*5u5mu6?)Zh034KvPJlI$MV+&Vq{@w_O(!H~m>m0iO9vZ~kr8&LZ?vx=*9Suc zXQ3lW-+PMQFHkzWf$Q0qKoFnCn~yVLOmb#CPTjK{VD~H(b4#hGnX?`B7{R2~9d5tA znMA5}nVf+)Gr_x-@=GjsXD#5@ojQ>2G=gKRiR`4-ysUnN3NqtiTa)fI_EYJ?#M4*9 z=}HsHI;LnIWhi;%5HBNnUij9&JhMK~v24n}3|~?0LzN(`P&Z8un~la@aXb5_XMBQ8x59)&C26t~ z9G~sW5_tkjGF^gl)Cd<^KtWb`jFP=`Sa&vl(`ErP#gvkp<-!Ww17T%BJ`3gvQv(FqhYH2u0R!| zeKu&Q$bXHgcx3fC%%%QVJ&&=~Q}F^Q@m#CBw?mQaqd^ko67Slu&tKPaQOZ}-{i59E zc09eH&H;9fsFRHIH?Q$Su*U1hNFt?g0D1VGqs(wn&FSaef!sP0DAIQCScHJcfQ5p% z1SZKv#KpU2$YKg=mI#IE7n#bn6i(rM*FYtqa8PsIV__e_UUI?Smi~6$V5NMxVMu`6 z(5|`MJ~oHfQV>ZBX<4LF3Xc2U6z0?l&m@) zDLq~#KmN36b0z?8^a|$%ZZDGKbJ(6j-bKJysh*M#}J1pj#a;LIAJ{~C91$L^BkzS#Zr z40h-FP5f@9b1JwI`d zNpF6moWrUWK%l(4U$!V|k+-mnJ)oiw#PY43Bb#MqW!A zxzp7GggPa>LPRzJ%dv&K;5PuZO*TOf4@tcxA<`m;@>6mDs!#9}_NV5|e6J#hG_FS> z#I*BqtQm6_c5pY_n3n4^o5LJLhK-5oo|*PK6zt?(s%WI0od?h91u5x4YN#gpFd3U5k} zr8nPSKB<^P70~dKe%?{R0u$67*`pVHzvM?2hFPbXR52zM>zycoaTdFwZ5QHMOvqfu z_Y3lCJ>EyaNOX(iD}A*y9|-e;#cnp0&G`4#n?0+QTk_GGV^5Y+o+*>@*dp+qXyV8- zX7fyh3Yn3IWvwl^6lmrmRHm<&VX0nB*@AB*<>WXIEeab~fyv9s1)bA4HVE3`-u$9K z+E44%3h;MYk~*6gE$IGk0(bS7lIlJ~V{x__^r7bX8n_;knnKkWBFO0{@v90Zy8KlX zGj`cuz-nChlIA+1e5pLQI@pM?i4*REC=eA|>zfm<{85+z8{hoc_#gI{s{514 zj-DzWl-N8l?g^sc?8;tp$2WW0y}@;?<$7mx;-QzyghmMz?LBZ) z@hKLfVtFy)y0j`IfH&BeQ>w2KfrD1N5Z0z9edl7lw^Bre2G6bClEwoYxduXv2XI<*-eA+ zXtTaTESr3Hp77n_-i5LQE~o5me0PuVp<{8=k<(77ly_X*ShlWuDjYbmcU}mt=ox zj<kDB<5@) zv4<*TssJ_yG4Po6kA*D)^-C@hnt}^W%!L-mEJ?f0Z?MTqjs#mbWk)EPjotC2zhkD+ zJElK1_vg>b#?J3N>ttNRLy};T#a8*GVEON6KcIQbTefuplP6gi?ojZC5YE67t$eucRD;`?tf6~5obic>r@ zMv=x~J@dBqQ-S|Ho&`M2_Vjhw(}hdDJsBle{{=Zm+ylwt5UwC86*{)xiE+-`B!>!h zrSy4AP9N{SBP$QP`<_*H#WNpBU}NtB+tjyFCn`|b8wT@u!bznNPU_-dxbbSK_J|OqYXK~ynNjhpDkHskgrVtN>a6esRC26?9Tra()G6h{UaG|8N;XxjgRb4 z%{^L226I~Qgrxszc~P`CDgUHTlW-*;7g}Y}|LFp1&MXtGvXtT*^qW3zA@5O4qmSEc z)U%_tXD-{~-Ok55dytq(yvBt(#`Y8$=7%&v&O~)q`9w%p^lG%@8({hHzmu23C!~8< z`2%;mp<11KKvfF+)SSCMWgViw9c>^xCxgjVTSo;7$1n%x zvc^`KN39L?dP*3f6(rWojj$$6$n&bYSZ%BPe577})k>!!oyEh-Ki&9y{L^jyPM8xy zXhHB}@8W!$MIvG~C7q1<(?Y1pHqT&V`&6;}Jy;OZSG>#d*L$&r1M94CKKOYgHig@~xaALO~mOVl>Xz#=m>sUKSw!zWWrhOO(Q8 zJ=OyGiEEXgi@)zmP@43TXjjpsd5*UtL+_oM{f>){fo}p)mK}Yun#ksp5Pn>!{l)Q{ z*#;Nkkk=95s%!Vq6ySQmXFj`#wA_lsdH#K(4JMkn1N4f!mJrXklTQ=BLVHUw=+oWpcQqjjS@$m|D|cO8>65c6 zRliou05i1`#6x2sjXRx)5fp(fG+iMs$vD+c9>YDkczliPkCi3*)MD=KZc21s_)e-3 zFDrC0EnjhugqUV<9--u_0HKW5LWaWN!+2{deF;s@(IPzp0b}UQdRPv&rF<&F5S)n+9`^uPbX6c~%*! zZKVh7#f>~9+ZnGe=~9@3o0Y;9DxIhNNUFpjjkE8T=+#XnTmuI)&BGd+hs|$b+vE4Q zxg}j{i0?!&S3VNFCh$YZM`GSuw)UpartS3D-}&D3JNP%)@7r#-((i1pZ~i_cp!NCY z&*rVE9T>Wk2}vuNh3R!f=LbD+TTAp^wR9?Dzy3k!qbQPz9cRL;SD9)tr6w{LK&3n3 zsubPSQkWEs^SZ7icQ}DmUs4PVS}w&R9{=uIsVtx-cvaywWpoS3N{wN03$)zW!&Rr( z9ujYi(IymH@e6nJ3-h1*dXx=bjvR|(_w zr_rh-!P-NGdxXAqKB*h|pM4p8dd$)XLd@sGx|O05^DBbG z#?$UNcL(3}b$X?|YiWxI|0&Grm71>W1zzlv4BwsT`fiK;abKJn*Vk#t%&r?02@rB= zN2=mB*KzQ0zzcPeG$|bRt3S+5E~5RjH`5`XvnX zL~z80m2{&U<7eqE_*v~_Ps`65v|jh7j22Nz_B^d%Q{<0g$?|YRp3jOmpN@Mb@f7ba zzTue0bqq>-PZcGRxb-vSd5SuWC8l@+48JW#37uEP&u;dcon+_es+!`JuH2+*5lh@6 z40-+Lw)d}1p3s2H2!rLyAxE`No2FCMoopw15tl?m1sj|~x#L_0-nDOCRHv`s=mnyW znBJZe7W!00$Fb5h=_T{M~ zJ_;>FW_*$THpx`we*fAq8NT?$zC3%_F84T30monVbzHVj=yyt^zwCXzb8VQtASceR zPV|&pZEQ5Za zwS$voeAN(9YK@`U30mw7S&s!Mjya{9No}a9k{|YQ_V*H)beln`(edCLhE`)#3I?U> z<1ZZ?#edi)sorChrwL7g#X50#L+*k*2hAXs(=`iNvK|r5a875HSgU@)zfFWc*DM46 zyzv6<&JP9I&fwt10v!A(1q_sT=l93K2Ul_M_JxU{ zp-dn|`nf%-4)O(>b6(Hk$UIOx{u~39BCe18E%;RzXl`dfJBZW}u)V%JFzUNBK)%1z zbP$A;qf)?9Id|S*a8KTP2$sqwdk|7CO#w^g-1$*Bc+UkamDh&h;Fl?2o}8Pt#%}+z z+k*)&|IW2=-0o(=nwi4u^{;5w(iiiQ_gy25E6774_bAFZy1a8EcK;r0Whs97Q6n;# zF7IBA-7kIm;YJaeU)$BBoZB@B54_~^Y_yW772dpQsJ*hhmSJC0y?S@Ns6`lkq3 z)udeB(b>y8_I%(&a?TJ!$O@9kw&r&_>5AzgK;Ruy4{{g?vYV2nO z7w2{Ce%y3|cctINhm^V`LvP@jRJ-gjN&beuYK!MH*O|JvbCU;W~R z?&+t=B@(O(?B3Qa1`F-Qg1^H%TZKE;mzR2YO6_9w-8ux0jv2R4F?3N++~>J-o6v+= z>yjz|Vs~FU^2-4_az;!#D&gCcr31Ks_pI(ob(K1U-&5J{&?l2G6@a*NaScd=64RhT zN2|#N&hN)*%1JnF9oxpnDfNr zzH`Y%?s4w(YlQyH=Hyv18ti|Yj;MftX{X$;D zy##sGz%B5xnAss@n=XJ^a{>W52F!Kc#MqZ;9X(OZNSU;X zY5@ZC%Y5>P+dpR8RVtZ+XDqREI^r(b=1i#5xDCEJz>Z*XOKpkX2h@jrI8)KIok=ST z`a(?=|G-`8BCYm4%mWpKD*FN`OME9@S~Rw!wSLO_`qb=iN=?-S5c!*K|Dq`rrT~#2 z!$7zk(?K`uL4o?N-T0uR?+kh1WqsMQ(2?A99xqZ-uvpYl{-Y~-!XF@jv-8~tvfQMc zJf?y*i$SZHkD?_3j{4{#H@$cWK&bIk2aBo$GaP)~>6n-uyEkP>4tVzO5N{t6!QLSF z0B7%WH^YGoz*(*Z{+H}SxIX-{yMR%l^om%BrS%Ohf)neLMEVoW@<6ePmcJAw0U}EXP?ZPRLmI)+-Bi8=yYtpWf-Y>)4=fl+N4LL^qkEGn zE(qpKPZXKlSBfKN%w=qJEikr$s{v4%FM0e|1f^GklJjs&vc=U9_fE2uD0@?tVD{}p zQ<@5|`MYA~XWL`^*6J~kwN)6=BWP%Ewv_B)0_Bevfo=xtz`QQT72 zt|Fn1Th-9TK=U4$l#j;2=Vacp+Dy#W-D$FU*%tK)can{3*)B1CZnLdr=Yc~%P?VFZ z9r0aA{4t7Rq;96@(3z4q6krzuvDeEs#9o8_CI1Q=sla@hg85Q6cu*QNBp&e-V8K-> zPQI7=&ZL^=B4}Ou6P=vif1~7I#)eyqT!aG?VSU0MNs}#m*v+kWpwcVUseRz({Y26w zQ7Iq)1pw~TlyNE{ZUI9tRWS0L{}J~f-glikve^yy8%yw!kt6u~`G^)!bt#$+`CAyI z#?Y<{AT>KAMHzfDV!jeVP<{@%4Tl%0vJ`Tp#vpJ(>pG8EW+C_#KUcK~C9VWiBs5(v z5iA$-HLOHaidAm_Bv2KNaC&p65CsenWAoB+64!|+UWv~EHdR(tMKkKAW3JFPl)mbl~|J3 z{&z(Sc>?>5EMm@BXVq{%EjxDss?n{??6>u8OLB?FPHeQM^w`(qzc|%mz|Jezz8G+p<;^db{m4 zIyELYrYG~j(ppPC*W~;~2&un>IVBy!QDH&+sX2k5r;z5$Gi<)lx?nqBzA$(q)sg1P zHG}=fzmi)Bg@A2F0^{uz?pR@0CyX>Jk)3A`=*0tGQGJVFJV&@6q=PfPrB4SH9 z5nC$8V^DAfBhFWX_!coYHyMl+h~{@;!8*5WnC6PrS&oWZzhXoL`SlH1ie=ZuBK$os zN0%*I9(Sywt44O|?1%!v8j)~zjo^KnKqp5y`CqD-C@bseX02VkU7qvtp;$N6v!LQ; zm{bVCh=;t+?<^m3$HbWXk|ORmj{HChxw8Iqr7qW-_XCX!@F&(3{HVk5wN!zVj{_Nc zckP3<-|>kZ?=ZgKj&kLW)6LS*G4>rdQ*DlBXPF^6Q!9Sk-~f!;r{7B> z%N7na047r-h$O`&a{9VRWj-PifT~gPk<{1Ihq_)!EjA2~tIov+F zu~)f&gToMmO%x-j6j{gL)#%r2p7=)oAU6n4ES#X_DS+}N34x$9!udbVULTVm+Jio9Y4OS=54Amg_)yTHjJ~m>4 zLgyT5oUFP|*DhGBvw+SLgOVDD}=X9tfG@WoZFX`5Q#>`WLS{%8cEUL ziK48(?S(x(R&Yopsm+Op@7`C~EvP1NH8{jBo`hKA=}Q`kzGRYcjPMX2t8zp?CrhVd zLHCBw{4nu_W)olN)5I706chlJ7c7KSr$;&at=txf>oK5h4D+McM!BuY52ygU`24db z`i=Z-C7-`Q4tBxbmb2bgT{E>p=VqnmXEo=sXgt`SvIZfx##n?vccdV`cD-rvJYlr_ z1n+T2r24^jR$`mvEa}h5QgZj(pT#cwQ*-~{`1^gCTz}pYbF*R`+t!4KOlP$!&D#&( z6XGt`wLZPiQ)4-o!^mQ;qvD$R7}d0{pf#4D_A49O7XEy z{w<$6^U*FXMZ2a!EVp+PJS~Cnje`%)d*|@e<7%N?dz%WgJ@|56;@82(<*QnI*@s_# zp>bZgs-e}5dH+p4hci>TpxRR5@()?a5=HmL+ zo}PW!h1f4X6$-=cL{|!hW2rkn?A9qN)qYly24XA1Mr>{Hm(0nw=NQ(@ zfbMKXhfLWNQ9HmU4c%YlVUy~e3kR9q;2XZX7p1Y3D|@>J%j(vh^*!DiOQaSr@E$(> z@hR^Pgb}VYPNW zNWzY>Y3g==$@^Nz&mEbBoj?+{A;Y2gRlR==%Gmh>mzHa=pB9(5ErO`CST*WIyYf`t zqfgPwHt4lyQk^PzwC3E({AZ>tn!ta^aQG-2Q%*1r|29F+&O%`wwrPuPxYZXt7fpZ0 zlk|nTY&D8eFF>K3QD6p6Swm8JJCKwM=J~;^6h5y#Tu0l_GU0tQ2_B@zSKwTl=LhFf z`23Fe?(S3^yu1Sk_wx4A>Orjbjo(4uAq0Hpf-`?P-uN`1*ac2v#67!1bF9!j#BNjm z1Xd=h!VONMGi%axv`#eD>ts&CuoL<asv8S9by`Q|MZlaVXodhD0CJ zCwXkORVM#$#5M^tL^)3;8wN$K^~?&OwwiGvFj%cYQd3*|vEL14GLjyEa3Ogsf(Ww5 z>%1)ARg#QJyXxR2KuY285ags9p1*EMiXl7*G3?ZJ?cWv39x!Z1qL;Z^2iTf$`C?Yv z`Xu;Fee?5ui}`U~t@HG)~hw(o4Q2IA@N%sCM&=|C~kjYk}Yv za4q252QBAONzKRi%ZGzX_^0|uQJ921-<^QB#CtPIV zgvgCTk~Wbim5YBs+fCrg8~K+d`-63a5u-JkuDb)+S*!C2Ov`ovNKbB!^`P~SV%f>S z&|<^>)EqdC**Y|d#hnS`%i9+!7ot)bp>0WRl(>Rrmh5DrcNY;>uOWvIK+a2oNpB*l!GeRNybH5+7fr! zW9wI77hYu?1MEC}2C@#)vU0!4m3P$?*i7yA4Ux#aB&r?2Q!+&x__e3Kbe?C|xddXF zB9~XP*wxrPqf4nnrwyH$ZKC7^&x%8eoIST5=bl0=tG)E8aZjYn`Q=mBYin$oJ%B23 z<@J||w3h^|x?-@g@1Y{KG1wSAos+J3sf?xl{rird%_FXn&##$G`8D4J8&6*Av(q^G z0TDnx94z+D-5->Qq?ty}(Zqmq+!w?HaUG=Po?TD#M#`mQnUW8RgshxG9w*rB$%nGs z=WKIMZGkgo=mi~{zvpw{zAJCDP$}$oWLp-hh`b$z=7lPiD%J=D&*C3B+W(&25Q|^V z$zn4s4@`DLmimCY=-e)ihx3rnD4P(hffeZ%E532@qDo>+Xu_Rdna3e~ zQ8CK{D-$vCUED$G1WSDesnjv9H`mri^>q`)h82~Lazm|X-3s>X&jn+LrMo`-dBgn7g z(FN7qc~LLQr%6lPg1kiIoWfBS(sZNK_ruJj>9kf@RwV)il9!m`slX^L;778Bod5UM zitlg@4@t7c7X^$GrK6u9-z^+bEKSOSO=^QZLhY1b)K1Bbz;=06yu@I?l^j+8C~qZT za*V2-5KaO44LJdU&Qc=OmXYOi^%qp7y-D(c@eb! zYT_b!ppZa$@N^L(^tm?{H6IcP;K7)t64XigR4V1_$w7-J73-2&Az1;*~-AsdD&XYmR<9W#}=13nXVS1wjfFz@5++l4JMcVoq{c5_S??M2RIK zuCdf-Its<~3DUdiMev=qe7H?Ewn&A>XQjGl)SXpS8hH;^2RRypRO>`<;G13+aD{Q5 zp3>F&#;+vg(aMYw-NxESp*u@-3BczJ2ct^V)V|}oPgdB^z(r07M{ZFSRHxeaG?G;{ zG0}s19vACWsFVAc5};~7NCkQFdY8EY5U%78=J%vC#5_R6xt=tBdjZ8e!8d)Ij zjJmh@)=0>L=+5VJyYL^jNhVMlq+l5SwLvofHEo|4xD@|*E_ooNY{gWPvV1ZW+`tRg zS=If=>iN4q#7Q6WD*n0yOt=5aoUia`b}`B?GRWji`)K)<0z~t&PDx^w4vrzuA>(*2 zB;mg2)`SYD3y!HF(X%ekCb>$Pm|4Hf9;HP!Q>TBGdxN{ZsRDUgzs>Ur$L^lzuzRL4 zoaMB1jD#<^B0igPA_s%ta+qDP=h=Gn4b4A3Hn<4Bib=|_WN8@Etn^RHkC2;%zG8Cn zI@8@WOn0M$gxl@t>3JkoqMey2nhdUJUSYeg;QKsaSZ&c5*TVTYRq#Qo6O$(?&yEV4 zlr>{=AI)SWDsy zzTp|68R_8>itvnnL;txe_2<+xUYMnsoH>(I{F7JhHd{Sy)@0=2=8kwaWWv|wX*-{M zF*;Qv>xKSczH^8ohIM9J6UMSo&toXtZci`ckMCLX`0bW_9-|5W3&UWR;WPQ%%S~JJ z@$#jnMy7EWZOi8=a(GHhfS4?z8r zL+l%gW}ZS-Zk)cwxH9JR7z-%w;63jvdaQ}N(lZBK$Zz(m-ZzI8< z-?SGT%Gq+0K1tv2*vizB3scr?(*He@u^Dfgpc<@C~dUoNuZZdvJi*ar+Ec-D~fhCP_i=Aqq7j+be7y2jZ?4Bv< zRy4MM&6n=0jA4a~fHjp)tMvNphLb8s{C&mfOj%1nhq1m4xhwAkKpotRGo&xIblSXu zbby{ku~>!!O?!xmz7EShyVHNt!9-Bi29tI^D&+=o#xr82OF1bIsI&mXq_u&$>3bLE zPcbh>)x8%>sbm{grfrh_Z7#XEdg@x@E@zi462G{CPYT1^ZF5O+|1v4Ds`Kkx|ML6+ z=1V5B^-T+T^0(GE)cs}^z|DaAQAH^IH(FUH9}o9-#j=JMU}Wqd%OYV77_l#wpZN=G z-Xp%P&d~S67j%Z(iv=z|OGe$~`aL>a>J0E`X6CcM0uPuyipNpu;I+Ei_0zsyo(nYh z%jaQXOjrXWsBt^l6Ph*QxTs{(zwHP{_a=N_&;KoG6>KZiSD{)cpLX+NVVI4)T~q=; zS$#!HG8I{Q_&&#MrG_0j%&qpapHo1vq%N^t<_5wCR!m?S2Hi&)O#QkYx1v03;th{hrBGDEhqDvx(dh zlNbUriM_><|XG^tNp;vPP!IKy>wzu>BY}5RTxpIXN$MEJQV+h@T@c<2>OldLG`QwFh2@eRCk#SbA28YvQ^W z5Cy4NHh~34Oc~)ka7l#<_CtimC~p`aP2|aHo&L&_(2r z0=K#zSCk|oXnhey_j$-iZL}LuCa`hiL?#=T#!`3mM_qt(dE%wq`C< zsn>)uW%m@KbiY)@D`o#GpMc%VxD@+Sa{@sC_H6TQHt0iH{vV)efaC%5M@HB#!;-XO zt~Q$KGA_Cc0j!(`_=q*q4Br*Z0yt|0hvs6>7$NaURFY5YG#jM%ImI^ zjq`Lna>HkN^dP(dWCWd%43D08ym$Q385HbnC9LT|L9UHQL#`za-JJDW#&N`5lG$_yC1j?LDO~X>m_rH>)}zJe#?`ofX z2{J~>WtE_e|8g5|w^?dOHzEIvz1b{~cJ8Bg(Vv7^xbq?@cb!LvEKih)0>py{x zt5P?@_gR70*!+}#pTMxxjfgKGWzXLeu8HXqJ4IUd9$+SPALYiYeaF$aGCaDwXC>mJ zC@Kt%cuM8Job|8BD_$P`%8A| z0o;StJpY~CZny|7^S{-#!ATXFJ{f>Ec+?eww_bM>xtERQ-4QZJUMNwn9Qm~n^#CIT zJHE*96e?G1^R@4U0cfY@l!Dm_DAK+I+E) z%@Jt4=`rUU`WpQQn)ZCLChjI{4WqxyF|&QJjIQP`^xGNW(~wSY7S0C zY;D&X%q#BM#R8(8!hGiW{;FN}lgly+(HN?~EbO&9AB8c_^QFdKhF4J(;ILS;uR*RA z!(K#z1`GlakGhx%5lKE+`uUMNJvw*kzE<6sm(~2z zQu+KnKf`pAsr+fMS{_IflYamd7vApT4I2qb^7PCMu_iAjyeix$Vr zCvJ+Dr`iV1)ts5T(t55*Uz}KC)fcC$ZS+No3)o)!&(0@ks_pa8JMMLa`e)Au`~QSF zc627BW2LwD%Z;i_c9gogSa@k-CuvHHo#RYJ|F`l*zOLBG@F}w9OVcwI$8!_G$|QS> zN7=HaPR+F*Q&zccdoKgKS92bzuWtxzS>?b3HagAYuWRa4M=XQv9TvwcCJv@WfAJ>j!=C6v zDwZ_MMi`o||Co0d1h@g7LL3h4zr%CwR7U5= z?q_*tsQ2->`|)E-B^4**jhp5n|E}c|E6~=q&(E*Xyet)?&4KzV3*B)aw~J^a`DgjI zqOVii_VxI9nNfXSQMOTOKZ%qry4MBtb@#{g^`m{k+Z?a5zHau`{B-V^g)HCtJ?%(=7_&oOh|MPbtqM9Bi4n}jn5!#M% z^FMtTkM>O{a6SUTYW6Ph@JruArSp_!H`toxvULsObu<3nsU65s z5+vjJdl!j?@-gC19(NC1id~cUh4Fn%x(Q^RX?|&6REU*x$`Z7K(wbWWvL%=v2n_HB zOX=6CXJZT|UMn*~=Z6@>;ZSEY_~E_%9?^Z?mLuCc%ADwb-b2^tkW!|4@}0(?cKJ^z zK+sy|D2j_^nEe~52`7y{4q9GT^r2->HHtpeP80WKSm0@}c58|C_{DWY-yAd0_Jc1p z64IH-L%nBolk&R2C4l!JSPXTLQW6c!=Mv-OFC@Z@LlRZSapXYy>FC@O#R-WI`d&T0 ziEZkcKa9Nt>B3g;zz_E@>+&>ifm5@QM->bs-BmhlBG%mVdT+bfkdgB9Zl7K?_~fK` zhjNwORo0NxlqgwI*A8ruY-Xja%(@{Pqe$n>zFXeY!}%?f#$?qEd3%DF;pTBLd~xRP zOMhNVX>FStSLz4FB8s4M^T#`Ys~TMTzSy&(2b3wKK17c0s#kl(i*9J>WSRS zsqXGX2W=c6XXdL(??5|Mwk)H3JNZ81{V0ER98b?Xf}Rmud**Ei{|INEpN!VIiulwp zLG+#NFyCzHhBonsd6%D>69__CAMy95zJzbMhqo#B5+5OF_<3ZOH>fRBO1TE;CvDq) z@=B1YX3QMntdA%Z+s)zDxksy*fVIrQPTfGqCO`i&YrB)R?cX@~&++BkPHPp7u^m+7 z^QgdC4OY6WMo5dM`8GKmypNoh3F%4HPWn@GX5P6d=`)BMiwT@{MK=oRQ(PT%KN`Ok z@$xv6ZwPJz3%m*6{4>9|^(j&N%rzl;Oav3{8|Cm>$vaMPFcG@KZFMR?iosIJ4xnd0 z2|xah(QEq914A6>SjnMB%~JNP9L_h(KeOy%?+5E&r1gHQZSOZ~VQGt93h75cFL#rk z>#&r$$+>nzgYEkA)T<_af!fi?x8v|1w}bb0*!H=9_tt%G^7X;B>F+jj`XBjA_~!@} zJp32x-AorLrZ^rzwr8tN8Pm~5My@g~RWG}`VifT197FGm?)#&Wc!&jSLcuJ{f~D)c ziK$xfs}~aKc2LB|uQkt{k?)Lta}|RFUm^N}e8(=$Jbl606+|vzqA#fH@aow+{^Ft2 zkSWxl9|SMCP6fqBpWW_T1pYmVN-0~6bS1ctz~ro28&FF+HR*o`SOk7TsH%+DZW!sf!fv1XbX++ilLA9!q(x@ zY{H@zA0ZyqWM8zdN5RJ^`8jBnWqh2w+NFjw`8s_yh`uP>Wu(jZPl*yN?v6|?0Cls= zp@<3xZ5Wf|Ye`D04pxPXOr#Rq>|J?5mz;IAJ{GTRcS>@os*-`GphDpyvMX%uTYXyY?>HqPJeUsy01 zENP4sV8-z?w@$kl2ZrG)9(0vAJ724~hK$0q2*>=JcsaH_czws-SE94q9mNc#Vl%0e zy#-nKujO-o5CmzC>_#E-Z*Mib7zdBTW!kgLOjho>TJ4iFe2-&9{-?)Ste$Y zvY%bn?%4Y(*g({f7P%^Rr31nn6+^OQW7C{*yAb~2Ba6Phb;-pzVigrkk+O>=*`H_} zyw`uq!afjZUvjKj*DB{W{->X$_j1ZyCt5u`V3*Xa`#1Bs?k6GSCg`bU!Ox1vEvJA` zf4sX}35wuZSr;YMV=s;$r3l`hc@DeR{ubg$Z&x)oIaOEIaBDOdyyK>a%qjD}q-sU- zU|rdz**LWOYaGh@MN)OFEwuJzf;`x3v?92#i5B4++E9Oznxi>IY8>hgH&x){P2zkS zd(MJAZv~EEy!5XqB*yu&XnD(9h~oi@Zk&7;zxc%#8=)(zaNcefk8D29VB^`grj2?0 zJGLG3+E!z}EXHv)zfN^u$*)s|w|bmDn7DD$oAU7^o*h2so&9f?JmWay=(o47xELeM z!&_B-Dm&}`t$c&8d3YN>KlobX?tYSsmf@Wc+uZo;Ua-TMhxe2j?oGE^FiFhATeY(N z-HK&dvTrQI`|Ul4ckF#Vy2aHzyzA2QKf8L-CudFxh7#k=>E7?AW^@w@%Y#{Z9F3!} zQ(Lp{-^(|2`3N(OCV=7dujVy2_LJPUjBS_6n**3O6@Y$v?8qn{#RYF)=OJ69`Cd{r zqcK8P*6f8tRF-iOmEQgYZ?LSTIDre^`?QB-5rE4h6L^<$5*E8g%4e`}y<2=bzf)HR zGB_JT$D;d4>3vRb^*#@>_sR3Z{1@`9u+_V@%Ck-XtvvhW+b3!r<~KI=lUz=OxEe~+ zy2A_I_FcX1lQTO4uc9kvYtB=>?`hs?lJAK|oGp-E#l+R8vR-?b&vilaV44F_rhMVD zpz&Hi$uD)dN&;Qwnc4Rm|Gm$DGdW!5kkH%t^SP#54_%CdVld-9A+3yWs+;#+edv?( zy5*febx@#f{H>qlej=pR)9f8S6Y}viDox-_~NG5zVP%O&yYnDHV4xgq>=UXF{ zo_@a4U$#(#j0ASC87}gj54F(>_cJIAL*g@gvQJR;POQoOQk!qtxf+M( zQe77&swQ@{cRl@WCHOExAgT_KsLFZjq9CWyFGBLv7!p+-NmOM|?i`o>nxw$c?MsNN z2qvmN+9P(%e5YByC#Dm+U@Fqh@PMzT8n3qZ%_*6HStLF#&SrA%d+h!_IoBkqPCGt+0*1Vc7lypf4nuwjhWts$ zxLsFi$ls+QKL|s9JPth^gM{GY&mbZAxp$C3TrsZ$;F2ieC|PvGW*!VQmYvuRIOa%A zGNfH&1*XIfWF3#3*VrH5{27+cQn!p|$EgVXVj!Nm^&HvNYL1ZcYv%hWyPuCCaJ~(j z{A*4+`Q_Rt2hD64WvmW&<|@>3A=Y^CgE9Twyxn2?d~G8gzdKQV|2-tNzWwX_{!s-P zHG<`oSAXZ2eZaFP)y0&W@`g_ENttn}cVHioCMiy*@ z-2JXVzpy~?b~kU#l#QHr;(6YTjLa=*UEhA_d|Z z4lumW86w#jjMOPcbI~N(zu@>_%?Tpf$xkpm*azc%^l#-)0|B~@<#z9el9tE2k2hJq zubAu+^jmMYk=KteFfB>-lH*Frs_Ub{AHG28e@Gcak;iPnY?G<^M4LH%|6#BT?w6Y9@pR6^yo#Aqwbqp!y}fW&BO3#PxT#S=g(cd z4fcyTD?WtZT*uAj;a*AFs2`db+4J|w{ZB0aUK2dt5bOSR-H4mdc^d3~1;+35pu~9R zg6b>gEx7!gvgD(gZIt5QSB>~ogoCRw{UEw*V|yx?|20x{o_+k0zrJUz9llKe6s#{k zIAz>|gUS7R*(Y!;z+HP(1KcuAg*i+Av6nP4Ur!6iV@ldNk_WK=nQsffHgy}S;FaW|DOEJuMOH?6Qg zHg2*%o{elR$64^mi$?5xy#flRb?2|WI8lDkctXYexsrATnavi@S=OCb(MRUatLdZf&THsn;La@;6?z?a$VhHZ zcg=0r+okv3x@06OF=|f*ezZ2tT91d!&5K^aNAGP*8t}1cPX+dj)>ih@9qgyumuyEP zw~uYHzwL+!y%c@zbowkyu9arnReOpn=d7B$cCnAA*~hc& z<2j2M(a%j7Y0d4f`Py3t-~9sn&YgbcpYD2*n@D)w%BMbk_sd-6NbaQWfjjPcJbK4~ zo$b{{Ye#T(BS&vJIstaoWNu4X5w2$2(X;4j`)#xEN@{wKo^4SBXV>9x?Q!(C_qYsw zKfaH?ACK>KyPrAc1P*z2-F`w1z}gd=IId>%Z70^zLmx*^+iqi@m7{APv4I`8Kf?9V z??1C2`);#8x!Rv|8KAvC=Pdg1QLc~Y>S{-8qkA8vAL{Dywe~Tt20!*b#?|4Y_HnE_ zT#Ycg_i>w2`{>#yY|6b)*w33s*Y2>tY#iOYgBAG;_WLgg=4y9ZOYmm6tmNoSji4iw-A3PjLgI z$};1tH@>%a?U>%DxVlf2S>vnsePzz{U)vSfH@f%NT+KlT1FWswTUEP@v(N*3*+=bf ztR)$X6UHu%%#YMZ=0&cFtdIvP=5buloljdwjM3H~%vror^V!=MMixDS2DeXthHCCUwM$=$UaK17jZMZ}^3 zyCl;R;bv~*Pkn4n-MUu}e^srC_sw6vdySn7dvRv=QEc^xWfpoJ3sTK2nGkfa-Ywj zVwEGUy6((6_e)R2!pH%#A;L|zzif0|?Fw!VP)8{g9pi|2E2=YML z+t!0fG=k&S&ThJ8TV#>WVKk2IeUqhHID4Q123_mkvR)Xgt;eh2W@olX7TpNG_P#~^ zt7h+n+PAGGSYEh2NIMtfp==z60B4OFM+3k*ls!#hA4jl{>FhVj{wRCLnq_}k_szKs zxO(9@4l``o->k*swDl2OU|V8coOurIEaU2Sjq4v*`wy-LeS3aI?daZrpx>h!<7)rO z4PXZ78zbEIPd0M*iQ6E_x**ap=2?G@x$8CI?Tfo1; zKW1$mrcD2N7s$3tEjEx2QVvq zvbugucSY^kx-q-Q)s5X;A&g}|BVwUzdF<&_ z_H-&g5TUhu;F$S*O@wQzsn}J$t-5#q+9eo9O~mhokt541B5y^;M>a-U%fAqLJhHTW z;o^Y`sQeCnmiwLcp7lQWDEF#$9uCmYTzg%Gwtf`NY;|Ja2^rj*K*^cu>|+M|h?ZNZ zM@A^O`|k4FPFqXwcKodJ+Q`BsoM6GP#>M3;mJC#2Sub0%_SFgvvW7LVG&8H*!py;+ zP^V^&E4M)S@c4k3IiY;f;iI{_%vICt*De`}Ic0qB&C{21^&H17TuSeoTd|bxP>kFV z*~GqBk*!O)1|;l<+_iHl*B{}u)=0MyIiY+-B)xSHe&o6FCzRKfk2;f^4+7KK$HFr? zRFqr6J~o}n(J0!=e%pB_-WJ9b`xteWUGVg?Y;YlaTEU(+v5&3nV<-FAbCzxXKI&{c z!*uqs@NBN0=d>5fuY9$w(^I|SDek}ioaX0PT*7+=bW^5!P-3&xRXihSi6{i z$$Do34SdLE<+cRaUs2n%))r^9^63o&6(`depJ)%5jFj0>&OsW^owD&Kl8$qplHB0KGbj}^t0Ftk zv-xbjKauXjjk;uQ>)JnXk8vMZWs|srFu^`)jhe(^LADN^#AWKs>ONV$eb1QQ3H{Y0 z$1R_*WOh3fi=P1A2jW(-7a;;u=%rg!q0PjEGfdnQqq zZY111sc&L`b#EtMH|n6w(Ytm{+Ey`g;@+z6Nww1|r)kp~rj497e_Cx9-voYV{xWgz zm>m;($Bi5}e?r~pfiZm(>PL?pEsO?%E`9)2-CbR~%BgejDt=&GS>}_~d#l?g^`l{R zlPKG^38?xZllC5Sk(=%!-U2skSMviHqfMjtRqq%B;SP@+33nq$*LL%nu?N>3T3zd_ z-R?h-kP{^Ql_Hjq>1w<5=RB_l#*@+Pa8(velg#N zcfEYlzKOM$*cI=+gm1z$Jbsckw)Rqcj_x1bdnunms$CaPs{JCRuNj!s`$d|fo4QAj zoVIUL?UyjmpwU|!Z5gTTyYEcW$`65HG^=S=-R#VV<%@V^ubfstt+sD1NmL{MRX)Al zUcJ}tu@0R^E2LF3J9F@eMRP!X*Vx*htzFX3aW(fvdLuVSGLfxL;x{a58k4-nj#zXf zmI%DdM{SDS^b2k2)>;f|G{a6DL6a$jXKDl2%RXwKU{6o*7RGYz4qAG+-W_}mlGOf! z-XPce3t}>aX0{saA`xGnT*DU3)iGN(} zE>_+y-ijR5G%y|#@^9=#t^Ky&*feUNwpXIwr&;D_h{as*GnA{Q{pe@yMX~+1XX!oF z^i|aU*7?%=TRX+TxZ3BaoSK1gz0cV{^;gyY&aPuG`>5@=>(SfK=s(X7V2fAwzI9y{ zhyAB@Qx#dWt-E?_70nFRJyqOY_;|32OXK5bRos2}*jdF1ecV-7j{Exf@!#0X|8?zO z*FIgv&1>Q|edEwW-&y+(AE{g4)K^wNr;-!UDGqMoCamK>Mc61{H9}04PSK8B-gEMO^BQ{EdgeWN zYWKTe>Y2ZO{ucQwJqvG~zx~}!J*WL-e!u*+o<-{x?CZL=r~bwTl|Qc zyVqa(?X&wwT(bU451zg6{!7{W|`iXKR(##`Qh?_Zk{1xv#F@z(3N^ zUD@=t^&9y;4O=ROYu9h$Z#`#w<@oQczk>hCIsKJQ-(7zt|EF{IRrY;v{bv4(b1NtJ z-M0QJ{+@HS$<`g~ujZdWw_$STuJzaOo6hT=T=SFlTljB$e#>OxrS;eGub;nt^0wXU zujjw{h5pGk|5|?o|7_E~$?an|WcYjZ$|;+xHr&L2q-#^Q9kbzPeuL34rG55>Tlha1 z-BbEb+|bKko7ys^e&L3#{KKj3Q))iH;ST=sbpMph6&vp2pK9JWrS66e+xY8OR8DQ* zy5S!Fl?$|~eLvlBFaPb9hN*QsH{8c>Z|R;|w`aq4zOQx5)PeUmJjnmJZTr;re{Xn* zf26&C>b5DDKg@rtW8c&P?eac;cW33an$s@-8GrpMZJN+{`J?L?-%_=AdZqOO|L{6~ zd)2O)mDY>=o^^bGRc2wO^)mm99)4fdw$m%E0sijwd}Vd}d6m|y{Eqd!R?VGXX}!kx zujd=8$A6*H`V;@odcM1wTV84H=C9nqZ>jEUuC(^>|GRug+3suk{#vdVM(kx%Ga=)n&i`9^Y{Ez=xBqYs%JU`0k_YJ~74GQg%y*-*R-_AycgD%AU{g+mEgp zH^sWXZ2gUV|Izi6r&u?X-G3v$@96PWQ>;wcH^0wUPS0FA#k#5NPq*^g^tvxkv2HH= zS})%)y=l`F>lQe)R@0)J@a*DOB?3Z`&mB;LQa*B0N+1@*N?UW+cs?}F^$2PulM&BV*t)G>Bu#MMd3{0MCJzDng5BY`}165P4$IJHqknf(+ci2>G zN7=@E_$@Pb&6sNKEPMVQe*292=v3=hW&gZ~@1MaPKh=7w>}&V(`)1UfI~DE~ANUbp zIkV~fsn*kFTkq$!nRS;=wVo~e{r!By%%-nQwVo?`VmseGv*yaFI6eFB1N@em+;^s0 zFO#`Tm&$w@~M1D0}b6d}UPFG1Ypt>{}1< zT6FVEQ?1v^{_zvOAzD9sn)Ro$fBl^Aj&kQsvv!yL>v4WdblY{)tUYDF{RO{0TJybW z)|+LUf5rDlckP^Jy;b((U-A2*b-$iw?Jc|dNxt&f%^ys&-YHwRi`S0b`-v*+-LlJ` z<{OS}YOJ#UQFhaFeD|??S5zVD$p_EzTaLB5tE~6Se)Kzj`>~t9SY`dI?3?|3|FOHi zQe}Nu_KSXg-?24Ysw^vV!}ENlR{xzUYhC22=Xp)rd_$Gh6S@2azCqh|M-{ACUweV? z*6QxAvNlF;{XM@$+x6orYg45E_xyIP@8K%zipalz&-ZKAjw#E30FY;QV{nu62)se5i#5W|iy-;Oc6S@B-zB^I#QkAtO^43fImc+pB zD(kw)buaVV6ZLOYS=UE?`!e63sDHc4x*>AyANYNVT_03gnaE3j;45d+)f@TxtNfN(!i;KbYvh?%`R%iWXti}m zWF(Za=Zwx+n6T*LZDq=8S6V-pCJM=No1Z zoL_C-7g_fwzI%4frPbE<$bGx{EwlH2uiAPr^1>dh+8p=QP0z>856A8LgK3_bX{pguc+E9U*S`4MF3yB{=8MoR9~!xO_m7blk`~u{DQE9ePs4X2fE}^@AASA_z-}`B z#(#ZCN4BNUJLyUGrT^UD={u#T|Ne?J-@>Pb=d1Dg5&k1-Yr_{g?%Q}K9r-mLyy{B~ z-x|R01-=C7>LMJs*pq(5mpOY!eiiUjJ@^?8{(J!cwu9GT&*n}42jFKQ|1#i1YE`Qd%zVJ z2Y>DWegdAO2eY$gmv4I<{DJ^pyN;#r4d7`9e?5TT?BGX?@Y8=4cogL}0;kvQmOK73 zjyoF9R{+O$I*TV9{N4bb1b!6Ky$JkBPx{LpoU|KW{0`uaNOvUgFSzN!&qI1RE{W%L zz;zG461a)yKLSsA@TY;-;`vnAm3_v=!O!;{yfuIyv7X&={uXc)mu=S)2Y)Pp_W&om z)4v1%yqg{wUja__{~S~R-ul;VV0P_y0~bB%JAe~^2Y}CTan$pBz(0-W(HNUYdGN;^ zTnylEIQUrs{F9e6I+q0SIB?=m2Dq0$jlhov{seIP-F@#Hfm1(x8#viKxc&BV;4wVU zz&s*(@b{ebUjXh+AK%F6d?$df0)7he_X9uKL+3#UpEkyie*}CU(lr66d~SVC`3j@| z1K{3rF9S~LUk#-H1@KdWe+DXa`rV~7eiOr22Jo|i&quod1y1?g^xt#v_XGH!fqxe1 zC@}p(PkQOA4F75X|DuEcHh}K{J{$QD8_(Icb#A$lD_DO$2l%lb`Y{LJ=*7{m3|O6n_sq;lY39;1xK@@!|)6ouxlL zfY&+rh5&vsaC%=q1y1F-<^Blxad>_YIQ{Ov$G-yqG@j)O|9GFYnc?RI@Z%l)O99+) z@b3rkuK@oH=Uje)x&p!ozh6jHU_~-CE7K#x1-K9VCYPPO_0XY5c;$L>~ zy94-dfYUrc0#kM#03W7(i{T3c_%h&iNPabN;*(4NR^W5+{0wmV-NknUKMBwOGlltA zaq(lWVfdK=ycIajo8JbWoo`W}{{>F#+3$g$=b=CD+iYD^r+U^kq;Cbj80oGC?&U+D zgTEfY58cA#A9b2X{sEn34!$XXKLq?N(0>{DnV$L_dMz8zu`18}AfOKdpNn+MffJu> zJ^-k%zL17JaCdf&H>)!Nq+{z!1n>C{_gT$zJZl@(h->BTpVAT9ei~FzX3Sa|90Tn`h)(nz~jINfYa|T{X@RT z@QI)D;GjR(!A}d|Yk<@HSO=WwxpaQ$;12}wzW|?wbbEo*`*hQPD#P%jkM!f`17C)8 zN#JQu`bUA!#`6x~M9-#!dVU0)`cK(W{{AD~$m%Bp&$gHN27D3HuK@0y$Le|2cpkdoxS_nOcAPb_ZV;z<&sw>U}HllRfnR0i5{! z25>K*#UC*IsH6ROi-R`?@LL`H+5rBlgFh3%t8QWZ88h9_pR|LY8Nly$@b3ojeGdM5 z0H1R!o2OkoXN zgFhd@wXH0DWz?U(+riHc;M;){AFcsT<+$a(=itu;@L9LB^b?Qur@sXFNyvW|@VOp3 z4?Fml0M6gR`t1wAv;7wBng^WtRgLe*xpeS;F9S~F|6JhS`S1Y;|9Sv_8#v7aj{>jv z(5btV;T57E|AvF70{E*Aes2Je-Non}gvHKFzsJFs2JqiH_{{tAU^GX;;lQhQHy(1&-?mZXz9dluWtlfxiTt_3IGw@S{EWi2r5!g~x$o$Y;~X9Q>~Vyb<_9 zq??AyEO67Kpxc0>c+LcluA6P|^T6Bid^PY^4?h21HeSlG*w(o?2z&*249|0cQ~TWd zKjh$D0sL*?^N{Wq;HS9hW$@rfY@K=oIQ{PO|5D)d@hoDoKGlOi3OtSHZs61}-1O7$ zWB5w}e6xek#UkQO{}13q|5o5$`X}7a`1TfXFW)u-|18qS(bYk{ASPq*CDA7J=D0{HC? zz66tyH~l9bWa+mB@MXYhJd8nQXdZRx-v*q<%Oc?3@$x2cqPrRR=iT(^4-0%dnc-KD@=-1NW~_hGMt=iR`Uxj5)Q=-_8yaq;3uJi>7oAl-eySGegx=W7mLgTdv+ z_W`H!HUX!6?)y#sjNyL|;JbiRx+V-pFP+&xXZ6?#oW`F^=O*A(e*uFiTTj$y)T3-Z z`8IIxe6q&D%Q5)8_-+U94B%%!#^}5fz#n(;GcZWKbd<+g`kw^wn}N5Zp2uMD(mdzZ zzv2moUl+i89Q+d)^xpLEI(T;gPwilI{v5!cb?~z=Ie6)u{0o-;u>gLrgUgsyyy=hJ z$?_U`_JyXVI@%f7k(>es}x%1HfDG zEY@~0`GLwqd!~=oSw&jj^jF99Q}OsQ?O6L^E%-4eq8!r1WxJR0ZzZW z_}dO{EcWC2ui5_PS>Ts=(!T_JHJ;B{0-w(=j`}R!#qh@h_%DHf3F&4pg-q^Azu-3< zndfucfv@r4KX-8POh117(=0u#NPX$=2fh~hKXn$)(mZsuXBhtd0R8~*b(H>W_Pfi6 z+0U|i-V8ijPw?{r;9o}i!yDM|c6u4|$8Q<_y#RhcaQw_wo#U5(-f-~x0DjnWY`we; zIHrQ^I7$OI@%#(mDG&Zj2cLPa9~XYd6{Ln=A&zXd+FQ{98)Cs z5pXKst#{OLacUWfcA06)<~XZ8TY zzZk$Taqx!%_>X~q0r@`wj#r$m|KwMgeAa-@Q0KwVb?_|#{5!xKk**&&(R2CmKJdAC zRxw!Tc<|$1W%Ax?;Pktj{>#8A-2=euJa`}Qqw)M6@LCr~fBuVuACAuE#Si@>u{vL2F zz1&ggw01v51875b>YrFUJAixn(*rz;^mhTD>7jEE@MG}&d*IVu9OLUH;3A&OF*rar z`yR*sna%GCaLI$u0Z!?c1=4o_r+Mt#z`gU>R^YT=JOw=Fq4P5E*?8tJ@Xy1Oce8Y} zfqTn64frgiUkN)C4j2C|aH9Wqfc}U*jDF2ZKm9u3w4OBpr}yU4X#;*L zo;LuW=fUp-z5vg^0zTh^e+0Z9&lRoy{o@&Lu>NBJKi!l5yTFNW+kkud_6%@(Pp<>_ z@*mdAHvcEJ`T1W5ocL7_-22|Ufz!CV9C&uzfr0k}r+)Sr@MH1mw)f8top%Ft4*P%X zJss2T@1OO+sUMsN-21-10-W0OP2k@5^)PVi4^II1_J4mo#f8xNs{7E}_ zO8~zfIPvX9;9kD{8n_7j8Q=mw-S%>CGyP1Y!=s-;g=YXi3F)H1v-1Y%qSdd?uc+1CC@i--ymG z;1lrtIPeM=M}pUZPr>sGz$bg~kAPEoe*;dx6aT5)DetiSV^-k|)x~A-1UT`z2Dr;- zDt86&CgA4*r**)l1AM2G{=q={ga5|T|2>dC4ctKfr5EM&14RE9z>~o51Fn1MAM-B5 zC$0A5UjuF;T{rNQC;dCXiH|P=ALHW0z`rv-{{^_0&*Om8d-*4D?|V50IKB5nyL0cI z>e&Na1ik{efKQhXKLS1)&({Gz#KlqWBfzOWKLFn3;-GWHKUlvkUy~azME^|SRF63D z?EAtCX$Ma8;OBt5>n5eY4|oOeYk+&-<4)ij@Y{gL@#)sH?4OJ;1Hh@iErZwIdm;3M8=ESNONB?jK zuMFVFICxC}R~)=HfS>5#LI7Xj;J6CvD|d;5*9GwN9ejQOU*_Prx9g*Gp@TOB@Jk%L zDS)qc@Z|yg>ki%?z^`@i?f?!JbLV5iBYit;zm2!ixe!sg%@Bo{^C@?BbwmaBAUU8U zJI{*qsXCu=`%`AgWsyBe>?5YPwzWp(L`={UshAowVhKT$by3w)sZ`9AB{7~zs7_Hb zqb#eXWpYZ=N=wZuBuWWZ>zHs+m!51fql}6eb3Y|&x|2BOG(F}tJ?1ny#+od~G>4c& zRCb9v`DD>4#K|u^bY=H<7grENS`-qE6v5gi8I4|K8qw%krjZS5edH=hI8yIqAN0DM zG)vk|N=oOUv#PcE!d0l-nf7Onh*LW`jVu(yTNQOxK}Rv=v>?Y*gVbs;YD210fu;p& zC94TTkj0p)DW;f=#i&-X&aRXw8f`5trqR{h*4imA*E^RZUU|DD&&RjZbvr=$XYq2* z!oMZ-4%Ft>PA~}Vj2j6dDT~RtuB2o&owj3@OLm7~uQb$>^hz-HWHY&HnH};Rk02u( zrWw}~rec_BEhQ)SlZ>tjLP}35>10w&>Pc;X$>^eB%AzbJS;xpv|qzh~5(W z8xc%^Aj3g1nMfpKvMNcEs0pTE+RbDXS9LaDYY&-%#q>@!ZPN_yZmKLOxqNIc&W>%AisECHBC6aM5 zKf`3=7Z@bQV^Z8mY8WC(F=pi27&BJ3$Ij?TVG8L+I+^~%`W43TIUS zN4;L}=xWwmPPx!uhAPt#lFSQHfS||X2~E;d>6CyWkn8E50@zS5P{5$AkXmTA)l4a# zN@3hXq7j2EQo(8rAtY1NVmz)SB{iib;^>XOH>a*_Ze__J2#E#CLcUnhQa*BM%avM-b|J4R*EC>J%wkcC9dkkV;6*W>ATn>Jg^0=yoKwmtb$XJOP; zRZB>5DW<5gw33Q>h6sL7xQyvk!I#F1L{tYNgP}v{lwyz@5~^pctTb1OLaS+}IvZ0R zZPXLd&0{(iIu#-yIy+ldY_=n<+__q(L?YHfA(>DlS&?Ik;;Dfrk)jAvQk8W{(`7X& zdHS>`k)aC-HJ(h$=$C3L#b)(jai*vzVNwX2cU_GNq={rM5|F?rdytTWxkUwxt`p zR=0r?#C=HYNqk62SyD>nu|iT-x}|M3q%4QevL=e?w?;xTjd)ti$vbwZ8ESjD`q%gWfMV7Rr<`FTdG6`D6@`&aTOj3eq8iFZGSiJq*A0!ht z0ZBP2q!MXSiN)fcmA*hpaRa*~td5$J!rM-iR+28s*i$9qlA;SnT=6X8C`l4*-9{s+ z2^u@})s5{C32Dw!4Txe`JRzDHaY68m0?HN3!wF}*l}MV{6k&s-q_m`*@W1{-84WBG zVq8q?5FZSD^RcmDMr=iD}taqRNz2q7qPjg+(tBV_Hw6cVVCkdfY#O4Ms*b^iF!!B9_{?sA4c+ z8zjg5Gss|>6?0{Km%V4f+fhsj8$U(Tz?70&pz2uOFyBA`H?YQH(=MvAAj=6qo8st; zlr9z!1&^Fte zf70I>OKxu*!WU_-K@ih`Zt4Q06irG%-RfhY=IVh(6+0uJiaR_+p_+yQ2couwK@v0l zbNG-b#j$5dV$&gF`=hBTe-9}@$! zzXkni+AlRgQ`p+c=AM8&OmmO@qi6OB?j00ePbwlrNew~N*5f?3yGM>%XFj(CK~*g1NauG_gIz zvYRBa5^DJUuVjv9N|zNQnHFW}jFL)Vn=qvJBDmI7Hu zl=WDy+1b2_RXC(kWv0EsQg1-piKWoQvhPtA*~trOjp?u~8l|@6)9KpT!4El+#=Na0 z6cMT(UCoJ(b^?{LBEgO?R;iepp$CQ>1Bor3fXoJ+ezt?j%W>i%iK|*6x*E&rEZFzz z42Vr4ULIbp7Bka1Nm-_I8^u1h5ru#RLrjfE*}+a%hu++U(;|A(yV`Knv%vZ0Yaq*F zpDQ^>L5t}`h+gL$l7Z-7thEb5EGZ#lDR3B5WL#BZxhej?P$jt)2gj&W9Gwc<0vV?r z7#+HYz0_`%F+p>Apt&rFcjCN@slC%Cq zvw$(h)`F+-_ULdbg`-$ArQ~`9GbT`5^fhhR`Us@rYSderm(dxCqGQjiLy;@R1#GW# zFSk%8Xu-6!A!#@pPeG}cYpO4kdKxQGYS&YZ&DUd8U#K;mJwQxC z7fZ+DCXS|(rkPte6r%;&WoISGf5JxzqS2G+!#7oC&kz|6vndNc`& ztpgEbG~Z-xOEhdx8IE}i<1h}508X@1X~naZbaLAECqBgz4pZe=0?OwUv>VV95%EiW=q^38o=9KT&gvVpfjCECjO0Vn?o0lCa-drKFgRj({pVyJa+2PspMH z0b5PtTvzgFcuONj$1}b$EGI?0CJCAf8j!MQ4BJgARyoDqp|MGV42`IU0`}(6qd?$* z*qQK*@KPwoT1=XqvDZV_mSa%-K{{lXNcM?SNzJsE4Nys?(C<A}$N-56>E2S#A zO^L2S1BopOj4*KU?m0YTwTb6FM7G!S=GK(ijb)!cPKRE@UAcUnI`GC5b|$Cuz?e=+ z#c@KPM$tI1$aXokt(`RRqH>1)neE}C&~`y%TSueW(n)V4j^3@x=;uOGQ6-NwR$_i^ z;GzD((2|W<(hzcMYl-=x$Hhb$e>Ecw!A3!vpMNJ2M77sB*Mf3D^ck= zF>I0&bbTU@PZFk9oa5Ot)2arc5C_8Gn1plM(#uTa3`b6CstEfNDA#hr5Y~^*RWNi& zEVe&cFFWbTQ*6~-nA4&R{Ra-*u|Gt|aqN{yyd5GPGy`T{*hLt!f}@O_9$|=dlF)RM zGDXE)DH$HYa)@*cLley zV*=wJr-Kr->bd2nQ0<}CrS6ZC>5x-OW7`Qq7YF}238+x^IE)n=%?^?jMM+Jlk^!SQ z9baWn=PyumPkszJ1)C=gMjNnF5K3#gCqI<`5b8Ay2N~9CYHs!}vHt0VNyl;uwBXQ; zc~qp>|94;`&|xf(b!)2J*-27SO!ydRI3}vwQ^{8S7&5X@*quJg} znKdXEB?AgP%)qcc$#E`U<`|VsJ8d_&kra_t$8m;?Da#|}=gTcqZrD?q7rNQ8<(6H|e#v}|lSeWMq>Y({u&a?8N zx6mLn!14o92M$IHR^Kka6Z?8ITRs&0Fb7D=DNR)p*pwE`AE)}S#3}wtz4HS1^{MG( zI)!}~4sNjU%ee(VUkhvsXu-v>-O1J=O_CutWuRiJFyk#)hXmDO6~vQtGfZr=G!!EN zYfDv0rIZBTXm0HKYoWn(NNa}aImy+{S~t#`u*1Ze5we(Z0|yjwkF97fFE(i_Q%W;< zF1fmEY)P~jwigPllMK&ccPJB;;$#vPLrg#=W=gPgc8nAp3pSr|F;lRFOwsKFCR)i{ zOLGBz7iPeuy-K44+MV~~(1Yj#`zgf`v?R_G6ZQoDap=W_IF1r!8D?Y9v@jF9k3&xt zVegNl0vy$(p{2BE*pEd|gXkY8DLJmgz|ijfABUbsmV3GqPeAQ~y@fp+lt6DmYgZdd zDreHWwcjt)d~}E;lI@_GO2gU|rW-MPv-5H2!3rg=tFRG+Ni@zS?XmiC=$RT6958uE zVAw&-VD)3C6ovZp(vCIroZA)ICTm?CYwUAKG&>IcCz z$vZ~!rCl_@F@<3yQ_w;ra2UdDN0?3k_aHhH)o)B&XhCk+?S~Wu#}}Si7N`ui?A0~6KpUHQogh6g-uXO)nW-9 zC-$(oWb@A;S#rBm7)nCIg5oKbg04nqqhyd=un5I%lZ$9)sHiXsj2p0!hb0GQltTQ8 z(<04w=1H9B3&;suCRxSM%w=Qj5!nT&Mp}|=<55*N4eVoLk|61@r}Xf_$)K3sP`*Rq z-MG@OHR^^{OHab8BWb{T8w!PBAx=)R)YM{7-r$T!F|h{N>oxn4{e`WyOB1%hGVDU3 zGJ_%vXH7wxV2ztpmn7I~V*!@Q%7z`AIaEth96;wwT?~StpyKERT`*>-38;=dW!i*r zWMN#OW|Irdpa+&qu<%FE4<^SE3(ad;RgqoaXtdCn3g{NRV+;0n*bT#G2HVUS4tH{; zscb$_*>o`2$yS1FLZLW|Cty5=i-UvZr=ALe#16=_bi)wZ?_?4~I+r6(_FKd=b_cI< z*($w*jET~Q4rvrZu#96zSW4x|p)A%{`=)`=Sf(o#CU!y^c7R&U+XJ)3CcH#WV#h8x zFhH+|wRKwuDR~7Pj^lQZf^{-3L4%#ADtW1}7Lj$aeW${JVYs4V{Kzn85H-(eEnFEd z83~j3s(A89`wx_bd-8Fg}Ti2K4!u zc~y4#z!`P!+bqhEqAkG)ghecbS&}3LvGkVE`j?yR1OY}UhL%QGkfCz-^wq))fuKqE z1TaFE;a(azi|cvlq_##27AbiO!fmE1RBxXV^Nwsg66en}k%);RNo&?TgBBecY-#bDb57QvDfMyMF* z$z&4eL#6Usb~r4>aQ_rHEd+Y?xOr7#;db_--APU8bc&HM4P3Cq?%}`^Pw6qu6lD{~ ze2|R}Y|U}1jti&Q)(SW=N-;Zv5=L8TY)L^wjHNMQnmC_OnWbe3#O>QQ_N*4SZ?eD) zTEa_LrBeCo5l50Tv>kLo1&7JFh-2?XRCZ&?S>~LNQ(M}SI=gJWssEEU~zD3Hu867TDn!%gZc$ zVDp6A&N-W>a5v6b0^#hITHxAoW6y~@o!GzY*i1MU=<0zeL52RSxsyz6G)0a>&@f=; z0nwJJjaA=nxnw2{_8zbk!kzOZ_7MGRiSW& zwj4$!8oO0+po&T5icz4M!)d*M^D4N4VAdR_ zLr>#Ac|u_3UrtG(p3AHQY4F&FlHqPK=*$C?J1Hf|xQ&^_y@r(imJV1cx!DKX3zasz zIQWCh1-3#9(*By5Rw_)61Yhz#q~7!=}= zlbK{ce5IvuPdg1(LTpOoa<{$F9=_5{ElvJ3;M53e9)+pqhp)6WF2cqQ+&F+OXhK%( zaXgHrVbfvaR(ldwOc>F&_;w&m3rtejH>PkA3kE>2_KUHr9>Z81jKJUy1)ea-z7W?A zNOT;|;-D+TnTDX?Tpd1y?6rRwi_^qdQh>7@6C0FRB4KMFhqJgiOx$38lEC3VZWs;ra@km%w$J%(hL#SX>Gh zz;N=esIZoUksDj#4&c%g80I*Gh~WyTf|JZRtdHys)iAb>&hv4l7oH`OurOyw3d2|& zwnFd;WtswPXJd-9j)l1px0F6y3!7)(Z(Uvrqn9P||0gV=^tO7S_sE0Z?QQ&t%!;R+z4hxbR zoaWdqWM^gtIg0BxskW6%$OTOJbuxa=UDe!@a#)TM;e&#JM*7iKqT$jk#6Dd5PDqIu zPOj{t*_PhZ)=rp9oA%ij_VV=oR66Hk1OKEW=h-7J^g;`alLU-RC0sawnH=tjF~>#P zu$Kx;NEo%?Yzdk}1*hB8)&v`!Y^c~Z_FiS0M@}L`4J%ct;TxwZ6UuwjfT5Lvi})#9 z7HtBujlxNsl;*K~>2~(1pU{)0Wk%Dn#9mlzaqQSicEIRFZBEjYfPmA59 zgw(tRRuUROIR$ay;RIzT`c)j~@VWu>Q(II`gvRg3=+hon=iAuJ@Lvb#4r$yB!*FJI z9sZN$uIH;)_P-Hg}zlFX7JaXMAazc`=PcI3Wqg zAaqfMxqnLJ7b1ccu)9HM#Q7^x`0c~uUceiGDJXPCs>!+?6D-&$XT;pgd6>}rm-C9T zpm6Cp0K{#DL{h}PLYQ8&zQ;-r@*eWj0`%(aoykFDC{|tfXryrIxQ3sG-3PA1D;f&7 zcTI_GxiAdK&f|(}si4AXADy@35_3#~j>GOOg|k31G~l8J2KPF7x3y1>a;22&HWt1h zP28%3vNDFvIXkQ!B9)@YrsSO|1qB$kbuxUJ*|Pe9E(0?wnu1G#xQZ1s1vc8U3?yzO zR_Yg+_L2+f3C3BNjj@BkqKmUpd#(3W3Dcpd%v}WscJ`$kyHDUY8r^10>YZeZfg3p> zqnhy;&MOT;NaBcusr8DGDd^+_$11uh*e>~CRU-vkk*`|L)p|JBA@_ph@D9F!n7vw& zn#k_Civ$Z7*m}e7m#X0Ah`;Z}@)eprQAt5#j|&30DS=f+V`mXXiY0>{+(-lWP*)sv zqhFx^LDsXkj3s1db^8A|fN>)X7R^v};v^j+DY%`dOtlj}vEf;?5xzoPS2%*I$6%H($uZdFIaizm zrNuD~`L}VRliq{5^RJ`Z3xE@&7{%>7~U zn#%Be*JyNgv}7IrYO%Ns2MQ7{-;gg3Hvi^EBXy}fb%j$V+q@7jiPEBn#NhT66C*s$ z!i_LSUiNh^a7;6@s6_v(WcsQV1dcD!%S~aW>#1uqJxDUxY9pq_t zkWkV3!YmM%LS=Ghhhor#K4=!QhzF-25MoY^p(^N&=g299&sqjhyeR`VRG$~rJOx+uq$t!&_1y>I6 z76eyXrLo$*SuE(ttHW6qF1cfeQX2bIwiKXjTpNJHVT?$adcY(pC{N{|U2~BF;7mO& zXgKYJKWDh2%O_-ndkNi|W3CaBa6W;v4!Es`u^OBsl=SYM>_s~kJoS;K6_nQGMuFYA zF8WU5xkVCv2|)+oX9w#fOz`uG6ydgc?8x9m6h`A%cHnLvw?~&!Qoz!EvBuHM(;jjeWKVV=9$HZ{? zok!S{M93oHEs-{Z~7JmEEa&n-Jb8dKEOvP~h0p51XQa+CuXWy_?PKB*VyC|&GyNu+ zuQuV+jfNQrp&Af1;UCAu4O9eGfy9`Z zMnYflR)$>e(p4B#3I=_6+3@g%3%0n>Ttdq*<5Tb)6E>*JSBF8?>TTZrR)NA8(B?o(4=mnUBoy{aE z;Y_&#<01yHfZ!sS-EdDbP*YJxP19|wI&w{eV-z??N#l|oHpyvr$m3z7=+BTVNX0R% zm^P6EZlIuf@v}sXdrHYROvMny_<<{5Y-(gjHpn$h4&})er_~s?hT^SP#ZsftG7W`d9o@cW|jxYJC zP&Wm|Mxx`yJj5b)v`#nDHI8VvdzGQoT8HjfH)_rsIAABHHLGbO-+TZa2%9QSV$s!Ofu8hbv9E z*T5D82l&BP7Y~+4*>Z(qdPw6&3-0}h6zRmi*pO>q0w@0X9}}@7`avv*N05XBpD4J5 z$4oBrC8zKxt8=BuxbzlB;58k6+rVLzziGKr$u*>H1h>DvjSDu1{bU5V0 zX<`f~@Fo-Hv+r6IPjBuvQ;dNM`OP979ya>$#)2JZoOF+&3E7)Rr992F)Ffaw1TQdY z2-AkCvbaq-zWWMdnMkfC&n2WCg8dde5=ghMFK86aac{t7&s{LQ;=-uowxu@u_0{56FibY9JS-YNLce*i`H7StHp#3Fm3GNn_k2$MxraW$bsZ4aZ3^!?Hby`0C5h>tBwnAIBsh1hxXZu<- z>gj9YgELQzB+UO#L?j*822D9B$Kmt|vY6dW=hD50?o#xRQ_$cNiQ)z__Rp9ru{lL> z09z@d`V4O{?4bIg(?0qPleK;Oxvu-@{M-icT11RenCL;QK=>)FG^ez*T(mN}3e$U( zv|v#;nn@IHLF}K*ZYbirqRk@A3vAzSiFUoU*|-43D)u)JCAk;^RSMfNcp*SU0y`(} z>|!qvZ5NugEHz+8`x=G?e;~o%|BKB*b9rMs+>W-jV&~Vj#;pahKQXVZ1KTp3I>H2j z;xF3Uh7P=PI#Wu(2pFCcF>2ul4_-E@H`xuyM#5r;=-GSR>^#+e%coIjnE7V6&Di{b zwqR+DaftI4-04VQ_3)7o*KAcg8sXFoLJ-btajk{I$Ei$hRcg)7Bszs_Mh+iw85|zZ z=u)dUuoc=yA!uS~vQi)nSaT=B!mKIK_84MhV)H~1NT9*=Mt5>bP}uQ!>8vH47)e#m zs6s4?n2eZBP)Xp9P9V;h9mQ<$0`hYxPyk%F7&06l(A>kB1^mgu$*w)7^-hRSCaUDS z?&Vkmvh%%YlsVo#rNb8r)XTg;tW*tt2@$X^hLr;QGUmd-t{Q1O$?sjvaVD77n_Fz1 z3xd2LdJmMZF=(uyNMn^FgFtd47H!8=va<7nWE8t<8ue`I#GE-8w*nQyfemhji6-1% zk_UY7s?nZ`>~=anHR!e2&(0N84bC%C5CvEo_x=(NMiI6dbGeGcWcW|;Q({yd=NL{I zj{l1+`RvVjI0Tqv`#oQ%>+_*_; zD+}Rg3x_AnQJ_D!D9%HJnv=~m_reiio+_w_6p1SyYTAGn1LnQqD)@-72+fXjJL~~* zSc9``9me>ne3~5uVsy(y-E#_Rgw=wCnnoZ~IUY+m8V#R<*{l3RENQ)~88McfpehJ| zO|uL3F$fL^QxVpGjIOSWvCyg1WvIIb)))lap*05Gh$&SB4O=w0*@9Q81UxU>D&TBB z&9+P=ciEyH8W;;Taw+L%vxQVXf@ml>;v|p7P~3VPFjJZN^X4o%5p)I1coNQBa5>T! z#uAx5OAqUi0QI%&Rrb3H3bER&yb#{wFG#(Xl(hxR1i1L_RKGRsX zDk?OB+yD0>Zd0ZH4~E>%U#h%K}bQ>h)0}*w5|LBCnZto|ZP~2^z!^8@o zFEM-72>TGi^6m8%6b`&iM{6VC?PvBUvQ)HW8&Me`wLS^X7u9#L~iV4=r~v{`OFEhXZgAC3iRi_t0_& zLvZKI4d%C#d#7*=ZZ|bWi!K<1JDhNkDBQk;gN5PtCmJLUw>MFtkShBbh&vDYygL$` z{C-8^&Qn5OFY4YBh8&99TS%c;-2QZf2jkABqm4=_(YT9b2#4eLX0UggYy**RJ8KI| z1-8oJc-$f41$N^0zJ%<@vpR^t9y1(}+e^N*h}_v6P|g$$$?Z)%cuekmslq|I^Q8($ z<<6HX9G2Ugs!&{RZ#o<{yYX+sfw{8@Nvk{L$lQbHCf6Xe0SJZW_GSr1rWT9E<}R4K zXmIX=xl4`CT@n#&;tGc6E`^A+8m`sbA=eBVpSuJq1p;*YatD-z+0Z9NBXpNWrD%xm zA(9y^Mt5msf}9Np=^iSb!J>4RMyI4O-6fK8wI;cK6OPlpAEX8g)SV>-ae0W5y0cly zLO&EEH5{tDNcvE$?!xKA!MY2l4@c`RoIV_`yGZ&_yzav3!vVVsrw>Q$_N5;r`Zhd- z1wwY0k}DjuyOdnvpxve93Pcy?JqSW02_Gc~gbLcjrxoy8{0B-T6|519*E=W$!74BY5Xe z77F2=H(5A_civ>-Al}|&gGJB|hX@Ww@h*jq8<#g6#=Df<1>$&@l0D~NJRHc|o4@4P z%f%yk?;qLFG8GQxyNba=RiBYN*Qsc=Z|5=l8GTj7}ACFXZ0k8n`$5((rcfN)gr zp_2%O^)8WwHxgwyuD6#6w4Vnwu=oDc#yBh<*?Ygq4;tG0<5CRA_TF!bxtSvz-1`6! z4M+FhZ=wamduOTQFk`SN2)M-@i0|#@vQ64z`xD?hOhK7%JDMRAyOJY(7pH;?rLdDC zolq#mcPMj_7~j71g*4K1QocVyzI_F#j2%UyeCM*j3#v4PFyGmXbVl@lB+mDLu}-dg zrEs8cU#0dh(zlPqeuVmV^D|?ZQe%CWk}DkSJ8!PiqkR|59*ne&Q5g>RU64Yl@xBWY z8EU}qLbMzSCLHm*luV(J--R*_9`n0UF7%kef_@jyHfYrElCp)veizDCDDHQ`d<6o3 z7s}_Ax5AOX{W*sc`a7G`HU}QI*x%V=Y~Nx-3jQ6)T1xcqK$cR&fBUl)3$g8wY8Hic$H}%6Yz=uR8w+jjf0rwO7&qe`v%N{I*bVf20n1m90W;fUb-Nhll=d_M_=V}h4LXt1E*rRNPt1urFUp|Iekph%GLLIg^T5?+)98c`%ncp(xc z#|h6*q{Kks;moB(3Li9A!BFAIRYI(0H?T5uDhdl>*Bg2`R`|yx7!DTxF$spFg?~(f za90xu7yfYxhT?^POoHKn;iVCz_;{pS&4$mGDQ*%}FyV;dACq7>WcbG<7>*fE1exua z&(NP;gUdSmUpnNV;Y8OL2hBC{Uoyy5U|7kLw|d+J@?5YCM-3;s_N4*bKl!)Rbk}55vc!|Vv*QS}b^)>KT1&)PdikC)j(4gX_Wgk4M_z?0J9U|ed;s=y^ zD6aT{q#h0|ejurbBa4?ty-;ZJ(kOVOm2hlvkodSUy4{|ogo2A70ODEsBphA*08sbJ zG@hP8;kYLbj*WnoBLnwsp zAz45wPw*bv-sR#Xg@TMz0ltWI*n%CZUsgaeJ|${6HYe5paXN{KX1g?SwaG21UU{QH3mHGTlgDHv-!Sk3_p0Ui!EK5RvW zqm3WHq5>g4!{Nq7IS=9iwg%GAJ*c+QOAe1xNz9l!$jbdTIi4ns~wvF)F;2}Y2RMtkpsMxA9EBz!G}|NJ?$PaRUT!g0t^)_*(@d9F;C zQys${iJXf3kA@;2o&s}1Za5Y>mB@r#lE9N4ZL3?OQS_W>bhv_%Q;E!t)_*=4Ih8%^ zfx*M!$p0h7hU1Z=*#BZc@?7bjo|Ow3Jmk>tgK2jV`6&>Q{6AH4I3zih{NIU5P9=xN z@qyuXX+g>V!xaceC8r9odBxM;?3oNvto|cm$*BhU#fo4JC@fug31+@HON-4Nj!RCZ z{}%(3=ZX)qAL0kKcX%U{Q}Nk?OAJk3JWn__xi8QD2PYponWCq!;ppVUP)ImDd8m*g z@yY$^F+TS*KzVUG1znefBa{~>IB1CS;#mieQC>W6Ruvi!QeHeWnF|dTrM$GQ*_*hW0jXwNGZX}OC#ji^Aw6! zzCVPDHar}zyrg1+@xO6K5RO;AUzCd0I2^Ein92!7EH9}X+UFGySzZ#UaQts#a|$tA zeKE`TlU7kihl7?6S4rWh<)xJriZu@Ygu|BaC#|CV3CArjsiaZ^mzP4!@oNx{TwY4% z!9$mqlzY(F$U$lpX1DKaW zy~`&3#Er32g4q zP*P-bf0hzLoBJ{hA-1_MUx~rZeR+l!-Q1T|EGfLXFUyePoBMK#r3N_n)b6@6? zLY(_@uvp-^py;^(!{Hd`zKo>?Irn9fh8E@Am$#%a=e`_6iF5ADC>9NL?n|COwzybA zr1Mh9loaZ`1VTfKbzTZR0pYz%3wG|KCYBoQ+@GtYaOb`(c7uIk%gt`=AzEn@@&9YP zm*fUv7!1HY5d+vs;SRk+rZZ%l?t1>p$dWBTMG9R3_AeVxlSv!k%e-@$bf+egRq$Nq z4vXg^9>8z^S6WVu~W^}G^nv*(qN&OH}l;gL7s^LnTypZ8K_`dp?| z_PLBG@N*I9=;xyEd;Ga5anL^(Sp|SD`|AXBnduVfh3+i_9lCp4m_NXsgP^;@_+?;J z_}>aTRK1Epe>5C)Yzq)NOk>9aH4-{z6AGOVW)?cPakewJviFT>mFL8B5k0Mc0g0XtalVOuV1)7_C74`}qNgM5 z%TzQ7@hKzksOb1BPb@m_v5Sto6&M|6ca4lrryXA4Z5kbC>1}ifi`(G*)sW}m=rlXM zj*jyy^XRVH2|juONQcUJ1FgS}RxPB*wY-YXMmn|;lFmc$11E|^d9I{GFkG%-;3|M) zOnMd<#JSc3KNZ^52otvuOMe)h?AzuTXELLor6gqj&i}mL3Po;(0?$?}x)h zr#Y7%r=vM{z4SO2rmO?gzaIM=!897)vhG1D!$|uxx6GE0-FWNHTc3W*Qq)d#WTp*Q z>-F;*>}tkk-3(l>W!7=A-_w2Bw#_^(e8gYZI}dMZB { } } +/* A linked list specialized to 64-bit elements */ +#[derive(Clone, Debug, PartialEq)] +#[repr(C,u64)] +pub enum List64 { + Nil64, + Cons64 (u64,Box) +} + +/* Test if a List64 is empty */ +pub fn list64_is_empty (l: &List64) -> bool { + match l { + List64::Nil64 => true, + List64::Cons64 (_,_) => false + } +} + + /* Insert a mapping into m from the greatest of x and y to the other */ pub fn hash_map_insert_gt_to_le (m: &mut HashMap, x:u64, y:u64) -> () { if x > y { @@ -288,6 +305,20 @@ pub fn hash_map_insert_gt_to_le (m: &mut HashMap, x:u64, y:u64) -> () { } } +/* A binary tree */ +pub enum BinTree { + BinLeaf (X), + BinNode (Box>,Box>) +} + +pub fn bintree_is_leaf (t: &BinTree) -> bool { + match *t { + BinTree::BinLeaf (_) => true, + BinTree::BinNode (_,_) => false + } +} + + /* A tree whose internal nodes contain vectors of children */ pub enum Tree { Leaf (X), diff --git a/heapster-saw/examples/rust_data.saw b/heapster-saw/examples/rust_data.saw index 2bbbeec57c..236acedcb6 100644 --- a/heapster-saw/examples/rust_data.saw +++ b/heapster-saw/examples/rust_data.saw @@ -34,6 +34,9 @@ heapster_define_rust_type env "pub enum Option { None, Some (X) }"; //heapster_define_recursive_perm env "ListPerm" "X:llvmshape 64, Xlen:bv 64, rw:rwmodality, l:lifetime" "llvmptr 64" ["[l]memblock(rw,0,Xlen + 16,List,X>)"] "\\ (X:sort 0) (_:Vec 64 Bool) -> List X" "\\ (X:sort 0) (_:Vec 64 Bool) -> foldListPermH X" "\\ (X:sort 0) (_:Vec 64 Bool) -> unfoldListPermH X"; heapster_define_rust_type env "pub enum List { Nil, Cons (X,Box>) }"; +// List64 type +heapster_define_rust_type env "pub enum List64 { Nil64, Cons64 (u64,Box) }"; + // The String type heapster_define_llvmshape env "String" 64 "" "exsh cap:bv 64. ptrsh(arraysh(cap,1,[(8,int8<>)]));fieldsh(int64<>);fieldsh(eq(llvmword(cap)))"; @@ -56,6 +59,9 @@ heapster_define_opaque_llvmshape env "Vec" 64 "T:llvmshape 64" "24" "\\ (T:sort // Opaque type for HashMap heapster_define_opaque_llvmshape env "HashMap" 64 "T:llvmshape 64, U:llvmshape 64" "56" "\\ (T:sort 0) (U:sort 0) -> List (T * U)"; +// BinTree type +heapster_define_rust_type env "pub enum BinTree { BinLeaf (X), BinNode (Box>,Box>) }"; + // Tree type // FIXME: this does not work yet because Heapster cannot yet handle recursive types // where the type being defined is passed to an opaque or recursvie type @@ -157,6 +163,10 @@ list_head_impl_sym <- heapster_find_symbol env "14list_head_impl"; heapster_typecheck_fun_rename env list_head_impl_sym "list_head_impl" "<'a> fn (l: &'a List) -> Result"; //heapster_typecheck_fun_rename env list_head_impl_sym "list_head_impl" "(rw:rwmodality).arg0:List),8,rw,always> -o ret:(struct(eq(llvmword(0)),exists z:bv 64. eq(llvmword(z)))) or (struct(eq(llvmword(1)),true))"; +// list64_is_empty +list64_is_empty_sym <- heapster_find_symbol env "15list64_is_empty"; +heapster_typecheck_fun_rename env list_is_empty_sym "list64_is_empty" "<'a> fn (l: &'a List64<>) -> bool"; + // StrStruct::new str_struct_new <- heapster_find_symbol env "9StrStruct3new"; @@ -166,6 +176,9 @@ str_struct_new <- heapster_find_symbol env "9StrStruct3new"; // FIXME: this is the correct version, with the String shape heapster_typecheck_fun_rename env str_struct_new "str_struct_new" "(len:bv 64).arg0:memblock(W,0,24,emptysh), arg1:array(0, int8<>]), arg2:eq(llvmword(len)) -o arg0:memblock(W,0,24,String<>)"; +bintree_is_leaf_sym <- heapster_find_symbol env "15bintree_is_leaf"; +heapster_typecheck_fun_rename env bintree_is_leaf_sym "bintree_is_leaf" "<'a> fn (t: &'a BinTree) -> bool"; + enum20_list_proj_sym <- heapster_find_symbol env "16enum20_list_proj"; //heapster_typecheck_fun_rename env enum20_list_proj_sym "enum20_list_proj" "<'a> fn (x:&'a Enum20>) -> &'a List"; diff --git a/heapster-saw/src/Verifier/SAW/Heapster/IRTTranslation.hs b/heapster-saw/src/Verifier/SAW/Heapster/IRTTranslation.hs index e35364f76e..6fff2e599e 100644 --- a/heapster-saw/src/Verifier/SAW/Heapster/IRTTranslation.hs +++ b/heapster-saw/src/Verifier/SAW/Heapster/IRTTranslation.hs @@ -599,6 +599,9 @@ instance IRTDescs (ValuePerm a) where do x1 <- irtDesc p1 ixs1 x2 <- irtDesc p2 ixs2 irtCtor "Prelude.IRT_Either" [x1, x2] + ([nuMP| ValPerm_Exists p |], IRTVarsCons ix _) + | [nuMP| ValPerm_Eq _ |] <- mbMatch (mbCombine RL.typeCtxProxies p) -> + irtCtor "Prelude.IRT_varT" [natOpenTerm ix] ([nuMP| ValPerm_Exists p |], IRTVarsCons ix ixs') -> do let tp = mbBindingType p tp_trans <- tupleTypeTrans <$> translateClosed tp From 5b5f422e43cab7de6cf3adc3a831bd4f16a383bb Mon Sep 17 00:00:00 2001 From: Eddy Westbrook Date: Wed, 1 Sep 2021 06:36:59 -0700 Subject: [PATCH 02/98] updated xor_swap_rust example to use the Rust type in the SAW script --- heapster-saw/examples/xor_swap_rust.saw | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/heapster-saw/examples/xor_swap_rust.saw b/heapster-saw/examples/xor_swap_rust.saw index 74dc989c02..ab764a67fe 100644 --- a/heapster-saw/examples/xor_swap_rust.saw +++ b/heapster-saw/examples/xor_swap_rust.saw @@ -1,10 +1,11 @@ // This script expects to be run from the saw-script root directory enable_experimental; - env <- heapster_init_env "xor_swap_rust" "xor_swap_rust.bc"; -xor_swap_sym <- heapster_find_symbol env "13xor_swap_rust13xor_swap_rust"; +heapster_define_llvmshape env "i64" 64 "" "fieldsh(exists x:bv 64.eq(llvmword(x)))"; -heapster_typecheck_fun_rename env xor_swap_sym "xor_swap_rust" "(x:bv 64, y:bv 64). arg0: ptr((W,0) |-> eq(llvmword(x))), arg1: ptr((W,0) |-> eq(llvmword(y))) -o arg0: ptr((W,0) |-> exists z:bv 64.eq(llvmword(z))), arg1: ptr((W,0) |-> exists z:bv 64.eq(llvmword(z))), ret:true"; +xor_swap_sym <- heapster_find_symbol env "13xor_swap_rust13xor_swap_rust"; +heapster_typecheck_fun_rename env xor_swap_sym "xor_swap_rust" "<'a,'b> fn (x:&'a mut i64, y:&'b mut i64)"; +//heapster_typecheck_fun_rename env xor_swap_sym "xor_swap_rust" "(x:bv 64, y:bv 64). arg0: ptr((W,0) |-> eq(llvmword(x))), arg1: ptr((W,0) |-> eq(llvmword(y))) -o arg0: ptr((W,0) |-> exists z:bv 64.eq(llvmword(z))), arg1: ptr((W,0) |-> exists z:bv 64.eq(llvmword(z))), ret:true"; heapster_export_coq env "xor_swap_rust_gen.v"; From 7b7709fadf06ac4398853be2c6714bce18c9d594 Mon Sep 17 00:00:00 2001 From: Eddy Westbrook Date: Wed, 1 Sep 2021 06:37:32 -0700 Subject: [PATCH 03/98] added a case to the Rust to Heapster translator to handle function types with no return value --- heapster-saw/src/Verifier/SAW/Heapster/RustTypes.hs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/heapster-saw/src/Verifier/SAW/Heapster/RustTypes.hs b/heapster-saw/src/Verifier/SAW/Heapster/RustTypes.hs index fbd151329a..1ecf1fc27c 100644 --- a/heapster-saw/src/Verifier/SAW/Heapster/RustTypes.hs +++ b/heapster-saw/src/Verifier/SAW/Heapster/RustTypes.hs @@ -1088,13 +1088,13 @@ rsConvertMonoFun w span abi ls fn_tp = rsConvertFun :: (1 <= w, KnownNat w) => prx w -> Abi -> Generics Span -> FnDecl Span -> RustConvM Some3FunPerm rsConvertFun w abi (Generics ldefs _tparams@[] - (WhereClause [] _) _) (FnDecl args (Just ret_tp) False _) = + (WhereClause [] _) _) (FnDecl args maybe_ret_tp False _) = fmap (\ret -> tracePretty (pretty "rsConvertFun returning:" <+> permPretty emptyPPInfo ret) ret) $ withLifetimes ldefs $ do arg_shapes <- mapM (rsConvert w) args - ret_shape <- rsConvert w ret_tp + ret_shape <- maybe (return PExpr_EmptyShape) (rsConvert w) maybe_ret_tp layoutFun abi arg_shapes ret_shape rsConvertFun _ _ _ _ = fail "rsConvertFun: unsupported Rust function type" From c18aec7701a02bef551c87ecb619baef5013b9c0 Mon Sep 17 00:00:00 2001 From: Eddy Westbrook Date: Wed, 1 Sep 2021 06:53:18 -0700 Subject: [PATCH 04/98] whoops, forgot to update the bitcode file for xor_swap_rust --- heapster-saw/examples/xor_swap_rust.bc | Bin 5408 -> 2128 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/heapster-saw/examples/xor_swap_rust.bc b/heapster-saw/examples/xor_swap_rust.bc index f770bc2e4e9d8277f64962a151dc14b10f478f35..3d46937f618564acfc7bc81d83a6cf1364d45d47 100644 GIT binary patch delta 898 zcmZWmOH30{6umPHWlBGpfg(jfr>#XSiqnD0FG@ck5E=r(7*Nr6+5!ed`AAGO0c*vg zD1~vMAyG(J7>x-^j0rBJPzf3m!HsdF3v|WCt%d~el&~1ZPNZ$+bkRH)hU_aj|7=HOv8Ma2JfUlJnoDQjOCgT-HNV5nYNqJfaGP+)SSXTI%ASk~8QG;g**f({^uFs*O zlmlaFH9-up3qK=^?|=RHb6makX`^?pW6y)fA4Kb%?ZnrX8ADoq5>^oacC5uU8(hyz zn{JVDkBfVgS{T-ll?KdvZBIl?*!M`C!MYH@WsU#|891<^O#(R=Z_>4h(^*XmQ1O=OyJUXb$W=Eigs zsT84fRMS1q`9(zq%Rrjr*>(`az~G>j@sn5zGdPrh!^gkZ%5A>QrpvpO3r{D4zc-e+ z&387s{4x~{Bub+yLxau)W_uF}1uP*(7Tgts`f0w?P9+lROonuTNwEY$4}ah$U(2)? zGXU~c(|O8qiH-)6h<>EKlm|>n_zay%|ac2&e(fn4gmHFju|@{&(dP z#x-OHatxV;v>|2eoXc9ym+=yLEUvcmwh&MVu#Vngq+FYa-0@LD3yx8RJC1Qw?sMTx zon&DRjF0#Eib||D-c}^?KARw&WiwfuRS>*Fq38`1^8SF=TPdxv<=O(TwN(_w_9MQw ZtNFa-)tPr!dvrRfi=~abI>{Jy1G+>QNUQ4`M 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 L<+nxtRf7H(geFX* From 5bc366ae90af7bdaf222ff2a4cdf237b967cc6e7 Mon Sep 17 00:00:00 2001 From: Eddy Westbrook Date: Wed, 1 Sep 2021 06:53:59 -0700 Subject: [PATCH 05/98] bugfix in the Rust to Heapster translator: empty return types need to be converted to unit, not to the empty struct --- .../src/Verifier/SAW/Heapster/RustTypes.hs | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/heapster-saw/src/Verifier/SAW/Heapster/RustTypes.hs b/heapster-saw/src/Verifier/SAW/Heapster/RustTypes.hs index 1ecf1fc27c..dd2a6489f1 100644 --- a/heapster-saw/src/Verifier/SAW/Heapster/RustTypes.hs +++ b/heapster-saw/src/Verifier/SAW/Heapster/RustTypes.hs @@ -931,14 +931,24 @@ layoutFun abi arg_shs ret_sh = foldr appendArgLayout argLayout0 <$> mapM (layoutArgShape abi) arg_shs ret_layout_eith <- layoutArgShapeOrBlock abi ret_sh case ret_layout_eith of + + -- Special case: if the return type is empty, use the unit type as the + -- return type + Right (ArgLayout Ctx.Empty _) -> + funPerm3FromArgLayoutNoArgs args_layout UnitRepr ValPerm_True + + -- Special case: if the return type is a single field, remove the struct + -- type and just use the type of that single field Right (ArgLayout (Ctx.Empty Ctx.:> ret_tp) (argLayoutPerm1ToPerm -> ret_p)) -> - -- Special case: if the return type is a single field, remove the - -- struct type and just use the type of that single field funPerm3FromArgLayoutNoArgs args_layout ret_tp ret_p + + -- If the return type can be laid out as a struct type, then do so Right (ArgLayout ret_ctx ret_p) -> funPerm3FromArgLayoutNoArgs args_layout (StructRepr ret_ctx) (argLayoutPermToPerm ret_p) + + -- Otherwise add an extra pointer argument used as an out variable Left bp -> funPerm3FromArgLayout args_layout (extend Ctx.empty knownRepr) From 068b7356846095818d2d0c0cedf39f8421e49be6 Mon Sep 17 00:00:00 2001 From: Eddy Westbrook Date: Wed, 1 Sep 2021 14:35:58 -0700 Subject: [PATCH 06/98] tweaked the error message for when Rust types do not translate correctly to the expected LLVM type --- heapster-saw/src/Verifier/SAW/Heapster/RustTypes.hs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/heapster-saw/src/Verifier/SAW/Heapster/RustTypes.hs b/heapster-saw/src/Verifier/SAW/Heapster/RustTypes.hs index dd2a6489f1..0f1771714c 100644 --- a/heapster-saw/src/Verifier/SAW/Heapster/RustTypes.hs +++ b/heapster-saw/src/Verifier/SAW/Heapster/RustTypes.hs @@ -673,12 +673,12 @@ un3SomeFunPerm args ret (Some3FunPerm fun_perm) return $ SomeFunPerm fun_perm un3SomeFunPerm args ret (Some3FunPerm fun_perm) = fail $ renderDoc $ vsep - [ pretty "Incorrect LLVM type for function permission:" + [ pretty "Unexpected LLVM type for function permission:" , permPretty emptyPPInfo fun_perm - , pretty "Expected type:" + , pretty "Actual LLVM type of function:" <+> PP.group (permPretty emptyPPInfo args) <+> pretty "=>" <+> PP.group (permPretty emptyPPInfo ret) - , pretty "Actual type:" + , pretty "Expected LLVM type of function:" <+> PP.group (permPretty emptyPPInfo (funPermArgs fun_perm)) <+> pretty "=>" <+> PP.group (permPretty emptyPPInfo (funPermRet fun_perm)) ] From f63c32665845d420f4f5420c93159630dfb3a48a Mon Sep 17 00:00:00 2001 From: Eddy Westbrook Date: Thu, 2 Sep 2021 06:22:46 -0700 Subject: [PATCH 07/98] started adding support for string literals by moving all creation of a HeapsterEnv into a single function which iterates through the globals and adds those it can handle --- src/SAWScript/HeapsterBuiltins.hs | 64 ++++++++++++++++++++++--------- 1 file changed, 46 insertions(+), 18 deletions(-) diff --git a/src/SAWScript/HeapsterBuiltins.hs b/src/SAWScript/HeapsterBuiltins.hs index 1900049dd8..bc0f336c48 100644 --- a/src/SAWScript/HeapsterBuiltins.hs +++ b/src/SAWScript/HeapsterBuiltins.hs @@ -254,6 +254,49 @@ parseAndInsDef henv nm term_tp term_string = liftIO $ scInsertDef sc mnm term_ident term_tp term return term_ident +-- | Translate a typed LLVM 'L.Value' to a Heapster permission + translation +-- +-- FIXME: move this to Permissions.hs +translateLLVMValue :: (1 <= w, KnownNat w) => f w -> L.Type -> L.Value -> + Maybe (ValuePerm (LLVMPointerType w), [OpenTerm]) +translateLLVMValue _ _ _ = + -- FIXME HERE NOW + Nothing + +-- | Add an LLVM global constant to a 'PermEnv', if the global has a type and +-- value we can translate to Heapster, otherwise silently ignore it +-- +-- FIXME: move this to Permissions.hs +permEnvAddGlobalConst :: (1 <= w, KnownNat w) => f w -> PermEnv -> + L.Global -> PermEnv +permEnvAddGlobalConst w env global = + maybe env id $ + do val <- L.globalValue global + (p, ts) <- translateLLVMValue w (L.globalType global) val + return $ permEnvAddGlobalSyms env + [PermEnvGlobalEntry (GlobalSymbol $ L.globalSym global) p ts] + +-- | Build a 'HeapsterEnv' associated with the given SAW core module and the +-- given 'LLVMModule's. Add any globals in the 'LLVMModule's to the returned +-- 'HeapsterEnv'. +mkHeapsterEnv :: ModuleName -> [Some LLVMModule] -> TopLevel HeapsterEnv +mkHeapsterEnv saw_mod_name llvm_mods@(Some first_mod:_) = + do let w = llvmModuleArchReprWidth first_mod + leq_proof <- case decideLeq (knownNat @1) w of + Left pf -> return pf + Right _ -> fail "LLVM arch width is 0!" + let globals = concatMap (\(Some lm) -> L.modGlobals $ modAST lm) llvm_mods + env = + withKnownNat w $ withLeqProof leq_proof $ + foldl (permEnvAddGlobalConst w) heapster_default_env globals + env_ref <- liftIO $ newIORef env + return $ HeapsterEnv { + heapsterEnvSAWModule = saw_mod_name, + heapsterEnvPermEnvRef = env_ref, + heapsterEnvLLVMModules = llvm_mods + } +mkHeapsterEnv _ [] = fail "mkHeapsterEnv: empty list of LLVM modules!" + heapster_init_env :: BuiltinContext -> Options -> Text -> String -> TopLevel HeapsterEnv @@ -269,12 +312,7 @@ heapster_init_env _bic _opts mod_str llvm_filename = preludeMod <- liftIO $ scFindModule sc preludeModuleName liftIO $ scLoadModule sc (insImport (const True) preludeMod $ emptyModule saw_mod_name) - perm_env_ref <- liftIO $ newIORef heapster_default_env - return $ HeapsterEnv { - heapsterEnvSAWModule = saw_mod_name, - heapsterEnvPermEnvRef = perm_env_ref, - heapsterEnvLLVMModules = [llvm_mod] - } + mkHeapsterEnv saw_mod_name [llvm_mod] load_sawcore_from_file :: BuiltinContext -> Options -> String -> TopLevel () load_sawcore_from_file _ _ mod_filename = @@ -289,12 +327,7 @@ heapster_init_env_from_file _bic _opts mod_filename llvm_filename = sc <- getSharedContext (saw_mod, saw_mod_name) <- readModuleFromFile mod_filename liftIO $ tcInsertModule sc saw_mod - perm_env_ref <- liftIO $ newIORef heapster_default_env - return $ HeapsterEnv { - heapsterEnvSAWModule = saw_mod_name, - heapsterEnvPermEnvRef = perm_env_ref, - heapsterEnvLLVMModules = [llvm_mod] - } + mkHeapsterEnv saw_mod_name [llvm_mod] heapster_init_env_for_files :: BuiltinContext -> Options -> String -> [String] -> TopLevel HeapsterEnv @@ -303,12 +336,7 @@ heapster_init_env_for_files _bic _opts mod_filename llvm_filenames = sc <- getSharedContext (saw_mod, saw_mod_name) <- readModuleFromFile mod_filename liftIO $ tcInsertModule sc saw_mod - perm_env_ref <- liftIO $ newIORef heapster_default_env - return $ HeapsterEnv { - heapsterEnvSAWModule = saw_mod_name, - heapsterEnvPermEnvRef = perm_env_ref, - heapsterEnvLLVMModules = llvm_mods - } + mkHeapsterEnv saw_mod_name llvm_mods -- | Look up the CFG associated with a symbol name in a Heapster environment heapster_get_cfg :: BuiltinContext -> Options -> HeapsterEnv -> From 2720516e64b5d632de419696ec00f47285c5a46c Mon Sep 17 00:00:00 2001 From: Eddy Westbrook Date: Thu, 2 Sep 2021 17:56:53 -0700 Subject: [PATCH 08/98] added a formatting example in Rust, and started defining the necessary types for it --- heapster-saw/examples/rust_data.bc | Bin 205856 -> 207424 bytes heapster-saw/examples/rust_data.rs | 14 +++++++++++++- heapster-saw/examples/rust_data.saw | 15 +++++++++++++++ 3 files changed, 28 insertions(+), 1 deletion(-) diff --git a/heapster-saw/examples/rust_data.bc b/heapster-saw/examples/rust_data.bc index eb625d453c4cbad040cd2a0fcde7b5ff9cb6dc99..d26bc8b0529c41cea2531972c8690ed35e8c7516 100644 GIT binary patch literal 207424 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 z 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

N##s)t#mS1_&_pq>Dd0;B&1mo#=bs0%=$yo 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

mikPeyulVhOjQ!|}y161O1%)7V+4I&hxQrxq` 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 Zgl>npTzuB=;^9F1c*@4#UHvfq`w!4YE+PN` diff --git a/heapster-saw/examples/rust_data.rs b/heapster-saw/examples/rust_data.rs index e488eeef99..a24bd53879 100644 --- a/heapster-saw/examples/rust_data.rs +++ b/heapster-saw/examples/rust_data.rs @@ -1,4 +1,6 @@ use std::collections::{HashMap, HashSet}; +use std::fmt; + /* The logical and operation as a function on bool */ pub fn bool_and (x:bool, y:bool) -> bool { @@ -245,6 +247,17 @@ pub fn cycle_true_enum (te: &TrueEnum) -> TrueEnum { } } +impl fmt::Display for TrueEnum { + fn fmt<'a, 'b>(&'a self, f: &'b mut fmt::Formatter) -> fmt::Result { + match self { + TrueEnum::Foo => write!(f, "Foo"), + TrueEnum::Bar => write!(f, "Bar"), + TrueEnum::Baz => write!(f, "Baz"), + } + } +} + + /* A linked list */ #[derive(Clone, Debug, PartialEq)] #[repr(C,u64)] @@ -295,7 +308,6 @@ pub fn list64_is_empty (l: &List64) -> bool { } } - /* Insert a mapping into m from the greatest of x and y to the other */ pub fn hash_map_insert_gt_to_le (m: &mut HashMap, x:u64, y:u64) -> () { if x > y { diff --git a/heapster-saw/examples/rust_data.saw b/heapster-saw/examples/rust_data.saw index 236acedcb6..21202e93b8 100644 --- a/heapster-saw/examples/rust_data.saw +++ b/heapster-saw/examples/rust_data.saw @@ -34,6 +34,17 @@ heapster_define_rust_type env "pub enum Option { None, Some (X) }"; //heapster_define_recursive_perm env "ListPerm" "X:llvmshape 64, Xlen:bv 64, rw:rwmodality, l:lifetime" "llvmptr 64" ["[l]memblock(rw,0,Xlen + 16,List,X>)"] "\\ (X:sort 0) (_:Vec 64 Bool) -> List X" "\\ (X:sort 0) (_:Vec 64 Bool) -> foldListPermH X" "\\ (X:sort 0) (_:Vec 64 Bool) -> unfoldListPermH X"; heapster_define_rust_type env "pub enum List { Nil, Cons (X,Box>) }"; +// fmt::Error type +heapster_define_rust_type_qual env "fmt" "pub struct Error { }"; + +// fmt::Result type +// FIXME: there seems to be some optimization in Rust that lays out fmt::Result as a 1-bit value +heapster_define_llvmshape env "fmt::Result" 64 "" "fieldsh(1,eq(llvmword(0))) orsh fieldsh(1,eq(llvmword(1)))"; +//heapster_define_rust_type_qual env "fmt" "pub enum Result { Ok (), Err (fmt::Error) }"; + +// Formatter type +heapster_define_opaque_llvmshape env "fmt::Formatter" 64 "" "64" "#()"; + // List64 type heapster_define_rust_type env "pub enum List64 { Nil64, Cons64 (u64,Box) }"; @@ -106,6 +117,10 @@ heapster_assume_fun_rename env to_string_str "to_string_str" "(len:bv 64). arg0: hashmap_u64_u64_insert_sym <- heapster_find_symbol env "std11collections4hash3map24HashMap$LT$K$C$V$C$S$GT$6insert"; heapster_assume_fun_rename env hashmap_u64_u64_insert_sym "hashmap_u64_u64_insert" "<'a> fn (&'a mut HashMap,u64,u64) -> Option" "\\ (endl:HashMap (Vec 64 Bool) (Vec 64 Bool) * #() -> CompM (HashMap (Vec 64 Bool) (Vec 64 Bool) * #())) (h:HashMap (Vec 64 Bool) (Vec 64 Bool)) (k:Vec 64 Bool) (v:Vec 64 Bool) -> returnM ((#() -> CompM (HashMap (Vec 64 Bool) (Vec 64 Bool) * #())) * Either #() (Vec 64 Bool) * #()) ((\\ (_:#()) -> returnM (HashMap (Vec 64 Bool) (Vec 64 Bool) * #()) (Cons (Vec 64 Bool * Vec 64 Bool) (k,v) h, ())), Left #() (Vec 64 Bool) (), ())"; +String__fmt_sym <- heapster_find_trait_method_symbol env "core::fmt::Display::fmt"; +// heapster_assume_fun_rename env String__fmt_sym "String__fmt" "<'a, 'b> fn(&'a String, f: &'b mut fmt::Formatter) -> fmt::Result" "\\ (end_a : List (Vec 8 Bool) * #() -> CompM (List (Vec 8 Bool) * #())) (end_b : #() * #() -> CompM (#() * #())) (str:List (Vec 8 Bool)) (fmt : #()) -> returnM ((#() -> CompM (List (Vec 8 Bool) * #())) * (#() -> CompM (#() * #())) * Either #() #() * #()) ((\\ (_:#()) -> returnM (List (Vec 8 Bool) * #()) (str, ())), (\\ (_:#()) -> returnM (#() * #()) ((), ())), Left #() #() (), ())"; +heapster_assume_fun_rename_prim env String__fmt_sym "String__fmt" "<'a, 'b> fn(&'a String, f: &'b mut fmt::Formatter) -> fmt::Result"; + /*** *** Type-Checked Functions From a6aee80e03eee206c1a06f1d475b2e2dbd7e2595 Mon Sep 17 00:00:00 2001 From: Eddy Westbrook Date: Thu, 2 Sep 2021 17:57:30 -0700 Subject: [PATCH 09/98] started trying to figure out how Rust stores string literals in its generated LLVM files --- src/SAWScript/HeapsterBuiltins.hs | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/SAWScript/HeapsterBuiltins.hs b/src/SAWScript/HeapsterBuiltins.hs index bc0f336c48..1351fc6908 100644 --- a/src/SAWScript/HeapsterBuiltins.hs +++ b/src/SAWScript/HeapsterBuiltins.hs @@ -93,6 +93,7 @@ import Lang.Crucible.LLVM.TypeContext import Lang.Crucible.LLVM.DataLayout import qualified Text.LLVM.AST as L +import qualified Text.LLVM.PP as L import SAWScript.TopLevel import SAWScript.Value @@ -113,6 +114,8 @@ import SAWScript.Prover.Exporter import Verifier.SAW.Translation.Coq import Prettyprinter +import Debug.Trace + -- | Extract out the contents of the 'Right' of an 'Either', calling 'fail' if -- the 'Either' is a 'Left'. The supplied 'String' describes the action (in @@ -260,7 +263,6 @@ parseAndInsDef henv nm term_tp term_string = translateLLVMValue :: (1 <= w, KnownNat w) => f w -> L.Type -> L.Value -> Maybe (ValuePerm (LLVMPointerType w), [OpenTerm]) translateLLVMValue _ _ _ = - -- FIXME HERE NOW Nothing -- | Add an LLVM global constant to a 'PermEnv', if the global has a type and @@ -270,6 +272,10 @@ translateLLVMValue _ _ _ = permEnvAddGlobalConst :: (1 <= w, KnownNat w) => f w -> PermEnv -> L.Global -> PermEnv permEnvAddGlobalConst w env global = + trace ("Global: " ++ show (L.globalSym global) ++ "; value =" ++ + show (maybe "None" (L.withConfig + (L.Config True True True) + (show . L.ppValue)) (L.globalValue global))) $ maybe env id $ do val <- L.globalValue global (p, ts) <- translateLLVMValue w (L.globalType global) val From 024287ef0afa0a9b88e8a48e6ba8ebf33678c99a Mon Sep 17 00:00:00 2001 From: Eddy Westbrook Date: Tue, 7 Sep 2021 07:10:59 -0700 Subject: [PATCH 10/98] fixed the prtty-printing for constant values --- src/SAWScript/HeapsterBuiltins.hs | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/SAWScript/HeapsterBuiltins.hs b/src/SAWScript/HeapsterBuiltins.hs index 960987c878..342b573ebd 100644 --- a/src/SAWScript/HeapsterBuiltins.hs +++ b/src/SAWScript/HeapsterBuiltins.hs @@ -114,6 +114,7 @@ import Verifier.SAW.Heapster.ParsedCtx import SAWScript.Prover.Exporter import Verifier.SAW.Translation.Coq import Prettyprinter +import qualified Text.PrettyPrint.HughesPJ as PPHPJ import Debug.Trace @@ -273,10 +274,10 @@ translateLLVMValue _ _ _ = permEnvAddGlobalConst :: (1 <= w, KnownNat w) => f w -> PermEnv -> L.Global -> PermEnv permEnvAddGlobalConst w env global = - trace ("Global: " ++ show (L.globalSym global) ++ "; value =" ++ - show (maybe "None" (L.withConfig - (L.Config True True True) - (show . L.ppValue)) (L.globalValue global))) $ + trace ("Global: " ++ show (L.globalSym global) ++ "; value =\n" ++ + maybe "None" (L.withConfig + (L.Config True True True) + (\v -> show $ PPHPJ.nest 2 $ L.ppValue v)) (L.globalValue global)) $ maybe env id $ do val <- L.globalValue global (p, ts) <- translateLLVMValue w (L.globalType global) val From 917547e34c57b8d5b09bdf2d7bafdb83bf711c80 Mon Sep 17 00:00:00 2001 From: Eddy Westbrook Date: Tue, 7 Sep 2021 07:13:11 -0700 Subject: [PATCH 11/98] changed TrueEnum::fmt to use the fmt method rather than the write! macro --- heapster-saw/examples/rust_data.bc | Bin 207424 -> 206528 bytes heapster-saw/examples/rust_data.rs | 6 +++--- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/heapster-saw/examples/rust_data.bc b/heapster-saw/examples/rust_data.bc index d26bc8b0529c41cea2531972c8690ed35e8c7516..8334f5cf9944d96f1c4a8d228c9423251e5b4af4 100644 GIT binary patch literal 206528 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 SF5DcVFWGSfjwXjq8<|72%>a7c7N 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 z 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

N##s)t#mS1_&_pq>Dd0;B&1mo#=bs0%=$yo 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

mikPeyulVhOjQ!|}y161O1%)7V+4I&hxQrxq` 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 TrueEnum { impl fmt::Display for TrueEnum { fn fmt<'a, 'b>(&'a self, f: &'b mut fmt::Formatter) -> fmt::Result { match self { - TrueEnum::Foo => write!(f, "Foo"), - TrueEnum::Bar => write!(f, "Bar"), - TrueEnum::Baz => write!(f, "Baz"), + TrueEnum::Foo => "Foo".fmt(f), + TrueEnum::Bar => "Bar".fmt(f), + TrueEnum::Baz => "Baz".fmt(f), } } } From 389d0d20a229ef18ebdc39e685c1653df1af0494 Mon Sep 17 00:00:00 2001 From: Eddy Westbrook Date: Tue, 7 Sep 2021 07:17:57 -0700 Subject: [PATCH 12/98] whoops, changed the fmt method for TrueEnum back to using the write! macro, because that seems to be the proper way to do things --- heapster-saw/examples/rust_data.bc | Bin 206528 -> 207424 bytes heapster-saw/examples/rust_data.rs | 6 +++--- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/heapster-saw/examples/rust_data.bc b/heapster-saw/examples/rust_data.bc index 8334f5cf9944d96f1c4a8d228c9423251e5b4af4..d26bc8b0529c41cea2531972c8690ed35e8c7516 100644 GIT binary patch literal 207424 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 z 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

N##s)t#mS1_&_pq>Dd0;B&1mo#=bs0%=$yo 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

mikPeyulVhOjQ!|}y161O1%)7V+4I&hxQrxq` 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 S TrueEnum { impl fmt::Display for TrueEnum { fn fmt<'a, 'b>(&'a self, f: &'b mut fmt::Formatter) -> fmt::Result { match self { - TrueEnum::Foo => "Foo".fmt(f), - TrueEnum::Bar => "Bar".fmt(f), - TrueEnum::Baz => "Baz".fmt(f), + TrueEnum::Foo => write!(f,"Foo"), + TrueEnum::Bar => write!(f,"Bar"), + TrueEnum::Baz => write!(f,"Baz"), } } } From f0ed90b24b4de44ad5f6e3c33afb6d755d8f4f64 Mon Sep 17 00:00:00 2001 From: Eddy Westbrook Date: Tue, 7 Sep 2021 09:17:20 -0700 Subject: [PATCH 13/98] whoops, forgot to add the repr(u64) pragma to the TrueEnum type --- heapster-saw/examples/rust_data.bc | Bin 207424 -> 207360 bytes heapster-saw/examples/rust_data.rs | 1 + 2 files changed, 1 insertion(+) diff --git a/heapster-saw/examples/rust_data.bc b/heapster-saw/examples/rust_data.bc index d26bc8b0529c41cea2531972c8690ed35e8c7516..22392f05c8b140195cafea37da6465ad8c68a58a 100644 GIT binary patch delta 59069 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≧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 diff --git a/heapster-saw/examples/rust_data.rs b/heapster-saw/examples/rust_data.rs index 94fd1e7a76..28ba2bbfe5 100644 --- a/heapster-saw/examples/rust_data.rs +++ b/heapster-saw/examples/rust_data.rs @@ -233,6 +233,7 @@ impl MixedStruct { /* A 'true' enum */ #[derive(Clone, Debug, PartialEq)] +#[repr(u64)] pub enum TrueEnum { Foo, Bar, From 1d6a5d7319638dc648b90089641fccbe72b7069f Mon Sep 17 00:00:00 2001 From: Eddy Westbrook Date: Tue, 7 Sep 2021 09:18:20 -0700 Subject: [PATCH 14/98] added a type-checking command for TrueEnum::fmt --- heapster-saw/examples/rust_data.saw | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/heapster-saw/examples/rust_data.saw b/heapster-saw/examples/rust_data.saw index 21202e93b8..982bdf45b2 100644 --- a/heapster-saw/examples/rust_data.saw +++ b/heapster-saw/examples/rust_data.saw @@ -117,9 +117,13 @@ heapster_assume_fun_rename env to_string_str "to_string_str" "(len:bv 64). arg0: hashmap_u64_u64_insert_sym <- heapster_find_symbol env "std11collections4hash3map24HashMap$LT$K$C$V$C$S$GT$6insert"; heapster_assume_fun_rename env hashmap_u64_u64_insert_sym "hashmap_u64_u64_insert" "<'a> fn (&'a mut HashMap,u64,u64) -> Option" "\\ (endl:HashMap (Vec 64 Bool) (Vec 64 Bool) * #() -> CompM (HashMap (Vec 64 Bool) (Vec 64 Bool) * #())) (h:HashMap (Vec 64 Bool) (Vec 64 Bool)) (k:Vec 64 Bool) (v:Vec 64 Bool) -> returnM ((#() -> CompM (HashMap (Vec 64 Bool) (Vec 64 Bool) * #())) * Either #() (Vec 64 Bool) * #()) ((\\ (_:#()) -> returnM (HashMap (Vec 64 Bool) (Vec 64 Bool) * #()) (Cons (Vec 64 Bool * Vec 64 Bool) (k,v) h, ())), Left #() (Vec 64 Bool) (), ())"; +/* String__fmt_sym <- heapster_find_trait_method_symbol env "core::fmt::Display::fmt"; // heapster_assume_fun_rename env String__fmt_sym "String__fmt" "<'a, 'b> fn(&'a String, f: &'b mut fmt::Formatter) -> fmt::Result" "\\ (end_a : List (Vec 8 Bool) * #() -> CompM (List (Vec 8 Bool) * #())) (end_b : #() * #() -> CompM (#() * #())) (str:List (Vec 8 Bool)) (fmt : #()) -> returnM ((#() -> CompM (List (Vec 8 Bool) * #())) * (#() -> CompM (#() * #())) * Either #() #() * #()) ((\\ (_:#()) -> returnM (List (Vec 8 Bool) * #()) (str, ())), (\\ (_:#()) -> returnM (#() * #()) ((), ())), Left #() #() (), ())"; heapster_assume_fun_rename_prim env String__fmt_sym "String__fmt" "<'a, 'b> fn(&'a String, f: &'b mut fmt::Formatter) -> fmt::Result"; +*/ + + /*** @@ -163,6 +167,9 @@ cycle_true_enum_sym <- heapster_find_symbol env "15cycle_true_enum"; // NOTE: This typecheck requires full(er) support for disjunctive shapes, which Heapster currently lacks // heapster_typecheck_fun_rename env cycle_true_enum_sym "cycle_true_enum" "<'a> fn (te:&'a TrueEnum) -> TrueEnum"; +TrueEnum__fmt_sym <- heapster_find_trait_method_symbol env "core::fmt::Display::fmt"; +heapster_typecheck_fun_rename env TrueEnum__fmt_sym "TrueEnum__fmt" "<'a, 'b> fn (&'a TrueEnum, f: &'b mut fmt::Formatter) -> fmt::Result"; + // list_is_empty list_is_empty_sym <- heapster_find_symbol env "13list_is_empty"; heapster_typecheck_fun_rename env list_is_empty_sym "list_is_empty" "<'a> fn (l: &'a List) -> bool"; From e987f428822e9f063d31ce54034adc15de3e0a79 Mon Sep 17 00:00:00 2001 From: Eddy Westbrook Date: Tue, 7 Sep 2021 15:04:58 -0700 Subject: [PATCH 15/98] moved some OpenTerm operators from SAWTranslation.hs to OpenTerm.hs --- .../Verifier/SAW/Heapster/SAWTranslation.hs | 29 ++++++--------- saw-core/src/Verifier/SAW/OpenTerm.hs | 36 +++++++++++++++++++ 2 files changed, 46 insertions(+), 19 deletions(-) diff --git a/heapster-saw/src/Verifier/SAW/Heapster/SAWTranslation.hs b/heapster-saw/src/Verifier/SAW/Heapster/SAWTranslation.hs index 080a890d2d..9a84ab4b6e 100644 --- a/heapster-saw/src/Verifier/SAW/Heapster/SAWTranslation.hs +++ b/heapster-saw/src/Verifier/SAW/Heapster/SAWTranslation.hs @@ -45,7 +45,6 @@ import Control.Lens hiding ((:>), Index, ix, op) import Control.Monad.Reader hiding (ap) import Control.Monad.Writer hiding (ap) import Control.Monad.Trans.Maybe -import qualified Data.Vector as V import qualified Control.Monad.Fail as Fail import What4.ProgramLoc @@ -725,18 +724,10 @@ piExprCtx ctx m = ---------------------------------------------------------------------- -- FIXME HERE: move these OpenTerm operations to OpenTerm.hs -trueOpenTerm :: OpenTerm -trueOpenTerm = globalOpenTerm "Prelude.True" -boolOpenTerm :: Bool -> OpenTerm -boolOpenTerm True = globalOpenTerm "Prelude.True" -boolOpenTerm False = globalOpenTerm "Prelude.False" - --- | Create a SAW core term for a bitvector literal -bvLitOpenTerm :: NatRepr w -> BV w -> OpenTerm -bvLitOpenTerm w bv = - flatOpenTerm $ ArrayValue (globalOpenTerm "Prelude.Bool") $ - V.fromList (map boolOpenTerm $ BV.asBitsBE w bv) +-- | Build a bitvector literal from a 'BV' value +bvBVOpenTerm :: NatRepr w -> BV w -> OpenTerm +bvBVOpenTerm w bv = bvLitOpenTerm (BV.asBitsBE w bv) bvNatOpenTerm :: Natural -> Natural -> OpenTerm bvNatOpenTerm w n = @@ -787,7 +778,7 @@ instance TransInfo info => return $ ETrans_Term $ stringLitOpenTerm $ pack $ mbLift str [nuMP| PExpr_BV bvfactors@[] off |] -> let w = natRepr3 bvfactors in - return $ ETrans_Term $ bvLitOpenTerm w $ mbLift off + return $ ETrans_Term $ bvBVOpenTerm w $ mbLift off [nuMP| PExpr_BV bvfactors (BV.BV 0) |] -> let w = natVal3 bvfactors in ETrans_Term <$> foldr1 (bvAddOpenTerm w) <$> @@ -796,7 +787,7 @@ instance TransInfo info => do let w = natRepr3 bvfactors bv_transs <- mapM translate $ mbList bvfactors return $ ETrans_Term $ - foldr (bvAddOpenTerm $ natValue w) (bvLitOpenTerm w $ mbLift off) bv_transs + foldr (bvAddOpenTerm $ natValue w) (bvBVOpenTerm w $ mbLift off) bv_transs [nuMP| PExpr_Struct args |] -> ETrans_Struct <$> translate args [nuMP| PExpr_Always |] -> @@ -869,7 +860,7 @@ instance TransInfo info => Translate info ctx (BVFactor w) OpenTerm where [nuMP| BVFactor (BV.BV 1) x |] -> translate1 (fmap PExpr_Var x) [nuMP| BVFactor i x |] -> let w = natRepr4 x in - bvMulOpenTerm (natValue w) (bvLitOpenTerm w $ mbLift i) <$> + bvMulOpenTerm (natValue w) (bvBVOpenTerm w $ mbLift i) <$> translate1 (fmap PExpr_Var x) @@ -3623,7 +3614,7 @@ instance (PermCheckExtC ext, TransInfo info) => -- Bitvectors [nuMP| BVLit w mb_bv |] -> - return $ ETrans_Term $ bvLitOpenTerm (mbLift w) $ mbLift mb_bv + return $ ETrans_Term $ bvBVOpenTerm (mbLift w) $ mbLift mb_bv [nuMP| BVConcat w1 w2 e1 e2 |] -> ETrans_Term <$> applyMultiTransM (return $ globalOpenTerm "Prelude.join") @@ -3748,15 +3739,15 @@ instance (PermCheckExtC ext, TransInfo info) => applyMultiTransM (return $ globalOpenTerm "Prelude.ite") [bitvectorTransM (translate mb_w), translateRWV e, - return (bvLitOpenTerm w (BV.one w)), - return (bvLitOpenTerm w (BV.zero w))] + return (bvBVOpenTerm w (BV.one w)), + return (bvBVOpenTerm w (BV.zero w))] [nuMP| BVNonzero mb_w e |] -> let w = mbLift mb_w in ETrans_Term <$> applyTransM (return $ globalOpenTerm "Prelude.not") (applyMultiTransM (return $ globalOpenTerm "Prelude.bvEq") [translate mb_w, translateRWV e, - return (bvLitOpenTerm w (BV.zero w))]) + return (bvBVOpenTerm w (BV.zero w))]) -- Strings [nuMP| Expr.StringLit (UnicodeLiteral text) |] -> diff --git a/saw-core/src/Verifier/SAW/OpenTerm.hs b/saw-core/src/Verifier/SAW/OpenTerm.hs index 30a57e7339..f8cc3e6d80 100644 --- a/saw-core/src/Verifier/SAW/OpenTerm.hs +++ b/saw-core/src/Verifier/SAW/OpenTerm.hs @@ -23,6 +23,8 @@ module Verifier.SAW.OpenTerm ( closedOpenTerm, flatOpenTerm, sortOpenTerm, natOpenTerm, unitOpenTerm, unitTypeOpenTerm, stringLitOpenTerm, stringTypeOpenTerm, + trueOpenTerm, falseOpenTerm, boolOpenTerm, boolTypeOpenTerm, + arrayValueOpenTerm, bvLitOpenTerm, bvTypeOpenTerm, pairOpenTerm, pairTypeOpenTerm, pairLeftOpenTerm, pairRightOpenTerm, tupleOpenTerm, tupleTypeOpenTerm, projTupleOpenTerm, ctorOpenTerm, dataTypeOpenTerm, globalOpenTerm, @@ -36,6 +38,7 @@ module Verifier.SAW.OpenTerm ( lambdaOpenTermAuxM, piOpenTermAuxM ) where +import qualified Data.Vector as V import Control.Monad import Control.Monad.IO.Class import Data.Text (Text) @@ -95,6 +98,39 @@ stringLitOpenTerm = flatOpenTerm . StringLit stringTypeOpenTerm :: OpenTerm stringTypeOpenTerm = globalOpenTerm "Prelude.String" +-- | The 'True' value as a SAW core term +trueOpenTerm :: OpenTerm +trueOpenTerm = globalOpenTerm "Prelude.True" + +-- | The 'False' value as a SAW core term +falseOpenTerm :: OpenTerm +falseOpenTerm = globalOpenTerm "Prelude.False" + +-- | Convert a 'Bool' to a SAW core term +boolOpenTerm :: Bool -> OpenTerm +boolOpenTerm True = globalOpenTerm "Prelude.True" +boolOpenTerm False = globalOpenTerm "Prelude.False" + +-- | The 'Bool' type as a SAW core term +boolTypeOpenTerm :: OpenTerm +boolTypeOpenTerm = globalOpenTerm "Prelude.Bool" + +-- | Build an 'OpenTerm' for an array literal +arrayValueOpenTerm :: OpenTerm -> [OpenTerm] -> OpenTerm +arrayValueOpenTerm tp elems = + flatOpenTerm $ ArrayValue tp $ V.fromList elems + +-- | Create a SAW core term for a bitvector literal +bvLitOpenTerm :: [Bool] -> OpenTerm +bvLitOpenTerm bits = + arrayValueOpenTerm boolTypeOpenTerm $ map boolOpenTerm bits + +-- | Create a SAW core term for the type of a bitvector +bvTypeOpenTerm :: Integral a => a -> OpenTerm +bvTypeOpenTerm n = + applyOpenTermMulti (globalOpenTerm "Prelude.Vec") + [natOpenTerm (fromIntegral n), boolTypeOpenTerm] + -- | Build an 'OpenTerm' for a pair pairOpenTerm :: OpenTerm -> OpenTerm -> OpenTerm pairOpenTerm t1 t2 = flatOpenTerm $ PairValue t1 t2 From 27527233c0a0bba037dfd2039dd7fde82ec47127 Mon Sep 17 00:00:00 2001 From: Eddy Westbrook Date: Tue, 7 Sep 2021 17:20:25 -0700 Subject: [PATCH 16/98] added llvmReadBlockOfShape --- .../src/Verifier/SAW/Heapster/Permissions.hs | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/heapster-saw/src/Verifier/SAW/Heapster/Permissions.hs b/heapster-saw/src/Verifier/SAW/Heapster/Permissions.hs index a7c41f5a3c..f382015b4c 100644 --- a/heapster-saw/src/Verifier/SAW/Heapster/Permissions.hs +++ b/heapster-saw/src/Verifier/SAW/Heapster/Permissions.hs @@ -3383,6 +3383,20 @@ llvmBlockPtrPerm :: (1 <= w, KnownNat w) => LLVMBlockPerm w -> ValuePerm (LLVMPointerType w) llvmBlockPtrPerm bp = ValPerm_Conj1 $ llvmBlockPtrAtomicPerm bp +-- | Create a read block permission with shape @sh@, i.e., the 'LLVMBlockPerm' +-- corresponding to the permission @memblock(R,0,'llvmShapeLength'(sh),sh)@ +llvmReadBlockOfShape :: (1 <= w, KnownNat w) => PermExpr (LLVMShapeType w) -> + LLVMBlockPerm w +llvmReadBlockOfShape sh + | Just len <- llvmShapeLength sh = + LLVMBlockPerm { llvmBlockRW = PExpr_Read, + llvmBlockLifetime = PExpr_Always, + llvmBlockOffset = bvInt 0, + llvmBlockLen = len, + llvmBlockShape = sh } +llvmReadBlockOfShape _ = + error "llvmReadBlockOfShape: shape without known length" + -- | Add the given read/write and lifetime modalities to all top-level pointer -- shapes in a shape. Top-level here means we do not recurse inside pointer -- shapes, as pointer shape modalities also apply recursively to the contained From 92d04e152f87b176cc73812abe6bb77485089d53 Mon Sep 17 00:00:00 2001 From: Eddy Westbrook Date: Tue, 7 Sep 2021 17:20:43 -0700 Subject: [PATCH 17/98] more work trying to translate globals --- src/SAWScript/HeapsterBuiltins.hs | 101 +++++++++++++++++++++++++----- 1 file changed, 87 insertions(+), 14 deletions(-) diff --git a/src/SAWScript/HeapsterBuiltins.hs b/src/SAWScript/HeapsterBuiltins.hs index 342b573ebd..ff8fcf0fc6 100644 --- a/src/SAWScript/HeapsterBuiltins.hs +++ b/src/SAWScript/HeapsterBuiltins.hs @@ -9,6 +9,7 @@ {-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE KindSignatures #-} {-# LANGUAGE ImplicitParams #-} +{-# LANGUAGE ViewPatterns #-} module SAWScript.HeapsterBuiltins ( heapster_init_env @@ -48,6 +49,7 @@ module SAWScript.HeapsterBuiltins , heapster_set_debug_level ) where +import Data.Bits import Data.Maybe import qualified Data.Map as Map import Data.String @@ -57,6 +59,7 @@ import Data.IORef import Data.Functor.Product import Control.Lens import Control.Monad +import Control.Monad.Reader import Control.Monad.IO.Class import qualified Control.Monad.Fail as Fail import System.Directory @@ -259,28 +262,98 @@ parseAndInsDef henv nm term_tp term_string = liftIO $ scInsertDef sc mnm term_ident term_tp term return term_ident +type LLVMTransM = ReaderT PermEnv Maybe + +runLLVMTransM :: LLVMTransM a -> PermEnv -> Maybe a +runLLVMTransM = runReaderT + +ppLLVMValue :: L.Value -> String +ppLLVMValue val = + L.withConfig (L.Config True True True) (show $ PPHPJ.nest 2 $ L.ppValue val) + +ppLLVMConstExpr :: L.ConstExpr -> String +ppLLVMConstExpr ce = + L.withConfig (L.Config True True True) (show $ PPHPJ.nest 2 $ L.ppConstExpr ce) + -- | Translate a typed LLVM 'L.Value' to a Heapster permission + translation -- -- FIXME: move this to Permissions.hs -translateLLVMValue :: (1 <= w, KnownNat w) => f w -> L.Type -> L.Value -> - Maybe (ValuePerm (LLVMPointerType w), [OpenTerm]) -translateLLVMValue _ _ _ = - Nothing +translateLLVMValue :: (1 <= w, KnownNat w) => NatRepr w -> L.Type -> L.Value -> + LLVMTransM (PermExpr (LLVMShapeType w), [OpenTerm]) +translateLLVMValue w _ (L.ValSymbol sym) = + do env <- ask + (p, ts) <- lift (lookupGlobalSymbol env (GlobalSymbol sym) w) + return (PExpr_FieldShape (LLVMFieldShape p), ts) +translateLLVMValue _ _ (L.ValPackedStruct []) = return (PExpr_EmptyShape, []) +translateLLVMValue w _ (L.ValPackedStruct elems) = + mapM (translateLLVMTypedValue w) elems >>= \(unzip -> (shs,tss)) -> + return (foldr1 PExpr_SeqShape shs, concat tss) +translateLLVMValue _ _ (L.ValString bytes) = + return (PExpr_ArrayShape (bvInt $ fromIntegral $ length bytes) 1 + [LLVMFieldShape (ValPerm_Exists $ nu $ \(bv :: Name (BVType 8)) -> + ValPerm_Eq $ PExpr_LLVMWord $ PExpr_Var bv)], + [arrayValueOpenTerm (bvTypeOpenTerm (8::Int)) $ + map (\b -> bvLitOpenTerm $ map (testBit b) [7,6..0]) bytes]) +translateLLVMValue w _ (L.ValConstExpr ce) = + translateLLVMConstExpr w ce +translateLLVMValue _ _ v = + trace ("translateLLVMValue cannot handle value:\n" + ++ show (ppLLVMValue v)) + mzero + +-- | Helper function for 'translateLLVMValue' +translateLLVMTypedValue :: (1 <= w, KnownNat w) => NatRepr w -> L.Typed L.Value -> + LLVMTransM (PermExpr (LLVMShapeType w), [OpenTerm]) +translateLLVMTypedValue w (L.Typed tp v) = translateLLVMValue w tp v + +-- | Helper function for 'translateLLVMValue' +translateLLVMConstExpr :: (1 <= w, KnownNat w) => NatRepr w -> L.ConstExpr -> + LLVMTransM (PermExpr (LLVMShapeType w), [OpenTerm]) +translateLLVMConstExpr w (L.ConstGEP _ _ _ (L.Typed tp ptr : ixs)) = + translateLLVMValue w tp ptr >>= \ptr_trans -> + translateLLVMGEP w tp ptr_trans ixs +translateLLVMConstExpr w (L.ConstConv L.BitCast + (L.Typed tp@(L.PtrTo _) v) (L.PtrTo _)) = + -- A bitcast from one LLVM pointer type to another is a no-op for us + translateLLVMValue w tp v +translateLLVMConstExpr _ ce = + trace ("translateLLVMConstExpr cannot handle expr:\n" + ++ show (ppLLVMConstExpr ce)) + mzero + +-- | Helper function for 'translateLLVMValue' +translateLLVMGEP :: (1 <= w, KnownNat w) => NatRepr w -> L.Type -> + (PermExpr (LLVMShapeType w), [OpenTerm]) -> + [L.Typed L.Value] -> + LLVMTransM (PermExpr (LLVMShapeType w), [OpenTerm]) +translateLLVMGEP _ _ vtrans [] = return vtrans +translateLLVMGEP w (L.Array _ tp) vtrans (L.Typed _ (L.ValInteger 0) : ixs) = + translateLLVMGEP w tp vtrans ixs +translateLLVMGEP w (L.PtrTo tp) vtrans (L.Typed _ (L.ValInteger 0) : ixs) = + translateLLVMGEP w tp vtrans ixs +translateLLVMGEP w (L.PackedStruct [tp]) vtrans (L.Typed _ (L.ValInteger 0) : ixs) = + translateLLVMGEP w tp vtrans ixs +translateLLVMGEP _ _ _ _ = mzero -- | Add an LLVM global constant to a 'PermEnv', if the global has a type and -- value we can translate to Heapster, otherwise silently ignore it -- -- FIXME: move this to Permissions.hs -permEnvAddGlobalConst :: (1 <= w, KnownNat w) => f w -> PermEnv -> - L.Global -> PermEnv -permEnvAddGlobalConst w env global = - trace ("Global: " ++ show (L.globalSym global) ++ "; value =\n" ++ - maybe "None" (L.withConfig - (L.Config True True True) - (\v -> show $ PPHPJ.nest 2 $ L.ppValue v)) (L.globalValue global)) $ +permEnvAddGlobalConst :: (1 <= w, KnownNat w) => NatRepr w -> L.Global -> + PermEnv -> PermEnv +permEnvAddGlobalConst w global env = + let sym = show (L.globalSym global) in + trace ("Global: " ++ sym ++ "; value =\n" ++ + maybe "None" ppLLVMValue + (L.globalValue global)) $ maybe env id $ - do val <- L.globalValue global - (p, ts) <- translateLLVMValue w (L.globalType global) val + (\x -> case x of + Just _ -> trace (sym ++ " translated") x + Nothing -> trace (sym ++ " not translated") x) $ + flip runLLVMTransM env $ + do val <- lift $ L.globalValue global + (sh, ts) <- translateLLVMValue w (L.globalType global) val + let p = ValPerm_LLVMBlock $ llvmReadBlockOfShape sh return $ permEnvAddGlobalSyms env [PermEnvGlobalEntry (GlobalSymbol $ L.globalSym global) p ts] @@ -296,7 +369,7 @@ mkHeapsterEnv saw_mod_name llvm_mods@(Some first_mod:_) = let globals = concatMap (\(Some lm) -> L.modGlobals $ modAST lm) llvm_mods env = withKnownNat w $ withLeqProof leq_proof $ - foldl (permEnvAddGlobalConst w) heapster_default_env globals + foldr (permEnvAddGlobalConst w) heapster_default_env globals env_ref <- liftIO $ newIORef env dlevel_ref <- liftIO $ newIORef noDebugLevel return $ HeapsterEnv { From 4f911f7d67263913e5dce21a6adce75ea269269b Mon Sep 17 00:00:00 2001 From: Eddy Westbrook Date: Wed, 8 Sep 2021 10:54:45 -0700 Subject: [PATCH 18/98] got string literals translated, but now there is some translation bug... --- src/SAWScript/HeapsterBuiltins.hs | 86 +++++++++++++++++++++++++++---- 1 file changed, 75 insertions(+), 11 deletions(-) diff --git a/src/SAWScript/HeapsterBuiltins.hs b/src/SAWScript/HeapsterBuiltins.hs index ff8fcf0fc6..c9b683bb30 100644 --- a/src/SAWScript/HeapsterBuiltins.hs +++ b/src/SAWScript/HeapsterBuiltins.hs @@ -280,25 +280,60 @@ ppLLVMConstExpr ce = -- FIXME: move this to Permissions.hs translateLLVMValue :: (1 <= w, KnownNat w) => NatRepr w -> L.Type -> L.Value -> LLVMTransM (PermExpr (LLVMShapeType w), [OpenTerm]) +translateLLVMValue w tp@(L.PrimType (L.Integer n)) (L.ValInteger i) = + translateLLVMType w tp >>= \(sh,_) -> + return (sh, [bvLitOpenTerm $ map (testBit i) $ + reverse [0..(fromIntegral n)-1]]) translateLLVMValue w _ (L.ValSymbol sym) = do env <- ask - (p, ts) <- lift (lookupGlobalSymbol env (GlobalSymbol sym) w) + -- (p, ts) <- lift (lookupGlobalSymbol env (GlobalSymbol sym) w) + (p, ts) <- case (lookupGlobalSymbol env (GlobalSymbol sym) w) of + Just p_ts -> return p_ts + Nothing -> trace ("Could not find symbol: " ++ show sym) mzero return (PExpr_FieldShape (LLVMFieldShape p), ts) +translateLLVMValue w _ (L.ValArray tp elems) = + do + -- First, translate the elements + transs <- mapM (translateLLVMValue w tp) elems + -- For now, we require each element to translate to exactly one term + ts <- forM transs (\etrans -> case etrans of + (_, [t]) -> return t + _ -> mzero) + -- Array shapes can only handle field shapes elements, so translate the + -- element type to and ensure it returns a field shape; FIXME: this could + -- actually handle sequences of field shapes if necessary + (sh, saw_tp) <- translateLLVMType w tp + fsh <- case sh of + PExpr_FieldShape fsh -> return fsh + _ -> mzero + -- Compute the array stride as the length of the element shape + sh_len_expr <- lift $ llvmShapeLength sh + sh_len <- fromInteger <$> lift (bvMatchConstInt sh_len_expr) + + -- Finally, build our array shape and SAW core value + return (PExpr_ArrayShape (bvInt $ fromIntegral $ length elems) sh_len [fsh], + [arrayValueOpenTerm saw_tp ts]) translateLLVMValue _ _ (L.ValPackedStruct []) = return (PExpr_EmptyShape, []) translateLLVMValue w _ (L.ValPackedStruct elems) = mapM (translateLLVMTypedValue w) elems >>= \(unzip -> (shs,tss)) -> return (foldr1 PExpr_SeqShape shs, concat tss) -translateLLVMValue _ _ (L.ValString bytes) = +translateLLVMValue w tp (L.ValString bytes) = + translateLLVMValue w tp (L.ValArray + (L.PrimType (L.Integer 8)) + (map (L.ValInteger . toInteger) bytes)) + {- return (PExpr_ArrayShape (bvInt $ fromIntegral $ length bytes) 1 [LLVMFieldShape (ValPerm_Exists $ nu $ \(bv :: Name (BVType 8)) -> ValPerm_Eq $ PExpr_LLVMWord $ PExpr_Var bv)], [arrayValueOpenTerm (bvTypeOpenTerm (8::Int)) $ map (\b -> bvLitOpenTerm $ map (testBit b) [7,6..0]) bytes]) +-} translateLLVMValue w _ (L.ValConstExpr ce) = translateLLVMConstExpr w ce +translateLLVMValue w tp L.ValZeroInit = + llvmZeroInitValue tp >>= translateLLVMValue w tp translateLLVMValue _ _ v = - trace ("translateLLVMValue cannot handle value:\n" - ++ show (ppLLVMValue v)) + trace ("translateLLVMValue does not yet handle:\n" ++ ppLLVMValue v) mzero -- | Helper function for 'translateLLVMValue' @@ -306,6 +341,22 @@ translateLLVMTypedValue :: (1 <= w, KnownNat w) => NatRepr w -> L.Typed L.Value LLVMTransM (PermExpr (LLVMShapeType w), [OpenTerm]) translateLLVMTypedValue w (L.Typed tp v) = translateLLVMValue w tp v +-- | Translate an LLVM type into a shape plus the SAW core type of elements of +-- the translation of that shape +translateLLVMType :: (1 <= w, KnownNat w) => NatRepr w -> L.Type -> + LLVMTransM (PermExpr (LLVMShapeType w), OpenTerm) +translateLLVMType _ (L.PrimType (L.Integer n)) + | Just (Some (n_repr :: NatRepr n)) <- someNat n + , Left leq_pf <- decideLeq (knownNat @1) n_repr = + withKnownNat n_repr $ withLeqProof leq_pf $ + return (PExpr_FieldShape (LLVMFieldShape $ ValPerm_Exists $ nu $ \bv -> + ValPerm_Eq $ PExpr_LLVMWord $ + PExpr_Var (bv :: Name (BVType n))), + (bvTypeOpenTerm n)) +translateLLVMType _ tp = + trace ("translateLLVMType does not yet handle:\n" ++ show (L.ppType tp)) + mzero + -- | Helper function for 'translateLLVMValue' translateLLVMConstExpr :: (1 <= w, KnownNat w) => NatRepr w -> L.ConstExpr -> LLVMTransM (PermExpr (LLVMShapeType w), [OpenTerm]) @@ -317,8 +368,7 @@ translateLLVMConstExpr w (L.ConstConv L.BitCast -- A bitcast from one LLVM pointer type to another is a no-op for us translateLLVMValue w tp v translateLLVMConstExpr _ ce = - trace ("translateLLVMConstExpr cannot handle expr:\n" - ++ show (ppLLVMConstExpr ce)) + trace ("translateLLVMConstExpr does not yet handle:\n" ++ ppLLVMConstExpr ce) mzero -- | Helper function for 'translateLLVMValue' @@ -333,15 +383,29 @@ translateLLVMGEP w (L.PtrTo tp) vtrans (L.Typed _ (L.ValInteger 0) : ixs) = translateLLVMGEP w tp vtrans ixs translateLLVMGEP w (L.PackedStruct [tp]) vtrans (L.Typed _ (L.ValInteger 0) : ixs) = translateLLVMGEP w tp vtrans ixs -translateLLVMGEP _ _ _ _ = mzero +translateLLVMGEP _ tp _ ixs = + trace ("translateLLVMGEP cannot handle arguments:\n" ++ + " " ++ intercalate "," (show tp : map show ixs)) + mzero + +-- | Build an LLVM value for a @zeroinitializer@ field of the supplied type +llvmZeroInitValue :: L.Type -> LLVMTransM (L.Value) +llvmZeroInitValue (L.PrimType (L.Integer _)) = return $ L.ValInteger 0 +llvmZeroInitValue (L.Array len tp) = + L.ValArray tp <$> replicate (fromIntegral len) <$> llvmZeroInitValue tp +llvmZeroInitValue (L.PackedStruct tps) = + L.ValPackedStruct <$> zipWith L.Typed tps <$> mapM llvmZeroInitValue tps +llvmZeroInitValue tp = + trace ("llvmZeroInitValue cannot handle type:\n" ++ show (L.ppType tp)) + mzero -- | Add an LLVM global constant to a 'PermEnv', if the global has a type and -- value we can translate to Heapster, otherwise silently ignore it -- -- FIXME: move this to Permissions.hs -permEnvAddGlobalConst :: (1 <= w, KnownNat w) => NatRepr w -> L.Global -> - PermEnv -> PermEnv -permEnvAddGlobalConst w global env = +permEnvAddGlobalConst :: (1 <= w, KnownNat w) => NatRepr w -> + PermEnv -> L.Global -> PermEnv +permEnvAddGlobalConst w env global = let sym = show (L.globalSym global) in trace ("Global: " ++ sym ++ "; value =\n" ++ maybe "None" ppLLVMValue @@ -369,7 +433,7 @@ mkHeapsterEnv saw_mod_name llvm_mods@(Some first_mod:_) = let globals = concatMap (\(Some lm) -> L.modGlobals $ modAST lm) llvm_mods env = withKnownNat w $ withLeqProof leq_proof $ - foldr (permEnvAddGlobalConst w) heapster_default_env globals + foldl (permEnvAddGlobalConst w) heapster_default_env globals env_ref <- liftIO $ newIORef env dlevel_ref <- liftIO $ newIORef noDebugLevel return $ HeapsterEnv { From 64d3006fef98b551172cebedfaa09ff24f2f224c Mon Sep 17 00:00:00 2001 From: Eddy Westbrook Date: Wed, 8 Sep 2021 12:40:16 -0700 Subject: [PATCH 19/98] whoops, translating a shape always yields exactly one term --- src/SAWScript/HeapsterBuiltins.hs | 38 ++++++++++++++----------------- 1 file changed, 17 insertions(+), 21 deletions(-) diff --git a/src/SAWScript/HeapsterBuiltins.hs b/src/SAWScript/HeapsterBuiltins.hs index c9b683bb30..162e5e72aa 100644 --- a/src/SAWScript/HeapsterBuiltins.hs +++ b/src/SAWScript/HeapsterBuiltins.hs @@ -279,26 +279,23 @@ ppLLVMConstExpr ce = -- -- FIXME: move this to Permissions.hs translateLLVMValue :: (1 <= w, KnownNat w) => NatRepr w -> L.Type -> L.Value -> - LLVMTransM (PermExpr (LLVMShapeType w), [OpenTerm]) + LLVMTransM (PermExpr (LLVMShapeType w), OpenTerm) translateLLVMValue w tp@(L.PrimType (L.Integer n)) (L.ValInteger i) = translateLLVMType w tp >>= \(sh,_) -> - return (sh, [bvLitOpenTerm $ map (testBit i) $ - reverse [0..(fromIntegral n)-1]]) + return (sh, bvLitOpenTerm (map (testBit i) $ + reverse [0..(fromIntegral n)-1])) translateLLVMValue w _ (L.ValSymbol sym) = do env <- ask -- (p, ts) <- lift (lookupGlobalSymbol env (GlobalSymbol sym) w) - (p, ts) <- case (lookupGlobalSymbol env (GlobalSymbol sym) w) of - Just p_ts -> return p_ts + (p, t) <- case (lookupGlobalSymbol env (GlobalSymbol sym) w) of + Just (p,[t]) -> return (p,t) + Just (p,ts) -> return (p,tupleOpenTerm ts) Nothing -> trace ("Could not find symbol: " ++ show sym) mzero - return (PExpr_FieldShape (LLVMFieldShape p), ts) + return (PExpr_FieldShape (LLVMFieldShape p), t) translateLLVMValue w _ (L.ValArray tp elems) = do -- First, translate the elements - transs <- mapM (translateLLVMValue w tp) elems - -- For now, we require each element to translate to exactly one term - ts <- forM transs (\etrans -> case etrans of - (_, [t]) -> return t - _ -> mzero) + ts <- map snd <$> mapM (translateLLVMValue w tp) elems -- Array shapes can only handle field shapes elements, so translate the -- element type to and ensure it returns a field shape; FIXME: this could -- actually handle sequences of field shapes if necessary @@ -312,11 +309,10 @@ translateLLVMValue w _ (L.ValArray tp elems) = -- Finally, build our array shape and SAW core value return (PExpr_ArrayShape (bvInt $ fromIntegral $ length elems) sh_len [fsh], - [arrayValueOpenTerm saw_tp ts]) -translateLLVMValue _ _ (L.ValPackedStruct []) = return (PExpr_EmptyShape, []) + arrayValueOpenTerm saw_tp ts) translateLLVMValue w _ (L.ValPackedStruct elems) = - mapM (translateLLVMTypedValue w) elems >>= \(unzip -> (shs,tss)) -> - return (foldr1 PExpr_SeqShape shs, concat tss) + mapM (translateLLVMTypedValue w) elems >>= \(unzip -> (shs,ts)) -> + return (foldr PExpr_SeqShape PExpr_EmptyShape shs, tupleOpenTerm ts) translateLLVMValue w tp (L.ValString bytes) = translateLLVMValue w tp (L.ValArray (L.PrimType (L.Integer 8)) @@ -338,7 +334,7 @@ translateLLVMValue _ _ v = -- | Helper function for 'translateLLVMValue' translateLLVMTypedValue :: (1 <= w, KnownNat w) => NatRepr w -> L.Typed L.Value -> - LLVMTransM (PermExpr (LLVMShapeType w), [OpenTerm]) + LLVMTransM (PermExpr (LLVMShapeType w), OpenTerm) translateLLVMTypedValue w (L.Typed tp v) = translateLLVMValue w tp v -- | Translate an LLVM type into a shape plus the SAW core type of elements of @@ -359,7 +355,7 @@ translateLLVMType _ tp = -- | Helper function for 'translateLLVMValue' translateLLVMConstExpr :: (1 <= w, KnownNat w) => NatRepr w -> L.ConstExpr -> - LLVMTransM (PermExpr (LLVMShapeType w), [OpenTerm]) + LLVMTransM (PermExpr (LLVMShapeType w), OpenTerm) translateLLVMConstExpr w (L.ConstGEP _ _ _ (L.Typed tp ptr : ixs)) = translateLLVMValue w tp ptr >>= \ptr_trans -> translateLLVMGEP w tp ptr_trans ixs @@ -373,9 +369,9 @@ translateLLVMConstExpr _ ce = -- | Helper function for 'translateLLVMValue' translateLLVMGEP :: (1 <= w, KnownNat w) => NatRepr w -> L.Type -> - (PermExpr (LLVMShapeType w), [OpenTerm]) -> + (PermExpr (LLVMShapeType w), OpenTerm) -> [L.Typed L.Value] -> - LLVMTransM (PermExpr (LLVMShapeType w), [OpenTerm]) + LLVMTransM (PermExpr (LLVMShapeType w), OpenTerm) translateLLVMGEP _ _ vtrans [] = return vtrans translateLLVMGEP w (L.Array _ tp) vtrans (L.Typed _ (L.ValInteger 0) : ixs) = translateLLVMGEP w tp vtrans ixs @@ -416,10 +412,10 @@ permEnvAddGlobalConst w env global = Nothing -> trace (sym ++ " not translated") x) $ flip runLLVMTransM env $ do val <- lift $ L.globalValue global - (sh, ts) <- translateLLVMValue w (L.globalType global) val + (sh, t) <- translateLLVMValue w (L.globalType global) val let p = ValPerm_LLVMBlock $ llvmReadBlockOfShape sh return $ permEnvAddGlobalSyms env - [PermEnvGlobalEntry (GlobalSymbol $ L.globalSym global) p ts] + [PermEnvGlobalEntry (GlobalSymbol $ L.globalSym global) p [t]] -- | Build a 'HeapsterEnv' associated with the given SAW core module and the -- given 'LLVMModule's. Add any globals in the 'LLVMModule's to the returned From 01074a96753aac2fbeeff8482b8b595eb1979f65 Mon Sep 17 00:00:00 2001 From: Eddy Westbrook Date: Wed, 8 Sep 2021 17:32:55 -0700 Subject: [PATCH 20/98] added helper function exprLLVMTypeBytes --- heapster-saw/src/Verifier/SAW/Heapster/Permissions.hs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/heapster-saw/src/Verifier/SAW/Heapster/Permissions.hs b/heapster-saw/src/Verifier/SAW/Heapster/Permissions.hs index f382015b4c..ce43c842a3 100644 --- a/heapster-saw/src/Verifier/SAW/Heapster/Permissions.hs +++ b/heapster-saw/src/Verifier/SAW/Heapster/Permissions.hs @@ -631,6 +631,11 @@ exprLLVMTypeWidth _ = knownNat shapeLLVMTypeWidth :: KnownNat w => f (LLVMShapeType w) -> NatRepr w shapeLLVMTypeWidth _ = knownNat +-- | Convenience function to get the number of bytes = the bit width divided by +-- 8 of an LLVM pointer type +exprLLVMTypeBytes :: KnownNat w => f (LLVMPointerType w) -> Integer +exprLLVMTypeBytes e = intValue (exprLLVMTypeWidth e) `div` 8 + -- | Convenience function to get the number of bytes = the bit width divided by -- 8 of an LLVM pointer type as an expr. Note that this assumes the bit width is -- a multiple of 8, so does not worry about rounding. From d2b4a22a86f56fd7a20f2c56744fd456657f47d9 Mon Sep 17 00:00:00 2001 From: Eddy Westbrook Date: Wed, 8 Sep 2021 17:33:21 -0700 Subject: [PATCH 21/98] added support for Rust slice types --- .../src/Verifier/SAW/Heapster/RustTypes.hs | 50 +++++++++++++++++-- 1 file changed, 47 insertions(+), 3 deletions(-) diff --git a/heapster-saw/src/Verifier/SAW/Heapster/RustTypes.hs b/heapster-saw/src/Verifier/SAW/Heapster/RustTypes.hs index f7c3d319cc..f1b34e9784 100644 --- a/heapster-saw/src/Verifier/SAW/Heapster/RustTypes.hs +++ b/heapster-saw/src/Verifier/SAW/Heapster/RustTypes.hs @@ -59,6 +59,7 @@ import Language.Rust.Data.Ident (Ident(..), name) import Prettyprinter as PP import Lang.Crucible.Types +import Lang.Crucible.LLVM.Bytes import Lang.Crucible.LLVM.MemModel hiding (Mutability(..)) import Verifier.SAW.Heapster.CruUtil @@ -327,6 +328,21 @@ withRecType rust_n rust_ns rec_n = local (\info -> info { rciRecType = Just (rus -- * Converting Rust Types to Heapster Shapes ---------------------------------------------------------------------- +-- | Test if a shape matches the translation of a slice type, and, if so, return +-- the stride and the fields of the slice, where the latter can have the length +-- free +matchSliceShape :: PermExpr (LLVMShapeType w) -> + Maybe (Bytes, Binding (BVType w) [LLVMFieldShape w]) +matchSliceShape (PExpr_ExShape + [nuP| PExpr_ArrayShape (PExpr_Var len) stride fshs |]) + | Left Member_Base <- mbNameBoundP len = + Just (mbLift stride, fshs) +matchSliceShape (PExpr_NamedShape _ _ nmsh@(NamedShape _ _ + (DefinedShapeBody _)) args) = + matchSliceShape (unfoldNamedShape nmsh args) +matchSliceShape _ = Nothing + + instance RsConvert w Mutability (PermExpr RWModalityType) where rsConvert _ Mutable = return PExpr_Write rsConvert _ Immutable = return PExpr_Read @@ -352,12 +368,40 @@ instance RsConvert w [PathParameters Span] (Some TypedPermExprs) where foldr appendTypedExprs emptyTypedPermExprs <$> mapM (rsConvert w) paramss instance RsConvert w (Ty Span) (PermExpr (LLVMShapeType w)) where - rsConvert _ (Rptr _ _ (Slice _ _) _) = - error "FIXME: pointers to slice types are not currently supported" + rsConvert w (Slice tp _) = + do sh <- rsConvert w tp + case sh of + PExpr_FieldShape fsh@(LLVMFieldShape p) -> + return (PExpr_ExShape $ nu $ \n -> + PExpr_ArrayShape (PExpr_Var n) + (fromIntegral $ exprLLVMTypeBytes p) + [fsh]) + _ -> fail "rsConvert: slices of compound types not yet supported" + rsConvert _ (Rptr Nothing _ _ _) = + fail "rsConvert: lifetimes must be supplied for reference types" rsConvert w (Rptr (Just rust_l) Mutable tp' _) = do l <- rsConvert w rust_l sh <- rsConvert w tp' - return $ PExpr_PtrShape Nothing (Just l) sh + case sh of + -- Test if sh is a slice type = an array of existential length + (matchSliceShape -> Just (stride,fshs)) -> + -- If so, build a "fat pointer" = a pair of a pointer to our array + -- shape plus a length value + return $ PExpr_ExShape $ nu $ \n -> + PExpr_SeqShape (PExpr_PtrShape Nothing Nothing $ + PExpr_ArrayShape (PExpr_Var n) stride $ + subst1 (PExpr_Var n) fshs) + (PExpr_FieldShape $ LLVMFieldShape $ ValPerm_Eq $ + PExpr_LLVMWord $ PExpr_Var n) + + -- If it's not a slice, make sure it has a known size + _ | Just len <- llvmShapeLength sh + , isJust (bvMatchConst len) -> + return $ PExpr_PtrShape Nothing (Just l) sh + + -- Otherwise, it's a non-standard dynamically-sized type, which we + -- don't quite know how to handle yet... + _ -> fail "rsConvert: pointer to non-slice dynamically-sized type" rsConvert w (Rptr (Just rust_l) Immutable tp' _) = do l <- rsConvert w rust_l sh <- rsConvert w tp' From 3941cdb867d40072b24ad384625fac6875e46a19 Mon Sep 17 00:00:00 2001 From: Eddy Westbrook Date: Thu, 9 Sep 2021 06:04:18 -0700 Subject: [PATCH 22/98] whoops, combined the two cases for translating shared vs mutable references into one --- .../src/Verifier/SAW/Heapster/RustTypes.hs | 21 +++++++++---------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/heapster-saw/src/Verifier/SAW/Heapster/RustTypes.hs b/heapster-saw/src/Verifier/SAW/Heapster/RustTypes.hs index f1b34e9784..9ef8f736cf 100644 --- a/heapster-saw/src/Verifier/SAW/Heapster/RustTypes.hs +++ b/heapster-saw/src/Verifier/SAW/Heapster/RustTypes.hs @@ -342,10 +342,12 @@ matchSliceShape (PExpr_NamedShape _ _ nmsh@(NamedShape _ _ matchSliceShape (unfoldNamedShape nmsh args) matchSliceShape _ = Nothing - -instance RsConvert w Mutability (PermExpr RWModalityType) where - rsConvert _ Mutable = return PExpr_Write - rsConvert _ Immutable = return PExpr_Read +-- Convert a 'Mutability' to a modality override for a 'PExpr_PtrShape'; mutable +-- references inherit the modality of the container they are in, so they +-- translate to 'Nothing' +instance RsConvert w Mutability (Maybe (PermExpr RWModalityType)) where + rsConvert _ Mutable = return Nothing + rsConvert _ Immutable = return (Just PExpr_Read) instance RsConvert w (Lifetime Span) (PermExpr LifetimeType) where rsConvert _ (Lifetime "static" _) = return PExpr_Always @@ -379,16 +381,17 @@ instance RsConvert w (Ty Span) (PermExpr (LLVMShapeType w)) where _ -> fail "rsConvert: slices of compound types not yet supported" rsConvert _ (Rptr Nothing _ _ _) = fail "rsConvert: lifetimes must be supplied for reference types" - rsConvert w (Rptr (Just rust_l) Mutable tp' _) = + rsConvert w (Rptr (Just rust_l) mut tp' _) = do l <- rsConvert w rust_l sh <- rsConvert w tp' + rw <- rsConvert w mut case sh of -- Test if sh is a slice type = an array of existential length (matchSliceShape -> Just (stride,fshs)) -> -- If so, build a "fat pointer" = a pair of a pointer to our array -- shape plus a length value return $ PExpr_ExShape $ nu $ \n -> - PExpr_SeqShape (PExpr_PtrShape Nothing Nothing $ + PExpr_SeqShape (PExpr_PtrShape rw Nothing $ PExpr_ArrayShape (PExpr_Var n) stride $ subst1 (PExpr_Var n) fshs) (PExpr_FieldShape $ LLVMFieldShape $ ValPerm_Eq $ @@ -397,15 +400,11 @@ instance RsConvert w (Ty Span) (PermExpr (LLVMShapeType w)) where -- If it's not a slice, make sure it has a known size _ | Just len <- llvmShapeLength sh , isJust (bvMatchConst len) -> - return $ PExpr_PtrShape Nothing (Just l) sh + return $ PExpr_PtrShape rw (Just l) sh -- Otherwise, it's a non-standard dynamically-sized type, which we -- don't quite know how to handle yet... _ -> fail "rsConvert: pointer to non-slice dynamically-sized type" - rsConvert w (Rptr (Just rust_l) Immutable tp' _) = - do l <- rsConvert w rust_l - sh <- rsConvert w tp' - return $ PExpr_PtrShape (Just PExpr_Read) (Just l) sh rsConvert w (PathTy Nothing path _) = do mrec <- asks rciRecType case mrec of From 2982d1f8272b326f7177cbf16b9872b915e6930a Mon Sep 17 00:00:00 2001 From: Eddy Westbrook Date: Thu, 9 Sep 2021 07:14:42 -0700 Subject: [PATCH 23/98] updated funPerm3FromArgLayout to handle layouts with existential permissions --- .../src/Verifier/SAW/Heapster/RustTypes.hs | 62 +++++++++++++------ 1 file changed, 43 insertions(+), 19 deletions(-) diff --git a/heapster-saw/src/Verifier/SAW/Heapster/RustTypes.hs b/heapster-saw/src/Verifier/SAW/Heapster/RustTypes.hs index 9ef8f736cf..267d4094bd 100644 --- a/heapster-saw/src/Verifier/SAW/Heapster/RustTypes.hs +++ b/heapster-saw/src/Verifier/SAW/Heapster/RustTypes.hs @@ -726,6 +726,46 @@ un3SomeFunPerm args ret (Some3FunPerm fun_perm) = <+> pretty "=>" <+> PP.group (permPretty emptyPPInfo (funPermRet fun_perm)) ] +-- | This is the more general form of 'funPerm3FromArgLayout, where there can be +-- ghost variables in the 'ArgLayout' +funPerm3FromMbArgLayout :: CtxRepr ctx -> + MatchedMb ghosts (ArgLayoutPerm ctx) -> + CruCtx ghosts -> CtxRepr args -> + ValuePerms (CtxToRList args) -> + ValuePerms (CtxToRList args) -> + TypeRepr ret -> ValuePerm ret -> + RustConvM Some3FunPerm + +-- Special case: if the argument perms are just a sequence of permissions on the +-- individual arguments, make a function perm with those argument perms, that +-- is, we build the function permission +-- +-- (ghosts). arg1:p1, ..., argn:pn -o ret:ret_perm +funPerm3FromMbArgLayout ctx [nuMP| ALPerm mb_ps_in |] + ghosts ctx1 ps1_in ps1_out ret_tp ret_perm + | ctx_args <- mkCruCtx (ctx1 Ctx.<++> ctx) + , ctx_all <- appendCruCtx ghosts ctx_args + , ghost_perms <- trueValuePerms $ cruCtxProxies ghosts + , mb_ps_in_all <- + mbCombine (cruCtxProxies ctx_args) $ + fmap (\ps_in -> + nuMulti (cruCtxProxies ctx_args) $ const $ + RL.append ghost_perms + (assignToRListAppend ctx1 ctx ps1_in ps_in)) mb_ps_in + , ps_out_all <- + RL.append ghost_perms (assignToRListAppend ctx1 ctx ps1_out $ + trueValuePerms $ assignToRList ctx) :>: ret_perm = + return $ Some3FunPerm $ FunPerm ghosts ctx_args ret_tp mb_ps_in_all + (nuMulti (cruCtxProxies ctx_all :>: Proxy) $ \_ -> ps_out_all) +funPerm3FromMbArgLayout ctx [nuMP| ALPerm_Exists mb_p |] + ghosts ctx1 ps1_in ps1_out ret_tp ret_perm = + funPerm3FromMbArgLayout ctx (mbMatch $ mbCombine (MNil :>: Proxy) mb_p) + (CruCtxCons ghosts knownRepr) ctx1 ps1_in ps1_out ret_tp ret_perm +funPerm3FromMbArgLayout _ctx [nuMP| ALPerm_Or _ _ |] + _ghosts _ctx1 _ps1_in _ps1_out _ret_tp _ret_perm = + fail "Cannot (yet) handle Rust enums or other disjunctive types in functions" + + -- | Build a function permission from an 'ArgLayout' that describes the -- arguments and their input permissions and a return permission that describes -- the output permissions on the return value. The arguments specified by the @@ -738,25 +778,9 @@ funPerm3FromArgLayout :: ArgLayout -> CtxRepr args -> ValuePerms (CtxToRList args) -> TypeRepr ret -> ValuePerm ret -> RustConvM Some3FunPerm -funPerm3FromArgLayout (ArgLayout ctx p_in) ctx1 ps1_in ps1_out ret_tp ret_perm - -- Special case: if the argument perms are just a sequence of permissions on - -- the individual arguments, make a function perm with those argument perms, - -- that is, we build the function permission - -- - -- (). arg1:p1, ..., argn:pn -o ret:ret_perm - | ALPerm ps_in <- p_in - , ctx_all <- mkCruCtx (ctx1 Ctx.<++> ctx) - , ps_in_all <- RL.append MNil (assignToRListAppend ctx1 ctx ps1_in ps_in) - , ps_out_all <- - RL.append MNil (assignToRListAppend ctx1 ctx ps1_out $ - trueValuePerms $ assignToRList ctx) :>: ret_perm - , gs_ctx_prxs <- RL.append MNil (cruCtxProxies ctx_all) = - return $ Some3FunPerm $ FunPerm CruCtxNil ctx_all ret_tp - (nuMulti gs_ctx_prxs $ \_ -> ps_in_all) - (nuMulti (gs_ctx_prxs :>: Proxy) $ \_ -> ps_out_all) -funPerm3FromArgLayout (ArgLayout _ctx _p) _ctx1 _p1_in _p1_out _ret_tp _ret_perm = - -- FIXME HERE - fail "Cannot (yet) handle Rust enums or other disjunctive types in functions" +funPerm3FromArgLayout (ArgLayout ctx p_in) ctx1 ps1_in ps1_out ret_tp ret_perm = + funPerm3FromMbArgLayout ctx (mbMatch $ emptyMb p_in) CruCtxNil + ctx1 ps1_in ps1_out ret_tp ret_perm -- | Like 'funPerm3FromArgLayout' but with no additional arguments funPerm3FromArgLayoutNoArgs :: ArgLayout -> TypeRepr ret -> ValuePerm ret -> From 281d602fe0817ce1d5bf0c58dc4b1d71e4a5cadb Mon Sep 17 00:00:00 2001 From: Eddy Westbrook Date: Mon, 13 Sep 2021 14:03:42 -0700 Subject: [PATCH 24/98] updated the rust_data example to use string literals --- heapster-saw/examples/rust_data.bc | Bin 207360 -> 206464 bytes heapster-saw/examples/rust_data.rs | 5 ++++ heapster-saw/examples/rust_data.saw | 35 ++++++++++++++++++++++++---- 3 files changed, 36 insertions(+), 4 deletions(-) diff --git a/heapster-saw/examples/rust_data.bc b/heapster-saw/examples/rust_data.bc index 22392f05c8b140195cafea37da6465ad8c68a58a..6abc2c8f1baaea87d2b6391fc47e19031137c0b2 100644 GIT binary patch delta 93005 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 delta 93556 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 TrueEnum { impl fmt::Display for TrueEnum { fn fmt<'a, 'b>(&'a self, f: &'b mut fmt::Formatter) -> fmt::Result { match self { + TrueEnum::Foo => f.write_str ("Foo"), + TrueEnum::Bar => f.write_str ("Bar"), + TrueEnum::Baz => f.write_str ("Baz"), + /* TrueEnum::Foo => write!(f,"Foo"), TrueEnum::Bar => write!(f,"Bar"), TrueEnum::Baz => write!(f,"Baz"), + */ } } } diff --git a/heapster-saw/examples/rust_data.saw b/heapster-saw/examples/rust_data.saw index 982bdf45b2..6c897879df 100644 --- a/heapster-saw/examples/rust_data.saw +++ b/heapster-saw/examples/rust_data.saw @@ -1,5 +1,6 @@ enable_experimental; env <- heapster_init_env_from_file "rust_data.sawcore" "rust_data.bc"; +heapster_set_debug_level env 1; /*** *** Types @@ -13,6 +14,7 @@ heapster_define_perm env "int1" " " "llvmptr 1" "exists x:bv 1.eq(llvmword(x))"; heapster_define_llvmshape env "u64" 64 "" "fieldsh(int64<>)"; heapster_define_llvmshape env "u32" 64 "" "fieldsh(32,int32<>)"; +heapster_define_llvmshape env "u8" 64 "" "fieldsh(8,int8<>)"; // bool type heapster_define_llvmshape env "bool" 64 "" "fieldsh(1,int1<>)"; @@ -29,11 +31,25 @@ heapster_define_rust_type env "pub enum Sum { Left (X), Right (Y) }"; // The Option type heapster_define_rust_type env "pub enum Option { None, Some (X) }"; +// The str type +heapster_define_llvmshape env "str" 64 "" "exsh len:bv 64.arraysh(len,1,[(8,int8<>)])"; +//heapster_define_rust_type env "type str = [u8];"; + +// The String type +heapster_define_llvmshape env "String" 64 "" "exsh cap:bv 64. ptrsh(arraysh(cap,1,[(8,int8<>)]));fieldsh(int64<>);fieldsh(eq(llvmword(cap)))"; + // List type //heapster_define_llvmshape env "List" 64 "L:perm(llvmptr 64),X:llvmshape 64" "(fieldsh(eq(llvmword(0)))) orsh (fieldsh(eq(llvmword(1)));X;fieldsh(L))"; //heapster_define_recursive_perm env "ListPerm" "X:llvmshape 64, Xlen:bv 64, rw:rwmodality, l:lifetime" "llvmptr 64" ["[l]memblock(rw,0,Xlen + 16,List,X>)"] "\\ (X:sort 0) (_:Vec 64 Bool) -> List X" "\\ (X:sort 0) (_:Vec 64 Bool) -> foldListPermH X" "\\ (X:sort 0) (_:Vec 64 Bool) -> unfoldListPermH X"; heapster_define_rust_type env "pub enum List { Nil, Cons (X,Box>) }"; +// Void type; note that Heapster does not (yet?) support empty types, so instead +// we make this type opaque. Also, note that the ArgumentV1 structure contains +// referens to Void, so presumably they are just casts of other types...? +// +//heapster_define_rust_type env "pub enum Void {}"; +heapster_define_opaque_llvmshape env "Void" 64 "" "64" "#()"; + // fmt::Error type heapster_define_rust_type_qual env "fmt" "pub struct Error { }"; @@ -42,15 +58,19 @@ heapster_define_rust_type_qual env "fmt" "pub struct Error { }"; heapster_define_llvmshape env "fmt::Result" 64 "" "fieldsh(1,eq(llvmword(0))) orsh fieldsh(1,eq(llvmword(1)))"; //heapster_define_rust_type_qual env "fmt" "pub enum Result { Ok (), Err (fmt::Error) }"; -// Formatter type +// fmt::Formatter type heapster_define_opaque_llvmshape env "fmt::Formatter" 64 "" "64" "#()"; +// fmt::ArgumentV1 type +//heapster_define_rust_type_qual env "fmt" "pub struct ArgumentV1<'a> { value: &'a Void, formatter: for <'b> fn(&'b Void, &'b mut fmt::Formatter) -> fmt::Result, }"; + +// fmt::Arguments type +//heapster_define_rust_type_qual env "fmt" "pub struct Arguments<'a> { pieces: &'a [&'a str], fmt: Option<&'a [fmt::Argument]>, args: &'a [fmt::ArgumentV1<'a>], }"; + + // List64 type heapster_define_rust_type env "pub enum List64 { Nil64, Cons64 (u64,Box) }"; -// The String type -heapster_define_llvmshape env "String" 64 "" "exsh cap:bv 64. ptrsh(arraysh(cap,1,[(8,int8<>)]));fieldsh(int64<>);fieldsh(eq(llvmword(cap)))"; - // The TwoValues, ThreeValues, FourValues, and FiveValues types heapster_define_rust_type env "pub struct TwoValues(u32,u32);"; heapster_define_rust_type env "pub struct ThreeValues(u32,u32,u32);"; @@ -124,6 +144,13 @@ heapster_assume_fun_rename_prim env String__fmt_sym "String__fmt" "<'a, 'b> fn(& */ +// Arguments::new_v1 +Arguments__new_v1_sym <- heapster_find_symbol env "3fmt9Arguments6new_v1"; +//heapster_assume_fun_rename_prim env Arguments__new_v1_sym "Arguments__new" "<'a> fn (pieces: &'a [&'a str], args: &'a [ArgumentV1<'a>]) -> Arguments<'a>"; + +// Formatter::write_str +Formatter__write_str_sym <- heapster_find_symbol env "9Formatter9write_str"; +heapster_assume_fun_rename_prim env Formatter__write_str_sym "Formatter__write_str" "<'a,'b> fn (&'a mut fmt::Formatter, &'b str) -> fmt::Result"; /*** From dbb2b9f044b202186ab6921ad09fad123b6f6230 Mon Sep 17 00:00:00 2001 From: Eddy Westbrook Date: Tue, 14 Sep 2021 05:57:10 -0700 Subject: [PATCH 25/98] added mapM and mapBVVecM --- saw-core/prelude/Prelude.sawcore | 40 ++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/saw-core/prelude/Prelude.sawcore b/saw-core/prelude/Prelude.sawcore index 73127d79e2..d25d0971e8 100644 --- a/saw-core/prelude/Prelude.sawcore +++ b/saw-core/prelude/Prelude.sawcore @@ -911,6 +911,10 @@ primitive Vec : Nat -> sort 0 -> sort 0; -- Primitive function for generating an array. primitive gen : (n : Nat) -> (a : sort 0) -> (Nat -> a) -> Vec n a; +-- Primitive eliminators for arrays +primitive head : (n : Nat) -> (a : sort 0) -> Vec (Succ n) a -> a; +primitive tail : (n : Nat) -> (a : sort 0) -> Vec (Succ n) a -> Vec n a; + primitive atWithDefault : (n : Nat) -> (a : sort 0) -> a -> Vec n a -> Nat -> a; at : (n : Nat) -> (a : sort 0) -> Vec n a -> Nat -> a; @@ -1947,6 +1951,24 @@ primitive CompM : sort 0 -> sort 0; primitive returnM : (a:sort 0) -> a -> CompM a; primitive bindM : (a b:sort 0) -> CompM a -> (a -> CompM b) -> CompM b; +-- Apply a pure function to a computation +fmapM : (a b: sort 0) -> (a -> b) -> CompM a -> CompM b; +fmapM a b f m = bindM a b m (\ (x:a) -> returnM b (f x)); + +-- Apply a computation of a function to a computation of an argument +applyM : (a b: sort 0) -> CompM (a -> b) -> CompM a -> CompM b; +applyM a b f m = + bindM (a -> b) b f (\ (f:a->b) -> bindM a b m (\ (x:a) -> returnM b (f x))); + +-- Apply a binary pure function to a computation +fmapM2 : (a b c: sort 0) -> (a -> b -> c) -> CompM a -> CompM b -> CompM c; +fmapM2 a b c f m1 m2 = applyM b c (fmapM a (b -> c) f m1) m2; + +-- Apply a trinary pure function to a computation +fmapM3 : (a b c d: sort 0) -> (a -> b -> c -> d) -> + CompM a -> CompM b -> CompM c -> CompM d; +fmapM3 a b c d f m1 m2 m3 = applyM c d (fmapM2 a b (c -> d) f m1 m2) m3; + -- Compose two monadic functions composeM : (a b c: sort 0) -> (a -> CompM b) -> (b -> CompM c) -> a -> CompM c; composeM a b c f g x = bindM b c (f x) g; @@ -1962,6 +1984,24 @@ tupleCompMFunOut : (a b c: sort 0) -> c -> (a -> CompM b) -> (a -> CompM (c * b) tupleCompMFunOut a b c x f = \ (y:a) -> bindM b (c*b) (f y) (\ (z:b) -> returnM (c*b) (x,z)); +-- Map a monadic function across a vector +mapM : (a b : sort 0) -> (a -> CompM b) -> (n : Nat) -> Vec n a -> CompM (Vec n b); +mapM a b f = + Nat__rec + (\ (n:Nat) -> Vec n a -> CompM (Vec n b)) + (\ (_:Vec 0 a) -> returnM (Vec 0 b) (EmptyVec b)) + (\ (n:Nat) (rec_f:Vec n a -> CompM (Vec n b)) (v:Vec (Succ n) a) -> + fmapM2 b (Vec n b) (Vec (Succ n) b) + (\ (hd:b) (tl:Vec n b) -> ConsVec b hd n tl) + (f (head n a v)) + (rec_f (tail n a v))); + +-- Map a monadic function across a BVVec +mapBVVecM : (a b : sort 0) -> (a -> CompM b) -> + (n : Nat) -> (len : Vec n Bool) -> BVVec n len a -> + CompM (BVVec n len b); +mapBVVecM a b f n len = mapM a b f (bvToNat n len); + -- Raise an error in the computation monad primitive errorM : (a:sort 0) -> String -> CompM a; From 9ae8f7589d3c972f75f57d2900acf07c758d9ddf Mon Sep 17 00:00:00 2001 From: Eddy Westbrook Date: Tue, 14 Sep 2021 06:02:45 -0700 Subject: [PATCH 26/98] added support for proving array permissions from other array permissions with different fields using the SImpl_LLVMArrayContents rule; to get the translation of the SImpl_LLVMArrayContents to work correctly, I had to change local implications to not use strict tuples, which in turn required changing the translation of lowned permissions (which are themselves local implications) to not use strict tuples as well --- .../src/Verifier/SAW/Heapster/Implication.hs | 150 +++++++++----- .../src/Verifier/SAW/Heapster/Permissions.hs | 7 + .../Verifier/SAW/Heapster/SAWTranslation.hs | 190 +++++++++++++----- 3 files changed, 248 insertions(+), 99 deletions(-) diff --git a/heapster-saw/src/Verifier/SAW/Heapster/Implication.hs b/heapster-saw/src/Verifier/SAW/Heapster/Implication.hs index 2a430f012a..adb1169efd 100644 --- a/heapster-saw/src/Verifier/SAW/Heapster/Implication.hs +++ b/heapster-saw/src/Verifier/SAW/Heapster/Implication.hs @@ -647,7 +647,7 @@ data SimplImpl ps_in ps_out where -- > -o x:array(off, - ExprVar (LLVMPointerType w) -> LLVMArrayPerm w -> LLVMArrayPerm w -> + ExprVar (LLVMPointerType w) -> LLVMArrayPerm w -> [LLVMArrayBorrow w] -> SimplImpl (RNil :> LLVMPointerType w) (RNil :> LLVMPointerType w) -- | Convert an array to a field of the same size with @true@ contents: @@ -723,17 +723,18 @@ data SimplImpl ps_in ps_out where SimplImpl (RNil :> LLVMPointerType w :> LLVMPointerType w) (RNil :> LLVMPointerType w) - -- | Apply an implication to the @i@th field of an array permission: + -- | Apply an implication to the fields of an array permission: -- - -- > y:fpi -o y:fpi' + -- > y:fp1 * ... * fpn -o y:fp1' * ... * fpn' -- > ------------------------------------------------ -- > x:array(off, x:array(off, (fp1, ..., fp(i-1), fpi', fp(i+1), ..., fpn),bs) + -- > x:array(off, - ExprVar (LLVMPointerType w) -> LLVMArrayPerm w -> Int -> LLVMArrayField w -> - LocalPermImpl (RNil :> LLVMPointerType w) (RNil :> LLVMPointerType w) -> + ExprVar (LLVMPointerType w) -> LLVMArrayPerm w -> [LLVMArrayField w] -> + Binding (LLVMPointerType w) (LocalPermImpl + (RNil :> LLVMPointerType w) + (RNil :> LLVMPointerType w)) -> SimplImpl (RNil :> LLVMPointerType w) (RNil :> LLVMPointerType w) -- | Prove that @x@ is a pointer from a field permission: @@ -1644,16 +1645,11 @@ simplImplIn (SImpl_LLVMArrayAppend x ap1 ap2) = x (ValPerm_Conj1 $ Perm_LLVMArray ap2) _ -> error "simplImplIn: SImpl_LLVMArrayAppend: arrays cannot be appended" -simplImplIn (SImpl_LLVMArrayRearrange x ap1 ap2) = - if bvEq (llvmArrayOffset ap1) (llvmArrayOffset ap2) && - bvEq (llvmArrayLen ap1) (llvmArrayLen ap2) && - llvmArrayStride ap1 == llvmArrayStride ap2 && - llvmArrayFields ap1 == llvmArrayFields ap2 && - all (flip elem (llvmArrayBorrows ap2)) (llvmArrayBorrows ap1) && - all (flip elem (llvmArrayBorrows ap1)) (llvmArrayBorrows ap2) then - distPerms1 x (ValPerm_Conj1 $ Perm_LLVMArray ap1) +simplImplIn (SImpl_LLVMArrayRearrange x ap bs) = + if llvmArrayBorrowsPermuteTo ap bs then + distPerms1 x (ValPerm_Conj1 $ Perm_LLVMArray ap) else - error "simplImplIn: SImpl_LLVMArrayRearrange: arrays not equivalent" + error "simplImplIn: SImpl_LLVMArrayRearrange: malformed output borrows list" simplImplIn (SImpl_LLVMArrayToField x ap _) = distPerms1 x (ValPerm_Conj1 $ Perm_LLVMArray ap) @@ -1694,7 +1690,7 @@ simplImplIn (SImpl_LLVMArrayIndexReturn x ap ix) = else error "simplImplIn: SImpl_LLVMArrayIndexReturn: index not being borrowed" -simplImplIn (SImpl_LLVMArrayContents x ap _ _ _) = +simplImplIn (SImpl_LLVMArrayContents x ap _ _) = distPerms1 x (ValPerm_Conj [Perm_LLVMArray ap]) simplImplIn (SImpl_LLVMFieldIsPtr x fp) = distPerms1 x (ValPerm_Conj [Perm_LLVMField fp]) @@ -1961,16 +1957,11 @@ simplImplOut (SImpl_LLVMArrayAppend x ap1 ap2) = llvmArrayAddArrayBorrows ap1' ap2 _ -> error "simplImplOut: SImpl_LLVMArrayAppend: arrays cannot be appended" -simplImplOut (SImpl_LLVMArrayRearrange x ap1 ap2) = - if bvEq (llvmArrayOffset ap1) (llvmArrayOffset ap2) && - bvEq (llvmArrayLen ap1) (llvmArrayLen ap2) && - llvmArrayStride ap1 == llvmArrayStride ap2 && - llvmArrayFields ap1 == llvmArrayFields ap2 && - all (flip elem (llvmArrayBorrows ap2)) (llvmArrayBorrows ap1) && - all (flip elem (llvmArrayBorrows ap1)) (llvmArrayBorrows ap2) then - distPerms1 x (ValPerm_Conj1 $ Perm_LLVMArray ap2) +simplImplOut (SImpl_LLVMArrayRearrange x ap bs) = + if llvmArrayBorrowsPermuteTo ap bs then + distPerms1 x (ValPerm_Conj1 $ Perm_LLVMArray $ ap { llvmArrayBorrows = bs }) else - error "simplImplOut: SImpl_LLVMArrayRearrange: arrays not equivalent" + error "simplImplOut: SImpl_LLVMArrayRearrange: malformed output borrows list" simplImplOut (SImpl_LLVMArrayToField x ap sz) = case llvmArrayToField sz ap of @@ -2016,11 +2007,8 @@ simplImplOut (SImpl_LLVMArrayIndexReturn x ap ix) = else error "simplImplOut: SImpl_LLVMArrayIndexReturn: index not being borrowed" -simplImplOut (SImpl_LLVMArrayContents x ap i fp _) = - distPerms1 x (ValPerm_Conj [Perm_LLVMArray $ - ap { llvmArrayFields = - take i (llvmArrayFields ap) ++ - fp : drop (i+1) (llvmArrayFields ap)}]) +simplImplOut (SImpl_LLVMArrayContents x ap flds _) = + distPerms1 x (ValPerm_Conj [Perm_LLVMArray $ ap { llvmArrayFields = flds }]) simplImplOut (SImpl_LLVMFieldIsPtr x fp) = distPerms2 x (ValPerm_Conj1 Perm_IsLLVMPtr) @@ -2421,8 +2409,8 @@ instance SubstVar PermVarSubst m => SImpl_LLVMArrayReturn <$> genSubst s x <*> genSubst s ap <*> genSubst s rng [nuMP| SImpl_LLVMArrayAppend x ap1 ap2 |] -> SImpl_LLVMArrayAppend <$> genSubst s x <*> genSubst s ap1 <*> genSubst s ap2 - [nuMP| SImpl_LLVMArrayRearrange x ap1 ap2 |] -> - SImpl_LLVMArrayRearrange <$> genSubst s x <*> genSubst s ap1 <*> genSubst s ap2 + [nuMP| SImpl_LLVMArrayRearrange x ap bs |] -> + SImpl_LLVMArrayRearrange <$> genSubst s x <*> genSubst s ap <*> genSubst s bs [nuMP| SImpl_LLVMArrayToField x ap sz |] -> SImpl_LLVMArrayToField <$> genSubst s x <*> genSubst s ap <*> return (mbLift sz) @@ -2438,10 +2426,9 @@ instance SubstVar PermVarSubst m => [nuMP| SImpl_LLVMArrayIndexReturn x ap ix |] -> SImpl_LLVMArrayIndexReturn <$> genSubst s x <*> genSubst s ap <*> genSubst s ix - [nuMP| SImpl_LLVMArrayContents x ap i fp impl |] -> + [nuMP| SImpl_LLVMArrayContents x ap flds mb_mb_impl |] -> SImpl_LLVMArrayContents <$> genSubst s x <*> genSubst s ap <*> - return (mbLift i) <*> genSubst s fp <*> - genSubst s impl + genSubst s flds <*> genSubst s mb_mb_impl [nuMP| SImpl_LLVMFieldIsPtr x fp |] -> SImpl_LLVMFieldIsPtr <$> genSubst s x <*> genSubst s fp [nuMP| SImpl_LLVMArrayIsPtr x ap |] -> @@ -2747,7 +2734,7 @@ embedImplM ps_in m = -- | Embed a sub-computation in a name-binding inside another 'ImplM' -- computation, throwing away any state from that sub-computation and returning -- a 'PermImpl' inside a name-binding -embedMbImplM :: Mb ctx (PermSet ps_in) -> +embedMbImplM :: Mb ctx (DistPerms ps_in) -> Mb ctx (ImplM RNil s r' ps_out ps_in (r' ps_out)) -> ImplM vars s r ps ps (Mb ctx (PermImpl r' ps_in)) embedMbImplM mb_ps_in mb_m = @@ -2755,7 +2742,7 @@ embedMbImplM mb_ps_in mb_m = lift $ strongMbM $ mbMap2 (\ps_in m -> runImplM - CruCtxNil ps_in + CruCtxNil (distPermSet ps_in) (view implStatePermEnv s) (view implStatePPInfo s) (view implStateFailPrefix s) (view implStateDebugLevel s) (view implStateNameTypes s) m (pure . fst)) @@ -3983,13 +3970,14 @@ implLLVMArrayAppend x ap1 ap2 = implSimplM Proxy (SImpl_LLVMArrayAppend x ap1 ap2) --- | Rearrange the order of the borrows in an array permission +-- | Rearrange the order of the borrows in the input array permission to match +-- the given list, assuming the two have the same elements implLLVMArrayRearrange :: (1 <= w, KnownNat w, NuMatchingAny1 r) => - ExprVar (LLVMPointerType w) -> LLVMArrayPerm w -> LLVMArrayPerm w -> + ExprVar (LLVMPointerType w) -> LLVMArrayPerm w -> [LLVMArrayBorrow w] -> ImplM vars s r (ps :> LLVMPointerType w) (ps :> LLVMPointerType w) () -implLLVMArrayRearrange x ap_in ap_out = - implSimplM Proxy (SImpl_LLVMArrayRearrange x ap_in ap_out) +implLLVMArrayRearrange x ap bs = + implSimplM Proxy (SImpl_LLVMArrayRearrange x ap bs) -- | Prove an empty array with length 0 implLLVMArrayEmpty :: @@ -5147,8 +5135,7 @@ proveVarLLVMArrayH x first_p ps ap = | precise <- bvEq off (llvmArrayOffset ap_lhs) , (first_p || precise) , Just cell_num <- llvmArrayIsOffsetArray ap_lhs ap - , bvCouldBeInRange cell_num (llvmArrayCells ap_lhs) - , llvmArrayFields ap_lhs == llvmArrayFields ap -> + , bvCouldBeInRange cell_num (llvmArrayCells ap_lhs) -> Just (precise, proveVarLLVMArray_ArrayStep x ps ap i ap_lhs) _ -> Nothing) ps [0..]) @@ -5160,6 +5147,24 @@ proveVarLLVMArray_ArrayStep :: [AtomicPerm (LLVMPointerType w)] -> LLVMArrayPerm w -> Int -> LLVMArrayPerm w -> ImplM vars s r (ps :> LLVMPointerType w) (ps :> LLVMPointerType w) () +proveVarLLVMArray_ArrayStep x ps ap i ap_lhs = + implTraceM (\info -> + pretty "proveVarLLVMArray_ArrayStep:" <+> + permPretty info x <> colon <> + align (sep [PP.group (permPretty info (ValPerm_Conj ps)), + parens (permPretty info (ValPerm_LLVMArray ap)), + pretty "-o", + PP.group (permPretty info (ValPerm_Conj1 $ + Perm_LLVMArray ap))])) >>> + proveVarLLVMArray_ArrayStepH x ps ap i ap_lhs + + +-- | The main workhorse of 'proveVarLLVMArray_ArrayStep' +proveVarLLVMArray_ArrayStepH :: + (1 <= w, KnownNat w, NuMatchingAny1 r) => ExprVar (LLVMPointerType w) -> + [AtomicPerm (LLVMPointerType w)] -> LLVMArrayPerm w -> + Int -> LLVMArrayPerm w -> + ImplM vars s r (ps :> LLVMPointerType w) (ps :> LLVMPointerType w) () -- If there is a borrow in ap_lhs that is not in ap but might overlap with ap, -- return it to ap_lhs @@ -5167,7 +5172,7 @@ proveVarLLVMArray_ArrayStep :: -- FIXME: when an array ap_ret is being borrowed from ap_lhs, this code requires -- all of it to be returned, with no borrows, even though it could be that ap -- allows some of ap_ret to be borrowed -proveVarLLVMArray_ArrayStep x ps ap i ap_lhs +proveVarLLVMArray_ArrayStepH x ps ap i ap_lhs | Just ap_cell_off <- llvmArrayIsOffsetArray ap_lhs ap , Just b <- find (\b -> @@ -5193,7 +5198,7 @@ proveVarLLVMArray_ArrayStep x ps ap i ap_lhs -- If there is a borrow in ap that is not in ap_lhs, borrow it from ap_lhs. Note -- the assymmetry with the previous case: we only add borrows if we definitely -- have to, but we remove borrows if we might have to. -proveVarLLVMArray_ArrayStep x ps ap i ap_lhs +proveVarLLVMArray_ArrayStepH x ps ap i ap_lhs | Just ap_lhs_cell_off <- llvmArrayIsOffsetArray ap ap_lhs , Just b <- find (\b -> @@ -5212,21 +5217,41 @@ proveVarLLVMArray_ArrayStep x ps ap i ap_lhs -- added to the front of the list of borrows, so we need to rearrange. implLLVMArrayBorrowBorrow x ap' b >>>= \p -> recombinePerm x p >>> - implLLVMArrayRearrange x (llvmArrayAddBorrow b ap') ap + implLLVMArrayRearrange x (llvmArrayAddBorrow b ap') (llvmArrayBorrows ap) -- If ap and ap_lhs are equal up to the order of their borrows, just rearrange --- the borrows and we should be good -proveVarLLVMArray_ArrayStep x ps ap i ap_lhs +-- the borrows and we should be done +proveVarLLVMArray_ArrayStepH x ps ap i ap_lhs | bvEq (llvmArrayOffset ap_lhs) (llvmArrayOffset ap) , bvEq (llvmArrayLen ap_lhs) (llvmArrayLen ap) , llvmArrayStride ap_lhs == llvmArrayStride ap - , llvmArrayFields ap_lhs == llvmArrayFields ap = + , llvmArrayFields ap_lhs == llvmArrayFields ap + , llvmArrayBorrowsPermuteTo ap_lhs (llvmArrayBorrows ap) = implGetPopConjM x ps i >>> - implLLVMArrayRearrange x ap_lhs ap + implLLVMArrayRearrange x ap_lhs (llvmArrayBorrows ap) + +-- If ap and ap_lhs have the same range and stride but their fields are +-- different, prove the rhs fields from the lhs fields +proveVarLLVMArray_ArrayStepH x ps ap i ap_lhs + | bvEq (llvmArrayOffset ap_lhs) (llvmArrayOffset ap) + , bvEq (llvmArrayLen ap_lhs) (llvmArrayLen ap) + , llvmArrayStride ap_lhs == llvmArrayStride ap + , flds <- llvmArrayFields ap + , flds_lhs <- llvmArrayFields ap_lhs + , ap' <- ap { llvmArrayFields = flds_lhs } + , dps_in <- + nu $ \y -> distPerms1 y $ ValPerm_Conj $ + map llvmArrayFieldToAtomicPerm flds_lhs + , dps_out <- + nu $ \y -> distPerms1 y $ ValPerm_Conj $ + map llvmArrayFieldToAtomicPerm flds = + proveVarLLVMArray_ArrayStep x ps ap' i ap_lhs >>> + localMbProveVars dps_in dps_out >>>= \mb_impl -> + implSimplM Proxy (SImpl_LLVMArrayContents x ap' flds mb_impl) -- If ap is contained inside ap_lhs at a cell boundary then copy or borrow ap -- from ap_lhs depending on whether they are copyable -proveVarLLVMArray_ArrayStep x ps ap i ap_lhs +proveVarLLVMArray_ArrayStepH x ps ap i ap_lhs | all bvPropCouldHold (bvPropRangeSubset (llvmArrayAbsOffsets ap) (llvmArrayAbsOffsets ap_lhs)) , llvmArrayStride ap_lhs == llvmArrayStride ap @@ -5246,7 +5271,7 @@ proveVarLLVMArray_ArrayStep x ps ap i ap_lhs -- If we get to this case but ap is still at a cell boundary in ap_lhs then -- ap_lhs only satisfies some initial portion of ap, so borrow or copy that part -- of ap_lhs and continue proving the rest of ap -proveVarLLVMArray_ArrayStep x ps ap i ap_lhs +proveVarLLVMArray_ArrayStepH x ps ap i ap_lhs | llvmArrayStride ap_lhs == llvmArrayStride ap , llvmArrayFields ap_lhs == llvmArrayFields ap , Just (LLVMArrayIndex ap_cell_num 0) <- @@ -5281,7 +5306,7 @@ proveVarLLVMArray_ArrayStep x ps ap i ap_lhs -- Otherwise we don't know what to do so we fail -proveVarLLVMArray_ArrayStep _x _ps _ap _i _ap_lhs = +proveVarLLVMArray_ArrayStepH _x _ps _ap _i _ap_lhs = implFailMsgM "proveVarLLVMArray_ArrayStep" @@ -7033,6 +7058,23 @@ localProveVars ps_in ps_out = proveVarsImplInt (emptyMb ps_out) >>> pure (LocalImplRet Refl)) +-- | Prove one sequence of permissions over an extended set of local variables +-- from another and capture the proof as a 'LocalPermImpl' in a binding +localMbProveVars :: NuMatchingAny1 r => + Mb (ctx :: RList CrucibleType) (DistPerms ps_in) -> + Mb ctx (DistPerms ps_out) -> + ImplM vars s r ps ps (Mb ctx (LocalPermImpl ps_in ps_out)) +localMbProveVars mb_ps_in mb_ps_out = + implTraceM (\i -> sep [pretty "localMbProveVars:", permPretty i mb_ps_in, + pretty "-o", permPretty i mb_ps_out]) >>> + fmap LocalPermImpl <$> + embedMbImplM mb_ps_in (mbMap2 + (\ps_in ps_out -> + recombinePermsRev ps_in >>> + proveVarsImplInt (emptyMb ps_out) >>> + pure (LocalImplRet Refl)) + mb_ps_in mb_ps_out) + ---------------------------------------------------------------------- -- * External Entrypoints to the Implication Prover diff --git a/heapster-saw/src/Verifier/SAW/Heapster/Permissions.hs b/heapster-saw/src/Verifier/SAW/Heapster/Permissions.hs index ce43c842a3..ab52151345 100644 --- a/heapster-saw/src/Verifier/SAW/Heapster/Permissions.hs +++ b/heapster-saw/src/Verifier/SAW/Heapster/Permissions.hs @@ -3753,6 +3753,13 @@ llvmArrayRemArrayBorrows ap sub_ap ap llvmArrayRemArrayBorrows _ _ = error "llvmArrayRemArrayBorrows" +-- | Test if the borrows of an array can be permuted to another order +llvmArrayBorrowsPermuteTo :: (1 <= w, KnownNat w) => LLVMArrayPerm w -> + [LLVMArrayBorrow w] -> Bool +llvmArrayBorrowsPermuteTo ap bs = + all (flip elem (llvmArrayBorrows ap)) bs && + all (flip elem bs) (llvmArrayBorrows ap) + -- | Add a cell offset to an 'LLVMArrayBorrow', meaning we change the borrow to -- be relative to an array with that many more cells added to the front cellOffsetLLVMArrayBorrow :: (1 <= w, KnownNat w) => PermExpr (BVType w) -> diff --git a/heapster-saw/src/Verifier/SAW/Heapster/SAWTranslation.hs b/heapster-saw/src/Verifier/SAW/Heapster/SAWTranslation.hs index 9a84ab4b6e..7a45f64fd5 100644 --- a/heapster-saw/src/Verifier/SAW/Heapster/SAWTranslation.hs +++ b/heapster-saw/src/Verifier/SAW/Heapster/SAWTranslation.hs @@ -574,6 +574,10 @@ translateClosed :: (TransInfo info, Translate info ctx a tr) => a -> TransM info ctx tr translateClosed a = nuMultiTransM (const a) >>= translate +instance (Translate info ctx a tr, NuMatching a) => + Translate info ctx [a] [tr] where + translate = mapM translate . mbList + ---------------------------------------------------------------------- -- * Translating Types @@ -781,11 +785,10 @@ instance TransInfo info => return $ ETrans_Term $ bvBVOpenTerm w $ mbLift off [nuMP| PExpr_BV bvfactors (BV.BV 0) |] -> let w = natVal3 bvfactors in - ETrans_Term <$> foldr1 (bvAddOpenTerm w) <$> - mapM translate (mbList bvfactors) + ETrans_Term <$> foldr1 (bvAddOpenTerm w) <$> translate bvfactors [nuMP| PExpr_BV bvfactors off |] -> do let w = natRepr3 bvfactors - bv_transs <- mapM translate $ mbList bvfactors + bv_transs <- translate bvfactors return $ ETrans_Term $ foldr (bvAddOpenTerm $ natValue w) (bvBVOpenTerm w $ mbLift off) bv_transs [nuMP| PExpr_Struct args |] -> @@ -822,7 +825,7 @@ instance TransInfo info => do let w = natVal4 mb_len let w_term = natOpenTerm w len_term <- translate1 mb_len - elem_tp <- tupleOfTypes <$> concat <$> mapM translate (mbList mb_fshs) + elem_tp <- tupleOfTypes <$> concat <$> translate mb_fshs return $ ETrans_Term $ applyOpenTermMulti (globalOpenTerm "Prelude.BVVec") [w_term, len_term, elem_tp] @@ -1420,7 +1423,7 @@ setLLVMArrayTransCell arr_trans (LLVMArrayIndexTrans _ i_trans _) -- | Adjust an array cell (= list of fields) of the translation of an LLVM array -- permission at a given index by applying a function to it adjustLLVMArrayTransCell :: (1 <= w, KnownNat w) => LLVMArrayPermTrans ctx w -> - OpenTerm -> LLVMArrayIndexTrans ctx w -> + OpenTerm -> LLVMArrayIndexTrans ctx w -> LLVMArrayPermTrans ctx w adjustLLVMArrayTransCell arr_trans f_trm (LLVMArrayIndexTrans _ i_trans _) = let w = fromInteger $ natVal arr_trans in @@ -1516,6 +1519,84 @@ setLLVMArrayTransSlice arr_trans sub_arr_trans off_tm = (globalOpenTerm "Prelude.updSliceBVVec") [natOpenTerm w, len_tm, elem_tp, arr_tm, off_tm, len'_tm, sub_arr_tm] } +-- | Weaken a monadic function of type @(T1*...*Tn) -> CompM(U1*...*Um)@ to one +-- of type @(V*T1*...*Tn) -> CompM(V*U1*...*Um)@, where tuples of 2 or more +-- types are right-nested and and in a unit type, i.e., have the form +-- @(T1*(T2*(...*(Tn*#()))))@. +weakenMonadicFun1 :: OpenTerm -> [OpenTerm] -> [OpenTerm] -> OpenTerm -> + OpenTerm +weakenMonadicFun1 v ts us f = + -- First form a term f1 of type V*(T1*...*Tn) -> CompM(V*(U1*...*Um)) + let t_tup = tupleOfTypes ts + u_tup = tupleOfTypes us + f1 = + applyOpenTermMulti (globalOpenTerm "Prelude.tupleCompMFunBoth") + [t_tup, u_tup, v, f] in + + let f2 = case ts of + -- If ts is empty, form the term \ (x:V) -> f1 (x, ()) to coerce f1 from + -- type V*#() -> CompM(V*Us) to type V -> CompM(V*Us) + [] -> + lambdaOpenTerm "x" v $ \x -> + applyOpenTerm f1 (pairOpenTerm x unitOpenTerm) + -- If ts = [t], form the term \ (x:V*(T*#())) -> f1 (x.(1),x.(2).(1)) to + -- coerce f1 from V*T -> CompM(V*Us) to type V*(T*#()) -> CompM(V*Us) + [t] -> + lambdaOpenTerm "x" (tupleTypeOpenTerm [v,t]) $ \x -> + applyOpenTerm f1 (pairOpenTerm + (pairLeftOpenTerm x) + (pairLeftOpenTerm $ pairRightOpenTerm x)) + -- Otherwise, leave f1 unchanged + _ -> f1 in + + case us of + -- If us is empty, compose f2 with \ (x:V*#()) -> returnM V x.(1) to coerce + -- from V*Us -> CompM (V*#()) to V*Us -> CompM V + [] -> + applyOpenTermMulti (globalOpenTerm "Prelude.composeM") + [tupleOfTypes (v:ts), pairTypeOpenTerm v unitTypeOpenTerm, v, f2, + lambdaOpenTerm "x" (pairTypeOpenTerm v unitTypeOpenTerm) + (\x -> applyOpenTermMulti (globalOpenTerm "Prelude.returnM") + [v, pairLeftOpenTerm x])] + [u] -> + -- If us = [u], compose f2 with the term + -- \ (x:V*U) -> returnM (V*(U*#())) (x.(1), (x.(2),())) to coerce + -- from V*Us -> CompM (V*U) to V*Us -> CompM (V*(U*#())) + applyOpenTermMulti (globalOpenTerm "Prelude.composeM") + [tupleOfTypes (v:ts), pairTypeOpenTerm v u, tupleOfTypes [v,u], f2, + lambdaOpenTerm "x" (pairTypeOpenTerm v u) + (\x -> applyOpenTermMulti (globalOpenTerm "Prelude.returnM") + [tupleOfTypes [v,u], + pairOpenTerm (pairLeftOpenTerm x) + (pairOpenTerm (pairRightOpenTerm x) unitOpenTerm)])] + -- Otherwise, leave f2 unchanged + _ -> f2 + + +-- | Weaken a monadic function of type @(T1*...*Tn) -> CompM(U1*...*Um)@ to one +-- of type @(V1*...*Vk*T1*...*Tn) -> CompM(V1*...*Vk*U1*...*Um)@, where tuples +-- of 2 or more types are right-nested and and in a unit type, i.e., have the +-- form @(T1 * (T2 * (... * (Tn * #()))))@ +weakenMonadicFun :: [OpenTerm] -> [OpenTerm] -> [OpenTerm] -> OpenTerm -> + OpenTerm +weakenMonadicFun vs ts_top us_top f_top = + let (_,_,ret) = + foldr (\v (ts,us,f) -> (v:ts, v:us, weakenMonadicFun1 v ts us f)) + (ts_top, us_top, f_top) + vs in + ret + +-- | Weaken a monadic function which is the translation of an ownership +-- permission @lowned(ps_in -o ps_out)@ to @lowned(P * ps_in -o P * ps_out)@ +weakenLifetimeFun :: TypeTrans (PermTrans ctx a) -> + TypeTrans (PermTransCtx ctx ps_in) -> + TypeTrans (PermTransCtx ctx ps_out) -> + OpenTerm -> OpenTerm +weakenLifetimeFun tp_trans ps_in_trans ps_out_trans f = + weakenMonadicFun (transTerms + tp_trans) (transTerms + ps_in_trans) (transTerms ps_out_trans) f + instance (1 <= w, KnownNat w, TransInfo info) => Translate info ctx (BVProp w) (TypeTrans (BVPropTrans ctx w)) where @@ -1616,7 +1697,7 @@ instance TransInfo info => translate (mbMap2 (unfoldDefinedPerm dp) args off) Nothing -> error "Unknown permission name!" [nuMP| ValPerm_Conj ps |] -> - fmap PTrans_Conj <$> listTypeTrans <$> mapM translate (mbList ps) + fmap PTrans_Conj <$> listTypeTrans <$> translate ps [nuMP| ValPerm_Var x _ |] -> mkPermTypeTrans1 p <$> translate1 x @@ -1659,8 +1740,8 @@ instance TransInfo info => [nuMP| Perm_LLVMFrame fp |] -> return $ mkTypeTrans0 $ APTrans_LLVMFrame fp [nuMP| Perm_LOwned ls ps_in ps_out |] -> - do tp_in <- translate1 ps_in - tp_out <- translate1 ps_out + do tp_in <- typeTransTupleType <$> translate ps_in + tp_out <- typeTransTupleType <$> translate ps_out let tp = arrowOpenTerm "ps" tp_in (applyOpenTerm (globalOpenTerm "Prelude.CompM") tp_out) @@ -1690,9 +1771,7 @@ translateLLVMArrayPerm mb_ap = let w_term = natOpenTerm w let mb_len = fmap llvmArrayLen mb_ap let mb_flds = fmap llvmArrayFields mb_ap - flds_trans <- - tupleTypeTrans <$> listTypeTrans <$> - mapM (translate . fmap llvmArrayFieldToAtomicPerm) (mbList mb_flds) + flds_trans <- tupleTypeTrans <$> listTypeTrans <$> translate mb_flds len_term <- translate1 mb_len let elem_tp = typeTransType1 flds_trans {- @@ -1746,13 +1825,19 @@ instance TransInfo info => (PermTransCtx ctx ps)) where translate = translate . mbDistPermsToValuePerms . fmap unTypeDistPerms +instance (TransInfo info, 1 <= w, KnownNat w) => + Translate info ctx (LLVMArrayField w) (TypeTrans + (AtomicPermTrans ctx + (LLVMPointerType w))) where + translate = translate . fmap llvmArrayFieldToAtomicPerm + + -- LOwnedPerms translate to a single tuple type, because lowned permissions -- translate to functions with one argument and one return value instance TransInfo info => Translate info ctx (LOwnedPerms ps) (TypeTrans (PermTransCtx ctx ps)) where - translate = - fmap strictTupleTypeTrans . translate . fmap (RL.map lownedPermPerm) + translate = translate . fmap (RL.map lownedPermPerm) -- Translate a FunPerm to a pi-abstraction (FIXME: more documentation!) instance TransInfo info => @@ -2467,13 +2552,10 @@ translateSimplImpl (ps0 :: Proxy ps0) mb_simpl m = case mbMatch mb_simpl of m - [nuMP| SImpl_LLVMArrayRearrange _ _ mb_ap2 |] -> - do ap2_tp_trans <- translate mb_ap2 + [nuMP| SImpl_LLVMArrayRearrange _ _ _ |] -> + do ttrans <- translateSimplImplOutHead mb_simpl withPermStackM id - (\(pctx :>: ptrans_array) -> - pctx :>: - PTrans_Conj [APTrans_LLVMArray $ - typeTransF ap2_tp_trans [transTerm1 ptrans_array]]) + (\(pctx :>: ptrans) -> pctx :>: typeTransF ttrans [transTerm1 ptrans]) m [nuMP| SImpl_LLVMArrayToField _ _ _ |] -> @@ -2564,8 +2646,32 @@ translateSimplImpl (ps0 :: Proxy ps0) mb_simpl m = case mbMatch mb_simpl of pctx :>: PTrans_Conj [APTrans_LLVMArray arr_trans']) m - [nuMP| SImpl_LLVMArrayContents _ _ _ _ _ |] -> - error "FIXME HERE: translateSimplImpl: SImpl_LLVMArrayContents unhandled" + [nuMP| SImpl_LLVMArrayContents _ ap flds' impl |] -> + do pctx_out_trans <- translateSimplImplOutHead mb_simpl + (w_term, len_term, elem_tp, _) <- translateLLVMArrayPerm ap + flds_in_trans <- + fmap tupleTypeTrans $ translate $ + fmap (ValPerm_Conj . map llvmArrayFieldToAtomicPerm . llvmArrayFields) ap + flds_out_trans <- + fmap tupleTypeTrans $ translate $ + fmap (ValPerm_Conj . map llvmArrayFieldToAtomicPerm) flds' + impl_tm <- + -- FIXME: this code just fabricates a pretend LLVM value for the + -- arbitrary field of the array, which seems like a hack + inExtTransM ETrans_LLVM $ + translateCurryLocalPermImpl "Error mapping array field permissions:" + (mbCombine RL.typeCtxProxies impl) MNil MNil + (fmap ((MNil :>:) . extPermTrans) flds_in_trans) (MNil :>: Member_Base) + (fmap ((MNil :>:) . extPermTrans) flds_out_trans) + let mk_arr_out_tm ptrans_arr = + applyOpenTermMulti + (globalOpenTerm "Prelude.mapBVVecM") + [elem_tp, typeTransType1 flds_out_trans, impl_tm, + w_term, len_term, transTerm1 ptrans_arr] + withPermStackM id + (\(pctx :>: ptrans_arr) -> + pctx :>: typeTransF pctx_out_trans [mk_arr_out_tm ptrans_arr]) + m [nuMP| SImpl_LLVMFieldIsPtr x _ |] -> withPermStackM (:>: translateVar x) @@ -2587,8 +2693,8 @@ translateSimplImpl (ps0 :: Proxy ps0) mb_simpl m = case mbMatch mb_simpl of [nuMP| SImpl_SplitLifetime _ f args l _ _ ps_in ps_out |] -> do pctx_out_trans <- translateSimplImplOut mb_simpl - ps_in_tp <- translate1 ps_in - ps_out_tp <- translate1 ps_out + ps_in_trans <- translate ps_in + ps_out_trans <- translate ps_out x_tp_trans <- translate (mbMap3 ltFuncApply f args l) withPermStackM (\(ns :>: x :>: _ :>: l2) -> ns :>: x :>: l2) @@ -2596,15 +2702,9 @@ translateSimplImpl (ps0 :: Proxy ps0) mb_simpl m = case mbMatch mb_simpl of -- The permission for x does not change type, just its lifetime; the -- permission for l has the (tupled) type of x added as a new input and -- output with tupleCompMFunBoth - let (f_tm,_,_) = - foldr (\x_tp (f_term,f_in_tp,f_out_tp) -> - ( applyOpenTermMulti - (globalOpenTerm "Prelude.tupleCompMFunBoth") - [f_in_tp, f_out_tp, x_tp, f_term] - , pairTypeOpenTerm x_tp f_in_tp - , pairTypeOpenTerm x_tp f_out_tp)) - (transTerm1 ptrans_l, ps_in_tp, ps_out_tp) - (transTerms x_tp_trans) in + let f_tm = + weakenLifetimeFun x_tp_trans ps_in_trans ps_out_trans $ + transTerm1 ptrans_l in RL.append pctx $ typeTransF pctx_out_trans (transTerms ptrans_x ++ [f_tm])) m @@ -2652,10 +2752,10 @@ translateSimplImpl (ps0 :: Proxy ps0) mb_simpl m = case mbMatch mb_simpl of ps_in' ps_out' ps1 ps2 impl_in impl_out |] -> -- First, translate the output permissions and all of the perm lists do pctx_out_trans <- translateSimplImplOut mb_simpl - ps_in_trans <- translate ps_in - ps_out_trans <- translate ps_out - ps_in'_trans <- translate ps_in' - ps_out'_trans <- translate ps_out' + ps_in_trans <- tupleTypeTrans <$> translate ps_in + ps_out_trans <- tupleTypeTrans <$> translate ps_out + ps_in'_trans <- tupleTypeTrans <$> translate ps_in' + ps_out'_trans <- tupleTypeTrans <$> translate ps_out' -- ps1_trans <- translate ps1 -- ps2_trans <- translate ps2 @@ -2692,12 +2792,12 @@ translateSimplImpl (ps0 :: Proxy ps0) mb_simpl m = case mbMatch mb_simpl of let l_res_tm = applyOpenTermMulti (globalOpenTerm "Prelude.composeM") - [transTerm1 ps_in'_trans, transTerm1 ps_in_trans, - transTerm1 ps_out'_trans, impl_in_tm, + [typeTransType1 ps_in'_trans, typeTransType1 ps_in_trans, + typeTransType1 ps_out'_trans, impl_in_tm, applyOpenTermMulti (globalOpenTerm "Prelude.composeM") - [transTerm1 ps_in_trans, transTerm1 ps_out_trans, - transTerm1 ps_out'_trans, transTerm1 ptrans_l, impl_out_tm]] + [typeTransType1 ps_in_trans, typeTransType1 ps_out_trans, + typeTransType1 ps_out'_trans, transTerm1 ptrans_l, impl_out_tm]] -- Finally, update the permissions withPermStackM @@ -2708,7 +2808,7 @@ translateSimplImpl (ps0 :: Proxy ps0) mb_simpl m = case mbMatch mb_simpl of [nuMP| SImpl_EndLifetime _ ps_in ps_out |] -> -- First, translate the output permissions and the input and output types of -- the monadic function for the lifeime ownership permission - do ps_out_trans <- translate ps_out + do ps_out_trans <- tupleTypeTrans <$> translate ps_out let prxs_in = mbRAssignProxies ps_in :>: Proxy -- Next, split out the ps_in permissions from the rest of the pctx @@ -2727,9 +2827,9 @@ translateSimplImpl (ps0 :: Proxy ps0) mb_simpl m = case mbMatch mb_simpl of -- Now we apply the lifetime ownerhip function to ps_in and bind its output -- in the rest of the computation applyMultiTransM (return $ globalOpenTerm "Prelude.bindM") - [return (transTerm1 ps_out_trans), returnTypeM, + [return (typeTransType1 ps_out_trans), returnTypeM, return (applyOpenTerm (transTerm1 ptrans_l) - (strictTransTupleTerm pctx_in)), + (transTupleTerm pctx_in)), lambdaTransM "endl_ps" ps_out_trans $ \pctx_out -> withPermStackM (\(_ :>: l) -> vars_out :>: l) @@ -3479,7 +3579,7 @@ instance ImplTranslateF (LocalImplRet ps) ext blocks ps_in ret where do pctx <- itiPermStack <$> ask ret_tp <- returnTypeM return $ applyOpenTermMulti (globalOpenTerm "Prelude.returnM") - [ret_tp, strictTransTupleTerm pctx] + [ret_tp, transTupleTerm pctx] -- | Translate a local implication to its output, adding an error message translateLocalPermImpl :: String -> Mb ctx (LocalPermImpl ps_in ps_out) -> @@ -3500,7 +3600,7 @@ translateCurryLocalPermImpl :: ImpTransM ext blocks tops ret ps ctx OpenTerm translateCurryLocalPermImpl err impl pctx1 vars1 tp_trans2 vars2 tp_trans_out = lambdaTransM "x_local" tp_trans2 $ \pctx2 -> - local (\info -> info { itiReturnType = transTerm1 tp_trans_out }) $ + local (\info -> info { itiReturnType = typeTransType1 tp_trans_out }) $ withPermStackM (const (RL.append vars1 vars2)) (const (RL.append pctx1 pctx2)) From 8caa5776b7acc907d7b7c565de2bb6840d915be8 Mon Sep 17 00:00:00 2001 From: Eddy Westbrook Date: Tue, 14 Sep 2021 06:13:13 -0700 Subject: [PATCH 27/98] added more definitions to the arrays example now that the implication prover can map array permission contents --- heapster-saw/examples/arrays.saw | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/heapster-saw/examples/arrays.saw b/heapster-saw/examples/arrays.saw index e5a0f6bd70..f943abc800 100644 --- a/heapster-saw/examples/arrays.saw +++ b/heapster-saw/examples/arrays.saw @@ -1,7 +1,14 @@ enable_experimental; env <- heapster_init_env_from_file "arrays.sawcore" "arrays.bc"; +heapster_set_debug_level env 1; -heapster_typecheck_fun env "contains0_rec_" "(len:bv 64).arg0:eq(llvmword(len)), arg1:array(0, exists z:bv 64.eq(llvmword(z))]), arg2:(exists z:bv 64.eq(llvmword(z))) -o arg0:true, arg1:array(0, exists z:bv 64.eq(llvmword(z))]), arg2:true, ret:exists z:(bv 64).eq(llvmword(z))"; +heapster_define_perm env "int64" " " "llvmptr 64" "exists x:bv 64.eq(llvmword(x))"; +heapster_define_perm env "int8" " " "llvmptr 8" "exists x:bv 8.eq(llvmword(x))"; + +heapster_define_perm env "int64array" "len:bv 64" "llvmptr 64" "array(0, int64<>])"; + + +heapster_typecheck_fun env "contains0_rec_" "(len:bv 64).arg0:eq(llvmword(len)), arg1:int64array, arg2:int64<> -o arg0:true, arg1:int64array, arg2:true, ret:int64<>"; // the old way using a block entry hint // heapster_define_perm env "int64" " " "llvmptr 64" "exists x:bv 64.eq(llvmword(x))"; @@ -10,20 +17,20 @@ heapster_typecheck_fun env "contains0_rec_" "(len:bv 64).arg0:eq(llvmword(len)), // the new way using a gen perms hint heapster_gen_block_perms_hint env "contains0" []; // Note that we could give specific block numbers here (e.g. [9]), but giving nothing will just add a hint to every block, which works just fine for this function. -heapster_typecheck_fun env "contains0" "(len:bv 64).arg0:array(0, exists z:bv 64.eq(llvmword(z))]), arg1:eq(llvmword(len)) -o arg0:array(0, exists z:bv 64.eq(llvmword(z))]), arg1:true, ret:exists z:(bv 64).eq(llvmword(z))"; +heapster_typecheck_fun env "contains0" "(len:bv 64).arg0:int64array, arg1:eq(llvmword(len)) -o arg0:int64array, arg1:true, ret:int64<>"; // the new way using a gen perms hint heapster_gen_block_perms_hint env "zero_array" []; -heapster_typecheck_fun env "zero_array" "(len:bv 64).arg0:array(0, exists z:bv 64.eq(llvmword(z))]), arg1:eq(llvmword(len)) -o arg0:array(0, exists z:bv 64.eq(llvmword(z))]), arg1:true, ret:true"; +heapster_typecheck_fun env "zero_array" "(len:bv 64).arg0:int64array, arg1:eq(llvmword(len)) -o arg0:int64array, arg1:true, ret:true"; heapster_gen_block_perms_hint env "zero_array_from" []; -heapster_typecheck_fun env "zero_array_from" "(len:bv 64, off:bv 64).arg0:array(0, exists z:bv 64.eq(llvmword(z))]), arg1:eq(llvmword(len)), arg2:eq(llvmword(off)) -o arg0:array(0, exists z:bv 64.eq(llvmword(z))]), arg1:true, ret:true"; +heapster_typecheck_fun env "zero_array_from" "(len:bv 64, off:bv 64).arg0:int64array, arg1:eq(llvmword(len)), arg2:eq(llvmword(off)) -o arg0:int64array, arg1:true, ret:true"; heapster_gen_block_perms_hint env "filter_and_sum_pos" []; heapster_join_point_hint env "filter_and_sum_pos" []; -heapster_typecheck_fun env "filter_and_sum_pos" "(len:bv 64).arg0:array(0, exists z:bv 64.eq(llvmword(z))]), arg1:eq(llvmword(len)) -o arg0:array(0, exists z:bv 64.eq(llvmword(z))]), arg1:true, ret:exists x:bv 64.eq(llvmword(x))"; +heapster_typecheck_fun env "filter_and_sum_pos" "(len:bv 64).arg0:int64array, arg1:eq(llvmword(len)) -o arg0:int64array, arg1:true, ret:int64<>"; heapster_gen_block_perms_hint env "sum_2d" []; -heapster_typecheck_fun env "sum_2d" "(l1:bv 64,l2:bv 64).arg0:array(0, array(0, exists z:bv 64.eq(llvmword(z))])]), arg1:eq(llvmword(l1)), arg2:eq(llvmword(l2)) -o arg0:array(0, array(0, exists z:bv 64.eq(llvmword(z))])]), arg1:true, arg2:true, ret:exists x:bv 64.eq(llvmword(x))"; +heapster_typecheck_fun env "sum_2d" "(l1:bv 64,l2:bv 64).arg0:array(0, array(0, exists z:bv 64.eq(llvmword(z))])]), arg1:eq(llvmword(l1)), arg2:eq(llvmword(l2)) -o arg0:array(0, array(0, exists z:bv 64.eq(llvmword(z))])]), arg1:true, arg2:true, ret:int64<>"; heapster_export_coq env "arrays_gen.v"; From f0e36a1da5e48357d4f67d471e779446a7c9e5ab Mon Sep 17 00:00:00 2001 From: Eddy Westbrook Date: Tue, 14 Sep 2021 06:47:48 -0700 Subject: [PATCH 28/98] moved the LLVM globals code to a new file LLVMGlobalConst.hs --- heapster-saw/heapster-saw.cabal | 2 + .../Verifier/SAW/Heapster/LLVMGlobalConst.hs | 191 ++++++++++++++++++ src/SAWScript/HeapsterBuiltins.hs | 166 +-------------- 3 files changed, 197 insertions(+), 162 deletions(-) create mode 100644 heapster-saw/src/Verifier/SAW/Heapster/LLVMGlobalConst.hs diff --git a/heapster-saw/heapster-saw.cabal b/heapster-saw/heapster-saw.cabal index c8d2a8c1cf..f8ad6390b9 100644 --- a/heapster-saw/heapster-saw.cabal +++ b/heapster-saw/heapster-saw.cabal @@ -28,6 +28,7 @@ library reflection, -- ansi-wl-pprint, prettyprinter >= 1.7.0, + pretty, transformers, mtl, containers, @@ -47,6 +48,7 @@ library Verifier.SAW.Heapster.Implication Verifier.SAW.Heapster.IRTTranslation Verifier.SAW.Heapster.Lexer + Verifier.SAW.Heapster.LLVMGlobalConst Verifier.SAW.Heapster.Located Verifier.SAW.Heapster.ParsedCtx Verifier.SAW.Heapster.Parser diff --git a/heapster-saw/src/Verifier/SAW/Heapster/LLVMGlobalConst.hs b/heapster-saw/src/Verifier/SAW/Heapster/LLVMGlobalConst.hs new file mode 100644 index 0000000000..4f377e783b --- /dev/null +++ b/heapster-saw/src/Verifier/SAW/Heapster/LLVMGlobalConst.hs @@ -0,0 +1,191 @@ +{-# LANGUAGE GADTs #-} +{-# LANGUAGE ScopedTypeVariables #-} +{-# LANGUAGE TypeApplications #-} +{-# LANGUAGE OverloadedStrings #-} +{-# LANGUAGE TypeOperators #-} +{-# LANGUAGE DataKinds #-} +{-# LANGUAGE ViewPatterns #-} + +module Verifier.SAW.Heapster.LLVMGlobalConst ( + permEnvAddGlobalConst + ) where + +import Data.Bits +import Data.List +import Control.Monad.Reader +import GHC.TypeLits +import qualified Text.PrettyPrint.HughesPJ as PPHPJ + +import qualified Text.LLVM.AST as L +import qualified Text.LLVM.PP as L + +import Data.Binding.Hobbits hiding (sym) + +import Data.Parameterized.NatRepr +import Data.Parameterized.Some + +import Lang.Crucible.Types +import Lang.Crucible.LLVM.MemModel +import Verifier.SAW.OpenTerm +import Verifier.SAW.Heapster.Permissions + +-- | The monad for translating LLVM globals to Heapster +type LLVMTransM = ReaderT (PermEnv, DebugLevel) Maybe + +-- | Run the 'LLVMTransM' monad +runLLVMTransM :: LLVMTransM a -> (PermEnv, DebugLevel) -> Maybe a +runLLVMTransM = runReaderT + +-- | Use 'debugTrace' to output a string message and then call 'mzero' +traceAndZeroM :: String -> LLVMTransM a +traceAndZeroM msg = + do (_,dlevel) <- ask + debugTrace dlevel msg mzero + +-- | Helper function to pretty-print the value of a global +ppLLVMValue :: L.Value -> String +ppLLVMValue val = + L.withConfig (L.Config True True True) (show $ PPHPJ.nest 2 $ L.ppValue val) + +-- | Helper function to pretty-print an LLVM constant expression +ppLLVMConstExpr :: L.ConstExpr -> String +ppLLVMConstExpr ce = + L.withConfig (L.Config True True True) (show $ PPHPJ.nest 2 $ L.ppConstExpr ce) + +-- | Translate a typed LLVM 'L.Value' to a Heapster permission + translation +translateLLVMValue :: (1 <= w, KnownNat w) => NatRepr w -> L.Type -> L.Value -> + LLVMTransM (PermExpr (LLVMShapeType w), OpenTerm) +translateLLVMValue w tp@(L.PrimType (L.Integer n)) (L.ValInteger i) = + translateLLVMType w tp >>= \(sh,_) -> + return (sh, bvLitOpenTerm (map (testBit i) $ + reverse [0..(fromIntegral n)-1])) +translateLLVMValue w _ (L.ValSymbol sym) = + do (env,_) <- ask + -- (p, ts) <- lift (lookupGlobalSymbol env (GlobalSymbol sym) w) + (p, t) <- case (lookupGlobalSymbol env (GlobalSymbol sym) w) of + Just (p,[t]) -> return (p,t) + Just (p,ts) -> return (p,tupleOpenTerm ts) + Nothing -> traceAndZeroM ("Could not find symbol: " ++ show sym) + return (PExpr_FieldShape (LLVMFieldShape p), t) +translateLLVMValue w _ (L.ValArray tp elems) = + do + -- First, translate the elements + ts <- map snd <$> mapM (translateLLVMValue w tp) elems + -- Array shapes can only handle field shapes elements, so translate the + -- element type to and ensure it returns a field shape; FIXME: this could + -- actually handle sequences of field shapes if necessary + (sh, saw_tp) <- translateLLVMType w tp + fsh <- case sh of + PExpr_FieldShape fsh -> return fsh + _ -> mzero + -- Compute the array stride as the length of the element shape + sh_len_expr <- lift $ llvmShapeLength sh + sh_len <- fromInteger <$> lift (bvMatchConstInt sh_len_expr) + + -- Finally, build our array shape and SAW core value + return (PExpr_ArrayShape (bvInt $ fromIntegral $ length elems) sh_len [fsh], + arrayValueOpenTerm saw_tp ts) +translateLLVMValue w _ (L.ValPackedStruct elems) = + mapM (translateLLVMTypedValue w) elems >>= \(unzip -> (shs,ts)) -> + return (foldr PExpr_SeqShape PExpr_EmptyShape shs, tupleOpenTerm ts) +translateLLVMValue w tp (L.ValString bytes) = + translateLLVMValue w tp (L.ValArray + (L.PrimType (L.Integer 8)) + (map (L.ValInteger . toInteger) bytes)) + {- + return (PExpr_ArrayShape (bvInt $ fromIntegral $ length bytes) 1 + [LLVMFieldShape (ValPerm_Exists $ nu $ \(bv :: Name (BVType 8)) -> + ValPerm_Eq $ PExpr_LLVMWord $ PExpr_Var bv)], + [arrayValueOpenTerm (bvTypeOpenTerm (8::Int)) $ + map (\b -> bvLitOpenTerm $ map (testBit b) [7,6..0]) bytes]) +-} +translateLLVMValue w _ (L.ValConstExpr ce) = + translateLLVMConstExpr w ce +translateLLVMValue w tp L.ValZeroInit = + llvmZeroInitValue tp >>= translateLLVMValue w tp +translateLLVMValue _ _ v = + traceAndZeroM ("translateLLVMValue does not yet handle:\n" ++ ppLLVMValue v) + +-- | Helper function for 'translateLLVMValue' +translateLLVMTypedValue :: (1 <= w, KnownNat w) => NatRepr w -> L.Typed L.Value -> + LLVMTransM (PermExpr (LLVMShapeType w), OpenTerm) +translateLLVMTypedValue w (L.Typed tp v) = translateLLVMValue w tp v + +-- | Translate an LLVM type into a shape plus the SAW core type of elements of +-- the translation of that shape +translateLLVMType :: (1 <= w, KnownNat w) => NatRepr w -> L.Type -> + LLVMTransM (PermExpr (LLVMShapeType w), OpenTerm) +translateLLVMType _ (L.PrimType (L.Integer n)) + | Just (Some (n_repr :: NatRepr n)) <- someNat n + , Left leq_pf <- decideLeq (knownNat @1) n_repr = + withKnownNat n_repr $ withLeqProof leq_pf $ + return (PExpr_FieldShape (LLVMFieldShape $ ValPerm_Exists $ nu $ \bv -> + ValPerm_Eq $ PExpr_LLVMWord $ + PExpr_Var (bv :: Name (BVType n))), + (bvTypeOpenTerm n)) +translateLLVMType _ tp = + traceAndZeroM ("translateLLVMType does not yet handle:\n" + ++ show (L.ppType tp)) + +-- | Helper function for 'translateLLVMValue' applied to a constant expression +translateLLVMConstExpr :: (1 <= w, KnownNat w) => NatRepr w -> L.ConstExpr -> + LLVMTransM (PermExpr (LLVMShapeType w), OpenTerm) +translateLLVMConstExpr w (L.ConstGEP _ _ _ (L.Typed tp ptr : ixs)) = + translateLLVMValue w tp ptr >>= \ptr_trans -> + translateLLVMGEP w tp ptr_trans ixs +translateLLVMConstExpr w (L.ConstConv L.BitCast + (L.Typed tp@(L.PtrTo _) v) (L.PtrTo _)) = + -- A bitcast from one LLVM pointer type to another is a no-op for us + translateLLVMValue w tp v +translateLLVMConstExpr _ ce = + traceAndZeroM ("translateLLVMConstExpr does not yet handle:\n" + ++ ppLLVMConstExpr ce) + +-- | Helper function for 'translateLLVMValue' applied to a @getelemptr@ +-- expression +translateLLVMGEP :: (1 <= w, KnownNat w) => NatRepr w -> L.Type -> + (PermExpr (LLVMShapeType w), OpenTerm) -> + [L.Typed L.Value] -> + LLVMTransM (PermExpr (LLVMShapeType w), OpenTerm) +translateLLVMGEP _ _ vtrans [] = return vtrans +translateLLVMGEP w (L.Array _ tp) vtrans (L.Typed _ (L.ValInteger 0) : ixs) = + translateLLVMGEP w tp vtrans ixs +translateLLVMGEP w (L.PtrTo tp) vtrans (L.Typed _ (L.ValInteger 0) : ixs) = + translateLLVMGEP w tp vtrans ixs +translateLLVMGEP w (L.PackedStruct [tp]) vtrans (L.Typed + _ (L.ValInteger 0) : ixs) = + translateLLVMGEP w tp vtrans ixs +translateLLVMGEP _ tp _ ixs = + traceAndZeroM ("translateLLVMGEP cannot handle arguments:\n" ++ + " " ++ intercalate "," (show tp : map show ixs)) + +-- | Build an LLVM value for a @zeroinitializer@ field of the supplied type +llvmZeroInitValue :: L.Type -> LLVMTransM (L.Value) +llvmZeroInitValue (L.PrimType (L.Integer _)) = return $ L.ValInteger 0 +llvmZeroInitValue (L.Array len tp) = + L.ValArray tp <$> replicate (fromIntegral len) <$> llvmZeroInitValue tp +llvmZeroInitValue (L.PackedStruct tps) = + L.ValPackedStruct <$> zipWith L.Typed tps <$> mapM llvmZeroInitValue tps +llvmZeroInitValue tp = + traceAndZeroM ("llvmZeroInitValue cannot handle type:\n" + ++ show (L.ppType tp)) + +-- | Add an LLVM global constant to a 'PermEnv', if the global has a type and +-- value we can translate to Heapster, otherwise silently ignore it +permEnvAddGlobalConst :: (1 <= w, KnownNat w) => DebugLevel -> NatRepr w -> + PermEnv -> L.Global -> PermEnv +permEnvAddGlobalConst dlevel w env global = + let sym = show (L.globalSym global) in + debugTrace dlevel ("Global: " ++ sym ++ "; value =\n" ++ + maybe "None" ppLLVMValue + (L.globalValue global)) $ + maybe env id $ + (\x -> case x of + Just _ -> debugTrace dlevel (sym ++ " translated") x + Nothing -> debugTrace dlevel (sym ++ " not translated") x) $ + flip runLLVMTransM (env,dlevel) $ + do val <- lift $ L.globalValue global + (sh, t) <- translateLLVMValue w (L.globalType global) val + let p = ValPerm_LLVMBlock $ llvmReadBlockOfShape sh + return $ permEnvAddGlobalSyms env + [PermEnvGlobalEntry (GlobalSymbol $ L.globalSym global) p [t]] diff --git a/src/SAWScript/HeapsterBuiltins.hs b/src/SAWScript/HeapsterBuiltins.hs index 162e5e72aa..33777a420d 100644 --- a/src/SAWScript/HeapsterBuiltins.hs +++ b/src/SAWScript/HeapsterBuiltins.hs @@ -49,7 +49,6 @@ module SAWScript.HeapsterBuiltins , heapster_set_debug_level ) where -import Data.Bits import Data.Maybe import qualified Data.Map as Map import Data.String @@ -59,7 +58,6 @@ import Data.IORef import Data.Functor.Product import Control.Lens import Control.Monad -import Control.Monad.Reader import Control.Monad.IO.Class import qualified Control.Monad.Fail as Fail import System.Directory @@ -97,7 +95,6 @@ import Lang.Crucible.LLVM.TypeContext import Lang.Crucible.LLVM.DataLayout import qualified Text.LLVM.AST as L -import qualified Text.LLVM.PP as L import SAWScript.TopLevel import SAWScript.Value @@ -113,13 +110,11 @@ import Verifier.SAW.Heapster.SAWTranslation import Verifier.SAW.Heapster.IRTTranslation import Verifier.SAW.Heapster.PermParser import Verifier.SAW.Heapster.ParsedCtx +import Verifier.SAW.Heapster.LLVMGlobalConst import SAWScript.Prover.Exporter import Verifier.SAW.Translation.Coq import Prettyprinter -import qualified Text.PrettyPrint.HughesPJ as PPHPJ - -import Debug.Trace -- | Extract out the contents of the 'Right' of an 'Either', calling 'fail' if @@ -262,161 +257,6 @@ parseAndInsDef henv nm term_tp term_string = liftIO $ scInsertDef sc mnm term_ident term_tp term return term_ident -type LLVMTransM = ReaderT PermEnv Maybe - -runLLVMTransM :: LLVMTransM a -> PermEnv -> Maybe a -runLLVMTransM = runReaderT - -ppLLVMValue :: L.Value -> String -ppLLVMValue val = - L.withConfig (L.Config True True True) (show $ PPHPJ.nest 2 $ L.ppValue val) - -ppLLVMConstExpr :: L.ConstExpr -> String -ppLLVMConstExpr ce = - L.withConfig (L.Config True True True) (show $ PPHPJ.nest 2 $ L.ppConstExpr ce) - --- | Translate a typed LLVM 'L.Value' to a Heapster permission + translation --- --- FIXME: move this to Permissions.hs -translateLLVMValue :: (1 <= w, KnownNat w) => NatRepr w -> L.Type -> L.Value -> - LLVMTransM (PermExpr (LLVMShapeType w), OpenTerm) -translateLLVMValue w tp@(L.PrimType (L.Integer n)) (L.ValInteger i) = - translateLLVMType w tp >>= \(sh,_) -> - return (sh, bvLitOpenTerm (map (testBit i) $ - reverse [0..(fromIntegral n)-1])) -translateLLVMValue w _ (L.ValSymbol sym) = - do env <- ask - -- (p, ts) <- lift (lookupGlobalSymbol env (GlobalSymbol sym) w) - (p, t) <- case (lookupGlobalSymbol env (GlobalSymbol sym) w) of - Just (p,[t]) -> return (p,t) - Just (p,ts) -> return (p,tupleOpenTerm ts) - Nothing -> trace ("Could not find symbol: " ++ show sym) mzero - return (PExpr_FieldShape (LLVMFieldShape p), t) -translateLLVMValue w _ (L.ValArray tp elems) = - do - -- First, translate the elements - ts <- map snd <$> mapM (translateLLVMValue w tp) elems - -- Array shapes can only handle field shapes elements, so translate the - -- element type to and ensure it returns a field shape; FIXME: this could - -- actually handle sequences of field shapes if necessary - (sh, saw_tp) <- translateLLVMType w tp - fsh <- case sh of - PExpr_FieldShape fsh -> return fsh - _ -> mzero - -- Compute the array stride as the length of the element shape - sh_len_expr <- lift $ llvmShapeLength sh - sh_len <- fromInteger <$> lift (bvMatchConstInt sh_len_expr) - - -- Finally, build our array shape and SAW core value - return (PExpr_ArrayShape (bvInt $ fromIntegral $ length elems) sh_len [fsh], - arrayValueOpenTerm saw_tp ts) -translateLLVMValue w _ (L.ValPackedStruct elems) = - mapM (translateLLVMTypedValue w) elems >>= \(unzip -> (shs,ts)) -> - return (foldr PExpr_SeqShape PExpr_EmptyShape shs, tupleOpenTerm ts) -translateLLVMValue w tp (L.ValString bytes) = - translateLLVMValue w tp (L.ValArray - (L.PrimType (L.Integer 8)) - (map (L.ValInteger . toInteger) bytes)) - {- - return (PExpr_ArrayShape (bvInt $ fromIntegral $ length bytes) 1 - [LLVMFieldShape (ValPerm_Exists $ nu $ \(bv :: Name (BVType 8)) -> - ValPerm_Eq $ PExpr_LLVMWord $ PExpr_Var bv)], - [arrayValueOpenTerm (bvTypeOpenTerm (8::Int)) $ - map (\b -> bvLitOpenTerm $ map (testBit b) [7,6..0]) bytes]) --} -translateLLVMValue w _ (L.ValConstExpr ce) = - translateLLVMConstExpr w ce -translateLLVMValue w tp L.ValZeroInit = - llvmZeroInitValue tp >>= translateLLVMValue w tp -translateLLVMValue _ _ v = - trace ("translateLLVMValue does not yet handle:\n" ++ ppLLVMValue v) - mzero - --- | Helper function for 'translateLLVMValue' -translateLLVMTypedValue :: (1 <= w, KnownNat w) => NatRepr w -> L.Typed L.Value -> - LLVMTransM (PermExpr (LLVMShapeType w), OpenTerm) -translateLLVMTypedValue w (L.Typed tp v) = translateLLVMValue w tp v - --- | Translate an LLVM type into a shape plus the SAW core type of elements of --- the translation of that shape -translateLLVMType :: (1 <= w, KnownNat w) => NatRepr w -> L.Type -> - LLVMTransM (PermExpr (LLVMShapeType w), OpenTerm) -translateLLVMType _ (L.PrimType (L.Integer n)) - | Just (Some (n_repr :: NatRepr n)) <- someNat n - , Left leq_pf <- decideLeq (knownNat @1) n_repr = - withKnownNat n_repr $ withLeqProof leq_pf $ - return (PExpr_FieldShape (LLVMFieldShape $ ValPerm_Exists $ nu $ \bv -> - ValPerm_Eq $ PExpr_LLVMWord $ - PExpr_Var (bv :: Name (BVType n))), - (bvTypeOpenTerm n)) -translateLLVMType _ tp = - trace ("translateLLVMType does not yet handle:\n" ++ show (L.ppType tp)) - mzero - --- | Helper function for 'translateLLVMValue' -translateLLVMConstExpr :: (1 <= w, KnownNat w) => NatRepr w -> L.ConstExpr -> - LLVMTransM (PermExpr (LLVMShapeType w), OpenTerm) -translateLLVMConstExpr w (L.ConstGEP _ _ _ (L.Typed tp ptr : ixs)) = - translateLLVMValue w tp ptr >>= \ptr_trans -> - translateLLVMGEP w tp ptr_trans ixs -translateLLVMConstExpr w (L.ConstConv L.BitCast - (L.Typed tp@(L.PtrTo _) v) (L.PtrTo _)) = - -- A bitcast from one LLVM pointer type to another is a no-op for us - translateLLVMValue w tp v -translateLLVMConstExpr _ ce = - trace ("translateLLVMConstExpr does not yet handle:\n" ++ ppLLVMConstExpr ce) - mzero - --- | Helper function for 'translateLLVMValue' -translateLLVMGEP :: (1 <= w, KnownNat w) => NatRepr w -> L.Type -> - (PermExpr (LLVMShapeType w), OpenTerm) -> - [L.Typed L.Value] -> - LLVMTransM (PermExpr (LLVMShapeType w), OpenTerm) -translateLLVMGEP _ _ vtrans [] = return vtrans -translateLLVMGEP w (L.Array _ tp) vtrans (L.Typed _ (L.ValInteger 0) : ixs) = - translateLLVMGEP w tp vtrans ixs -translateLLVMGEP w (L.PtrTo tp) vtrans (L.Typed _ (L.ValInteger 0) : ixs) = - translateLLVMGEP w tp vtrans ixs -translateLLVMGEP w (L.PackedStruct [tp]) vtrans (L.Typed _ (L.ValInteger 0) : ixs) = - translateLLVMGEP w tp vtrans ixs -translateLLVMGEP _ tp _ ixs = - trace ("translateLLVMGEP cannot handle arguments:\n" ++ - " " ++ intercalate "," (show tp : map show ixs)) - mzero - --- | Build an LLVM value for a @zeroinitializer@ field of the supplied type -llvmZeroInitValue :: L.Type -> LLVMTransM (L.Value) -llvmZeroInitValue (L.PrimType (L.Integer _)) = return $ L.ValInteger 0 -llvmZeroInitValue (L.Array len tp) = - L.ValArray tp <$> replicate (fromIntegral len) <$> llvmZeroInitValue tp -llvmZeroInitValue (L.PackedStruct tps) = - L.ValPackedStruct <$> zipWith L.Typed tps <$> mapM llvmZeroInitValue tps -llvmZeroInitValue tp = - trace ("llvmZeroInitValue cannot handle type:\n" ++ show (L.ppType tp)) - mzero - --- | Add an LLVM global constant to a 'PermEnv', if the global has a type and --- value we can translate to Heapster, otherwise silently ignore it --- --- FIXME: move this to Permissions.hs -permEnvAddGlobalConst :: (1 <= w, KnownNat w) => NatRepr w -> - PermEnv -> L.Global -> PermEnv -permEnvAddGlobalConst w env global = - let sym = show (L.globalSym global) in - trace ("Global: " ++ sym ++ "; value =\n" ++ - maybe "None" ppLLVMValue - (L.globalValue global)) $ - maybe env id $ - (\x -> case x of - Just _ -> trace (sym ++ " translated") x - Nothing -> trace (sym ++ " not translated") x) $ - flip runLLVMTransM env $ - do val <- lift $ L.globalValue global - (sh, t) <- translateLLVMValue w (L.globalType global) val - let p = ValPerm_LLVMBlock $ llvmReadBlockOfShape sh - return $ permEnvAddGlobalSyms env - [PermEnvGlobalEntry (GlobalSymbol $ L.globalSym global) p [t]] - -- | Build a 'HeapsterEnv' associated with the given SAW core module and the -- given 'LLVMModule's. Add any globals in the 'LLVMModule's to the returned -- 'HeapsterEnv'. @@ -427,9 +267,11 @@ mkHeapsterEnv saw_mod_name llvm_mods@(Some first_mod:_) = Left pf -> return pf Right _ -> fail "LLVM arch width is 0!" let globals = concatMap (\(Some lm) -> L.modGlobals $ modAST lm) llvm_mods + dlevel = noDebugLevel -- FIXME: how to set the debug level for + -- permEnvAddGlobalConst? env = withKnownNat w $ withLeqProof leq_proof $ - foldl (permEnvAddGlobalConst w) heapster_default_env globals + foldl (permEnvAddGlobalConst dlevel w) heapster_default_env globals env_ref <- liftIO $ newIORef env dlevel_ref <- liftIO $ newIORef noDebugLevel return $ HeapsterEnv { From 1eb23238e423c9153bbca7b1ac0788106dec249e Mon Sep 17 00:00:00 2001 From: Eddy Westbrook Date: Tue, 14 Sep 2021 13:46:59 -0700 Subject: [PATCH 29/98] fixed the translation of LLVM array constants to generate SAW core BVVecs instead of SAW core Vecs --- .../Verifier/SAW/Heapster/LLVMGlobalConst.hs | 31 +++++++++++++++++-- saw-core/prelude/Prelude.sawcore | 8 +++++ 2 files changed, 36 insertions(+), 3 deletions(-) diff --git a/heapster-saw/src/Verifier/SAW/Heapster/LLVMGlobalConst.hs b/heapster-saw/src/Verifier/SAW/Heapster/LLVMGlobalConst.hs index 4f377e783b..d739d24ce8 100644 --- a/heapster-saw/src/Verifier/SAW/Heapster/LLVMGlobalConst.hs +++ b/heapster-saw/src/Verifier/SAW/Heapster/LLVMGlobalConst.hs @@ -29,6 +29,25 @@ import Lang.Crucible.LLVM.MemModel import Verifier.SAW.OpenTerm import Verifier.SAW.Heapster.Permissions +-- | Generate a SAW core term for a bitvector literal whose length is given by +-- the first integer and whose value is given by the second +bvLitOfIntOpenTerm :: Integer -> Integer -> OpenTerm +bvLitOfIntOpenTerm n i = + bvLitOpenTerm (map (testBit i) $ reverse [0..(fromIntegral n)-1]) + +-- | Helper function to build a SAW core term of type @BVVec w len a@, i.e., a +-- bitvector-indexed vector, containing a given list of elements of type +-- @a@. The roundabout way we do this currently requires a default element of +-- type @a@, even though this value is never actually used. Also required is the +-- bitvector width @w@. +bvVecValueOpenTerm :: NatRepr w -> OpenTerm -> [OpenTerm] -> OpenTerm -> + OpenTerm +bvVecValueOpenTerm w tp ts def_tm = + applyOpenTermMulti (globalOpenTerm "Prelude.genBVVecFromVec") + [natOpenTerm (fromIntegral $ length ts), tp, arrayValueOpenTerm tp ts, + def_tm, natOpenTerm (natValue w), + bvLitOfIntOpenTerm (intValue w) (fromIntegral $ length ts)] + -- | The monad for translating LLVM globals to Heapster type LLVMTransM = ReaderT (PermEnv, DebugLevel) Maybe @@ -57,8 +76,7 @@ translateLLVMValue :: (1 <= w, KnownNat w) => NatRepr w -> L.Type -> L.Value -> LLVMTransM (PermExpr (LLVMShapeType w), OpenTerm) translateLLVMValue w tp@(L.PrimType (L.Integer n)) (L.ValInteger i) = translateLLVMType w tp >>= \(sh,_) -> - return (sh, bvLitOpenTerm (map (testBit i) $ - reverse [0..(fromIntegral n)-1])) + return (sh, bvLitOfIntOpenTerm (fromIntegral n) i) translateLLVMValue w _ (L.ValSymbol sym) = do (env,_) <- ask -- (p, ts) <- lift (lookupGlobalSymbol env (GlobalSymbol sym) w) @@ -71,6 +89,7 @@ translateLLVMValue w _ (L.ValArray tp elems) = do -- First, translate the elements ts <- map snd <$> mapM (translateLLVMValue w tp) elems + -- Array shapes can only handle field shapes elements, so translate the -- element type to and ensure it returns a field shape; FIXME: this could -- actually handle sequences of field shapes if necessary @@ -78,13 +97,19 @@ translateLLVMValue w _ (L.ValArray tp elems) = fsh <- case sh of PExpr_FieldShape fsh -> return fsh _ -> mzero + -- Compute the array stride as the length of the element shape sh_len_expr <- lift $ llvmShapeLength sh sh_len <- fromInteger <$> lift (bvMatchConstInt sh_len_expr) + -- Generate a default element of type tp using the zero initializer; this is + -- currently needed by bvVecValueOpenTerm + def_v <- llvmZeroInitValue tp + (_,def_tm) <- translateLLVMValue w tp def_v + -- Finally, build our array shape and SAW core value return (PExpr_ArrayShape (bvInt $ fromIntegral $ length elems) sh_len [fsh], - arrayValueOpenTerm saw_tp ts) + bvVecValueOpenTerm w saw_tp ts def_tm) translateLLVMValue w _ (L.ValPackedStruct elems) = mapM (translateLLVMTypedValue w) elems >>= \(unzip -> (shs,ts)) -> return (foldr PExpr_SeqShape PExpr_EmptyShape shs, tupleOpenTerm ts) diff --git a/saw-core/prelude/Prelude.sawcore b/saw-core/prelude/Prelude.sawcore index 73127d79e2..fd50f097eb 100644 --- a/saw-core/prelude/Prelude.sawcore +++ b/saw-core/prelude/Prelude.sawcore @@ -1623,6 +1623,14 @@ genBVVec n len a f = (\(i:Nat) (pf:IsLtNat i (bvToNat n len)) -> f (bvNat n i) (IsLtNat_to_bvult n len i pf)); +-- Generate a BVVec from the elements of an existing vector, using a default +-- value when we run out of the existing vector +genBVVecFromVec : (m : Nat) -> (a : sort 0) -> Vec m a -> a -> + (n : Nat) -> (len : Vec n Bool) -> BVVec n len a; +genBVVecFromVec m a v def n len = + genBVVec n len a (\ (i:Vec n Bool) (_:is_bvult n i len) -> + atWithDefault m a def v (bvToNat n i)); + -- Ex Falso Quodlibet: if True = False then anything is possible efq : (a : sort 0) -> Eq Bool True False -> a; efq a contra = From 9347756c40bfba6be3fea4b93bf093ce0c39500d Mon Sep 17 00:00:00 2001 From: Eddy Westbrook Date: Tue, 14 Sep 2021 13:49:36 -0700 Subject: [PATCH 30/98] regenerated Coq files for saw-core-coq --- .../CryptolPrimitivesForSAWCore.v | 85 +++++++++++++++++-- .../generated/CryptolToCoq/SAWCorePrelude.v | 43 +++++++--- 2 files changed, 112 insertions(+), 16 deletions(-) diff --git a/saw-core-coq/coq/generated/CryptolToCoq/CryptolPrimitivesForSAWCore.v b/saw-core-coq/coq/generated/CryptolToCoq/CryptolPrimitivesForSAWCore.v index 28b94c7cd2..38baeac59c 100644 --- a/saw-core-coq/coq/generated/CryptolToCoq/CryptolPrimitivesForSAWCore.v +++ b/saw-core-coq/coq/generated/CryptolToCoq/CryptolPrimitivesForSAWCore.v @@ -44,8 +44,10 @@ Definition getFinNat : forall (n : @Num), @SAWCoreScaffolding.Nat := Definition finNumRec : forall (p : @Num -> Type), (forall (n : @SAWCoreScaffolding.Nat), p (@TCNum n)) -> forall (n : @Num), p n := fun (p : @Num -> Type) (f : forall (n : @SAWCoreScaffolding.Nat), p (@TCNum n)) (n : @Num) => CryptolPrimitivesForSAWCore.Num_rect p f (@SAWCoreScaffolding.error (p (@TCInf)) "Unexpected Fin constraint violation!"%string) n. -Definition finNumRec2 : forall (p : @Num -> @Num -> Type), (forall (m : @SAWCoreScaffolding.Nat), forall (n : @SAWCoreScaffolding.Nat), p (@TCNum m) (@TCNum n)) -> forall (m : @Num), forall (n : @Num), p m n := - fun (p : @Num -> @Num -> Type) (f : forall (m : @SAWCoreScaffolding.Nat), forall (n : @SAWCoreScaffolding.Nat), p (@TCNum m) (@TCNum n)) => @finNumRec (fun (m : @Num) => forall (n : @Num), p m n) (fun (m : @SAWCoreScaffolding.Nat) => @finNumRec (p (@TCNum m)) (f m)). +Definition finNumRec2 : forall (p : @Num -> @Num -> Type), (forall (m : @SAWCoreScaffolding.Nat), forall (n : @SAWCoreScaffolding.Nat), let var__0 := @SAWCoreScaffolding.Nat -> @Num in + p (@TCNum m) (@TCNum n)) -> forall (m : @Num), forall (n : @Num), p m n := + fun (p : @Num -> @Num -> Type) (f : forall (m : @SAWCoreScaffolding.Nat), forall (n : @SAWCoreScaffolding.Nat), let var__0 := @SAWCoreScaffolding.Nat -> @Num in + p (@TCNum m) (@TCNum n)) => @finNumRec (fun (m : @Num) => forall (n : @Num), p m n) (fun (m : @SAWCoreScaffolding.Nat) => @finNumRec (p (@TCNum m)) (f m)). Definition binaryNumFun : (@SAWCoreScaffolding.Nat -> @SAWCoreScaffolding.Nat -> @SAWCoreScaffolding.Nat) -> (@SAWCoreScaffolding.Nat -> @Num) -> (@SAWCoreScaffolding.Nat -> @Num) -> @Num -> @Num -> @Num -> @Num := fun (f1 : @SAWCoreScaffolding.Nat -> @SAWCoreScaffolding.Nat -> @SAWCoreScaffolding.Nat) (f2 : @SAWCoreScaffolding.Nat -> @Num) (f3 : @SAWCoreScaffolding.Nat -> @Num) (f4 : @Num) (num1 : @Num) (num2 : @Num) => CryptolPrimitivesForSAWCore.Num_rect (fun (num1' : @Num) => @Num) (fun (n1 : @SAWCoreScaffolding.Nat) => CryptolPrimitivesForSAWCore.Num_rect (fun (num2' : @Num) => @Num) (fun (n2 : @SAWCoreScaffolding.Nat) => @TCNum (f1 n1 n2)) (f2 n1) num2) (CryptolPrimitivesForSAWCore.Num_rect (fun (num2' : @Num) => @Num) f3 f4 num2) num1. @@ -90,7 +92,7 @@ Definition tcCeilDiv : @Num -> @Num -> @Num := @binaryNumFun ceilDivNat (fun (x : @SAWCoreScaffolding.Nat) => @TCNum 0) (fun (y : @SAWCoreScaffolding.Nat) => @TCInf) (@TCInf). Definition tcCeilMod : @Num -> @Num -> @Num := - @binaryNumFun ceilModNat (fun (x : @SAWCoreScaffolding.Nat) => @TCNum 0) (fun (y : @SAWCoreScaffolding.Nat) => @TCInf) (@TCInf). + @binaryNumFun ceilModNat (fun (x : @SAWCoreScaffolding.Nat) => @TCNum 0) (fun (y : @SAWCoreScaffolding.Nat) => @TCNum 0) (@TCInf). Definition tcLenFromThenTo_Nat : @SAWCoreScaffolding.Nat -> @SAWCoreScaffolding.Nat -> @SAWCoreScaffolding.Nat -> @SAWCoreScaffolding.Nat := fun (x : @SAWCoreScaffolding.Nat) (y : @SAWCoreScaffolding.Nat) (z : @SAWCoreScaffolding.Nat) => if @SAWCorePrelude.ltNat x y then if @SAWCorePrelude.ltNat z x then 0 else @SAWCorePrelude.addNat (@SAWCorePrelude.divNat (@SAWCorePrelude.subNat z x) (@SAWCorePrelude.subNat y x)) 1 else if @SAWCorePrelude.ltNat x z then 0 else @SAWCorePrelude.addNat (@SAWCorePrelude.divNat (@SAWCorePrelude.subNat x z) (@SAWCorePrelude.subNat x y)) 1. @@ -607,8 +609,9 @@ Definition ecAt : forall (n : @Num), forall (a : Type), forall (ix : Type), @PIn Definition ecAtBack : forall (n : @Num), forall (a : Type), forall (ix : Type), @PIntegral ix -> @seq n a -> ix -> a := fun (n : @Num) (a : Type) (ix : Type) (pix : RecordTypeCons "div" (ix -> ix -> ix) (RecordTypeCons "integralRing" (RecordTypeCons "add" (ix -> ix -> ix) (RecordTypeCons "int" (@SAWCoreScaffolding.Integer -> ix) (RecordTypeCons "mul" (ix -> ix -> ix) (RecordTypeCons "neg" (ix -> ix) (RecordTypeCons "ringZero" ix (RecordTypeCons "sub" (ix -> ix -> ix) RecordTypeNil)))))) (RecordTypeCons "mod" (ix -> ix -> ix) (RecordTypeCons "posNegCases" (forall (r : Type), (@SAWCoreScaffolding.Nat -> r) -> (@SAWCoreScaffolding.Nat -> r) -> ix -> r) (RecordTypeCons "toInt" (ix -> @SAWCoreScaffolding.Integer) RecordTypeNil))))) (xs : CryptolPrimitivesForSAWCore.Num_rect (fun (num : @Num) => Type) (fun (n1 : @SAWCoreScaffolding.Nat) => @SAWCoreVectorsAsCoqVectors.Vec n1 a) (@SAWCorePrelude.Stream a) n) => @ecAt n a ix pix (@ecReverse n a xs). -Definition ecFromTo : forall (first : @Num), forall (last : @Num), forall (a : Type), @PLiteral a -> @PLiteral a -> @seq (@tcAdd (@TCNum 1) (@tcSub last first)) a := - @finNumRec (fun (first : @Num) => forall (last : @Num), forall (a : Type), @PLiteral a -> @PLiteral a -> @seq (@tcAdd (@TCNum 1) (@tcSub last first)) a) (fun (first : @SAWCoreScaffolding.Nat) => @finNumRec (fun (last : @Num) => forall (a : Type), @PLiteral a -> @PLiteral a -> @seq (@tcAdd (@TCNum 1) (@tcSub last (@TCNum first))) a) (fun (last : @SAWCoreScaffolding.Nat) (a : Type) (pa : @SAWCoreScaffolding.Nat -> a) (_1 : @SAWCoreScaffolding.Nat -> a) => @SAWCoreVectorsAsCoqVectors.gen (@SAWCorePrelude.addNat 1 (@SAWCorePrelude.subNat last first)) a (fun (i : @SAWCoreScaffolding.Nat) => pa (@SAWCorePrelude.addNat i first)))). +Definition ecFromTo : forall (first : @Num), forall (last : @Num), forall (a : Type), @PLiteral a -> @seq (@tcAdd (@TCNum 1) (@tcSub last first)) a := + @finNumRec (fun (first : @Num) => forall (last : @Num), forall (a : Type), @PLiteral a -> @seq (@tcAdd (@TCNum 1) (@tcSub last first)) a) (fun (first : @SAWCoreScaffolding.Nat) => @finNumRec (fun (last : @Num) => forall (a : Type), @PLiteral a -> let var__0 := @SAWCoreScaffolding.Nat -> @Num in + @seq (@tcAdd (@TCNum 1) (@tcSub last (@TCNum first))) a) (fun (last : @SAWCoreScaffolding.Nat) (a : Type) (pa : @SAWCoreScaffolding.Nat -> a) => @SAWCoreVectorsAsCoqVectors.gen (@SAWCorePrelude.addNat 1 (@SAWCorePrelude.subNat last first)) a (fun (i : @SAWCoreScaffolding.Nat) => pa (@SAWCorePrelude.addNat i first)))). Definition ecFromToLessThan : forall (first : @Num), forall (bound : @Num), forall (a : Type), @PLiteralLessThan a -> @seq (@tcSub bound first) a := fun (first : @Num) (bound : @Num) (a : Type) => @finNumRec (fun (first1 : @Num) => @PLiteralLessThan a -> @seq (@tcSub bound first1) a) (fun (first1 : @SAWCoreScaffolding.Nat) => CryptolPrimitivesForSAWCore.Num_rect (fun (bound1 : @Num) => @PLiteralLessThan a -> @seq (@tcSub bound1 (@TCNum first1)) a) (fun (bound1 : @SAWCoreScaffolding.Nat) (pa : @SAWCoreScaffolding.Nat -> a) => @SAWCoreVectorsAsCoqVectors.gen (@SAWCorePrelude.subNat bound1 first1) a (fun (i : @SAWCoreScaffolding.Nat) => pa (@SAWCorePrelude.addNat i first1))) (fun (pa : @SAWCoreScaffolding.Nat -> a) => @SAWCorePrelude.MkStream a (fun (i : @SAWCoreScaffolding.Nat) => pa (@SAWCorePrelude.addNat i first1))) bound) first. @@ -616,6 +619,22 @@ Definition ecFromToLessThan : forall (first : @Num), forall (bound : @Num), fora Definition ecFromThenTo : forall (first : @Num), forall (next : @Num), forall (last : @Num), forall (a : Type), forall (len : @Num), @PLiteral a -> @PLiteral a -> @PLiteral a -> @seq len a := fun (first : @Num) (next : @Num) (_1 : @Num) (a : Type) => @finNumRec (fun (len : @Num) => @PLiteral a -> @PLiteral a -> @PLiteral a -> @seq len a) (fun (len : @SAWCoreScaffolding.Nat) (pa : @SAWCoreScaffolding.Nat -> a) (_2 : @SAWCoreScaffolding.Nat -> a) (_3 : @SAWCoreScaffolding.Nat -> a) => @SAWCoreVectorsAsCoqVectors.gen len a (fun (i : @SAWCoreScaffolding.Nat) => pa (@SAWCorePrelude.subNat (@SAWCorePrelude.addNat (@getFinNat first) (@SAWCorePrelude.mulNat i (@getFinNat next))) (@SAWCorePrelude.mulNat i (@getFinNat first))))). +Definition ecFromToBy : forall (first : @Num), forall (last : @Num), forall (stride : @Num), forall (a : Type), @PLiteral a -> @seq (@tcAdd (@TCNum 1) (@tcDiv (@tcSub last first) stride)) a := + @finNumRec (fun (first : @Num) => forall (last : @Num), forall (stride : @Num), forall (a : Type), @PLiteral a -> @seq (@tcAdd (@TCNum 1) (@tcDiv (@tcSub last first) stride)) a) (fun (first : @SAWCoreScaffolding.Nat) => @finNumRec (fun (last : @Num) => forall (stride : @Num), forall (a : Type), @PLiteral a -> let var__0 := @SAWCoreScaffolding.Nat -> @Num in + @seq (@tcAdd (@TCNum 1) (@tcDiv (@tcSub last (@TCNum first)) stride)) a) (fun (last : @SAWCoreScaffolding.Nat) => @finNumRec (fun (stride : @Num) => forall (a : Type), @PLiteral a -> let var__0 := @SAWCoreScaffolding.Nat -> @Num in + @seq (@tcAdd (@TCNum 1) (@tcDiv (@TCNum (@SAWCorePrelude.subNat last first)) stride)) a) (fun (stride : @SAWCoreScaffolding.Nat) (a : Type) (pa : @SAWCoreScaffolding.Nat -> a) => @SAWCoreVectorsAsCoqVectors.gen (@SAWCorePrelude.addNat 1 (@SAWCorePrelude.divNat (@SAWCorePrelude.subNat last first) stride)) a (fun (i : @SAWCoreScaffolding.Nat) => pa (@SAWCorePrelude.addNat first (@SAWCorePrelude.mulNat i stride)))))). + +Definition ecFromToByLessThan : forall (first : @Num), forall (bound : @Num), forall (stride : @Num), forall (a : Type), @PLiteralLessThan a -> @seq (@tcCeilDiv (@tcSub bound first) stride) a := + @finNumRec (fun (first : @Num) => forall (bound : @Num), forall (stride : @Num), forall (a : Type), @PLiteralLessThan a -> @seq (@tcCeilDiv (@tcSub bound first) stride) a) (fun (first : @SAWCoreScaffolding.Nat) => @CryptolPrimitivesForSAWCore.Num_rect (fun (bound : @Num) => forall (stride : @Num), forall (a : Type), @PLiteralLessThan a -> @seq (@tcCeilDiv (@tcSub bound (@TCNum first)) stride) a) (fun (bound : @SAWCoreScaffolding.Nat) => @finNumRec (fun (stride : @Num) => forall (a : Type), @PLiteralLessThan a -> @seq (@tcCeilDiv (@TCNum (@SAWCorePrelude.subNat bound first)) stride) a) (fun (stride : @SAWCoreScaffolding.Nat) (a : Type) (pa : @SAWCoreScaffolding.Nat -> a) => @SAWCoreVectorsAsCoqVectors.gen (@ceilDivNat (@SAWCorePrelude.subNat bound first) stride) a (fun (i : @SAWCoreScaffolding.Nat) => pa (@SAWCorePrelude.addNat first (@SAWCorePrelude.mulNat i stride))))) (@finNumRec (fun (stride : @Num) => forall (a : Type), @PLiteralLessThan a -> @seq (@tcCeilDiv (@TCInf) stride) a) (fun (stride : @SAWCoreScaffolding.Nat) (a : Type) (pa : @SAWCoreScaffolding.Nat -> a) => @SAWCorePrelude.MkStream a (fun (i : @SAWCoreScaffolding.Nat) => pa (@SAWCorePrelude.addNat first (@SAWCorePrelude.mulNat i stride)))))). + +Definition ecFromToDownBy : forall (first : @Num), forall (last : @Num), forall (stride : @Num), forall (a : Type), @PLiteral a -> @seq (@tcAdd (@TCNum 1) (@tcDiv (@tcSub first last) stride)) a := + @finNumRec (fun (first : @Num) => forall (last : @Num), forall (stride : @Num), forall (a : Type), @PLiteral a -> @seq (@tcAdd (@TCNum 1) (@tcDiv (@tcSub first last) stride)) a) (fun (first : @SAWCoreScaffolding.Nat) => @finNumRec (fun (last : @Num) => forall (stride : @Num), forall (a : Type), @PLiteral a -> let var__0 := @SAWCoreScaffolding.Nat -> @Num in + @seq (@tcAdd (@TCNum 1) (@tcDiv (@tcSub (@TCNum first) last) stride)) a) (fun (last : @SAWCoreScaffolding.Nat) => @finNumRec (fun (stride : @Num) => forall (a : Type), @PLiteral a -> let var__0 := @SAWCoreScaffolding.Nat -> @Num in + @seq (@tcAdd (@TCNum 1) (@tcDiv (@TCNum (@SAWCorePrelude.subNat first last)) stride)) a) (fun (stride : @SAWCoreScaffolding.Nat) (a : Type) (pa : @SAWCoreScaffolding.Nat -> a) => @SAWCoreVectorsAsCoqVectors.gen (@SAWCorePrelude.addNat 1 (@SAWCorePrelude.divNat (@SAWCorePrelude.subNat first last) stride)) a (fun (i : @SAWCoreScaffolding.Nat) => pa (@SAWCorePrelude.subNat first (@SAWCorePrelude.mulNat i stride)))))). + +Definition ecFromToDownByGreaterThan : forall (first : @Num), forall (bound : @Num), forall (stride : @Num), forall (a : Type), @PLiteral a -> @seq (@tcCeilDiv (@tcSub first bound) stride) a := + @finNumRec (fun (first : @Num) => forall (bound : @Num), forall (stride : @Num), forall (a : Type), @PLiteral a -> @seq (@tcCeilDiv (@tcSub first bound) stride) a) (fun (first : @SAWCoreScaffolding.Nat) => @finNumRec (fun (bound : @Num) => forall (stride : @Num), forall (a : Type), @PLiteral a -> @seq (@tcCeilDiv (@tcSub (@TCNum first) bound) stride) a) (fun (bound : @SAWCoreScaffolding.Nat) => @finNumRec (fun (stride : @Num) => forall (a : Type), @PLiteral a -> @seq (@tcCeilDiv (@TCNum (@SAWCorePrelude.subNat first bound)) stride) a) (fun (stride : @SAWCoreScaffolding.Nat) (a : Type) (pa : @SAWCoreScaffolding.Nat -> a) => @SAWCoreVectorsAsCoqVectors.gen (@ceilDivNat (@SAWCorePrelude.subNat first bound) stride) a (fun (i : @SAWCoreScaffolding.Nat) => pa (@SAWCorePrelude.subNat first (@SAWCorePrelude.mulNat i stride)))))). + Definition ecInfFrom : forall (a : Type), @PIntegral a -> a -> @seq (@TCInf) a := fun (a : Type) (pa : RecordTypeCons "div" (a -> a -> a) (RecordTypeCons "integralRing" (RecordTypeCons "add" (a -> a -> a) (RecordTypeCons "int" (@SAWCoreScaffolding.Integer -> a) (RecordTypeCons "mul" (a -> a -> a) (RecordTypeCons "neg" (a -> a) (RecordTypeCons "ringZero" a (RecordTypeCons "sub" (a -> a -> a) RecordTypeNil)))))) (RecordTypeCons "mod" (a -> a -> a) (RecordTypeCons "posNegCases" (forall (r : Type), (@SAWCoreScaffolding.Nat -> r) -> (@SAWCoreScaffolding.Nat -> r) -> a -> r) (RecordTypeCons "toInt" (a -> @SAWCoreScaffolding.Integer) RecordTypeNil))))) (x : a) => @SAWCorePrelude.MkStream a (fun (i : @SAWCoreScaffolding.Nat) => RecordProj (RecordProj pa "integralRing") "add" x (RecordProj (RecordProj pa "integralRing") "int" (@SAWCoreScaffolding.natToInt i))). @@ -763,6 +782,62 @@ Definition ecArrayLookup : forall (a : Type), forall (b : Type), @SAWCorePrelude Definition ecArrayUpdate : forall (a : Type), forall (b : Type), @SAWCorePrelude.Array a b -> a -> b -> @SAWCorePrelude.Array a b := @SAWCorePrelude.arrayUpdate. +Definition ecArrayCopy : forall (n : @Num), forall (a : Type), @SAWCorePrelude.Array (@seq n (@SAWCoreScaffolding.Bool)) a -> @seq n (@SAWCoreScaffolding.Bool) -> @SAWCorePrelude.Array (@seq n (@SAWCoreScaffolding.Bool)) a -> @seq n (@SAWCoreScaffolding.Bool) -> @seq n (@SAWCoreScaffolding.Bool) -> @SAWCorePrelude.Array (@seq n (@SAWCoreScaffolding.Bool)) a := + @finNumRec (fun (n : @Num) => forall (a : Type), @SAWCorePrelude.Array (@seq n (@SAWCoreScaffolding.Bool)) a -> @seq n (@SAWCoreScaffolding.Bool) -> @SAWCorePrelude.Array (@seq n (@SAWCoreScaffolding.Bool)) a -> @seq n (@SAWCoreScaffolding.Bool) -> @seq n (@SAWCoreScaffolding.Bool) -> @SAWCorePrelude.Array (@seq n (@SAWCoreScaffolding.Bool)) a) (@SAWCorePrelude.arrayCopy). + +Definition ecArraySet : forall (n : @Num), forall (a : Type), @SAWCorePrelude.Array (@seq n (@SAWCoreScaffolding.Bool)) a -> @seq n (@SAWCoreScaffolding.Bool) -> a -> @seq n (@SAWCoreScaffolding.Bool) -> @SAWCorePrelude.Array (@seq n (@SAWCoreScaffolding.Bool)) a := + @finNumRec (fun (n : @Num) => forall (a : Type), @SAWCorePrelude.Array (@seq n (@SAWCoreScaffolding.Bool)) a -> @seq n (@SAWCoreScaffolding.Bool) -> a -> @seq n (@SAWCoreScaffolding.Bool) -> @SAWCorePrelude.Array (@seq n (@SAWCoreScaffolding.Bool)) a) (@SAWCorePrelude.arraySet). + +Definition ecArrayRangeEq : forall (n : @Num), forall (a : Type), @SAWCorePrelude.Array (@seq n (@SAWCoreScaffolding.Bool)) a -> @seq n (@SAWCoreScaffolding.Bool) -> @SAWCorePrelude.Array (@seq n (@SAWCoreScaffolding.Bool)) a -> @seq n (@SAWCoreScaffolding.Bool) -> @seq n (@SAWCoreScaffolding.Bool) -> @SAWCoreScaffolding.Bool := + @finNumRec (fun (n : @Num) => forall (a : Type), @SAWCorePrelude.Array (@seq n (@SAWCoreScaffolding.Bool)) a -> @seq n (@SAWCoreScaffolding.Bool) -> @SAWCorePrelude.Array (@seq n (@SAWCoreScaffolding.Bool)) a -> @seq n (@SAWCoreScaffolding.Bool) -> @seq n (@SAWCoreScaffolding.Bool) -> @SAWCoreScaffolding.Bool) (@SAWCorePrelude.arrayRangeEq). + +Definition AESEncRound : @SAWCoreVectorsAsCoqVectors.Vec 4 (@SAWCoreVectorsAsCoqVectors.Vec 32 (@SAWCoreScaffolding.Bool)) -> @SAWCoreVectorsAsCoqVectors.Vec 4 (@SAWCoreVectorsAsCoqVectors.Vec 32 (@SAWCoreScaffolding.Bool)) := + fun (x : @SAWCoreVectorsAsCoqVectors.Vec 4 (@SAWCoreVectorsAsCoqVectors.Vec 32 (@SAWCoreScaffolding.Bool))) => @SAWCoreScaffolding.error (@SAWCoreVectorsAsCoqVectors.Vec 4 (@SAWCoreVectorsAsCoqVectors.Vec 32 (@SAWCoreScaffolding.Bool))) "Unimplemented: AESEncRound"%string. + +Definition AESEncFinalRound : @SAWCoreVectorsAsCoqVectors.Vec 4 (@SAWCoreVectorsAsCoqVectors.Vec 32 (@SAWCoreScaffolding.Bool)) -> @SAWCoreVectorsAsCoqVectors.Vec 4 (@SAWCoreVectorsAsCoqVectors.Vec 32 (@SAWCoreScaffolding.Bool)) := + fun (x : @SAWCoreVectorsAsCoqVectors.Vec 4 (@SAWCoreVectorsAsCoqVectors.Vec 32 (@SAWCoreScaffolding.Bool))) => @SAWCoreScaffolding.error (@SAWCoreVectorsAsCoqVectors.Vec 4 (@SAWCoreVectorsAsCoqVectors.Vec 32 (@SAWCoreScaffolding.Bool))) "Unimplemented: AESEncFinalRound"%string. + +Definition AESDecRound : @SAWCoreVectorsAsCoqVectors.Vec 4 (@SAWCoreVectorsAsCoqVectors.Vec 32 (@SAWCoreScaffolding.Bool)) -> @SAWCoreVectorsAsCoqVectors.Vec 4 (@SAWCoreVectorsAsCoqVectors.Vec 32 (@SAWCoreScaffolding.Bool)) := + fun (x : @SAWCoreVectorsAsCoqVectors.Vec 4 (@SAWCoreVectorsAsCoqVectors.Vec 32 (@SAWCoreScaffolding.Bool))) => @SAWCoreScaffolding.error (@SAWCoreVectorsAsCoqVectors.Vec 4 (@SAWCoreVectorsAsCoqVectors.Vec 32 (@SAWCoreScaffolding.Bool))) "Unimplemented: AESDecRound"%string. + +Definition AESDecFinalRound : @SAWCoreVectorsAsCoqVectors.Vec 4 (@SAWCoreVectorsAsCoqVectors.Vec 32 (@SAWCoreScaffolding.Bool)) -> @SAWCoreVectorsAsCoqVectors.Vec 4 (@SAWCoreVectorsAsCoqVectors.Vec 32 (@SAWCoreScaffolding.Bool)) := + fun (x : @SAWCoreVectorsAsCoqVectors.Vec 4 (@SAWCoreVectorsAsCoqVectors.Vec 32 (@SAWCoreScaffolding.Bool))) => @SAWCoreScaffolding.error (@SAWCoreVectorsAsCoqVectors.Vec 4 (@SAWCoreVectorsAsCoqVectors.Vec 32 (@SAWCoreScaffolding.Bool))) "Unimplemented: AESDecFinalRound"%string. + +Definition AESInvMixColumns : @SAWCoreVectorsAsCoqVectors.Vec 4 (@SAWCoreVectorsAsCoqVectors.Vec 32 (@SAWCoreScaffolding.Bool)) -> @SAWCoreVectorsAsCoqVectors.Vec 4 (@SAWCoreVectorsAsCoqVectors.Vec 32 (@SAWCoreScaffolding.Bool)) := + fun (x : @SAWCoreVectorsAsCoqVectors.Vec 4 (@SAWCoreVectorsAsCoqVectors.Vec 32 (@SAWCoreScaffolding.Bool))) => @SAWCoreScaffolding.error (@SAWCoreVectorsAsCoqVectors.Vec 4 (@SAWCoreVectorsAsCoqVectors.Vec 32 (@SAWCoreScaffolding.Bool))) "Unimplemented: AESInvMixColumns"%string. + +Definition AESKeyExpand : forall (k : @Num), @seq k (@SAWCoreVectorsAsCoqVectors.Vec 32 (@SAWCoreScaffolding.Bool)) -> let var__0 := @SAWCoreScaffolding.Nat -> @Num in + @seq (@tcMul (@TCNum 4) (@tcAdd (@TCNum 7) k)) (@SAWCoreVectorsAsCoqVectors.Vec 32 (@SAWCoreScaffolding.Bool)) := + fun (k : @Num) (x : CryptolPrimitivesForSAWCore.Num_rect (fun (num : @Num) => Type) (fun (n : @SAWCoreScaffolding.Nat) => @SAWCoreVectorsAsCoqVectors.Vec n (@SAWCoreVectorsAsCoqVectors.Vec 32 (@SAWCoreScaffolding.Bool))) (@SAWCorePrelude.Stream (@SAWCoreVectorsAsCoqVectors.Vec 32 (@SAWCoreScaffolding.Bool))) k) => @SAWCoreScaffolding.error (@seq (@tcMul (@TCNum 4) (@tcAdd (@TCNum 7) k)) (@SAWCoreVectorsAsCoqVectors.Vec 32 (@SAWCoreScaffolding.Bool))) "Unimplemented: AESKeyExpand"%string. + +Definition processSHA2_224 : forall (n : @Num), @seq n (@SAWCoreVectorsAsCoqVectors.Vec 16 (@SAWCoreVectorsAsCoqVectors.Vec 32 (@SAWCoreScaffolding.Bool))) -> @SAWCoreVectorsAsCoqVectors.Vec 7 (@SAWCoreVectorsAsCoqVectors.Vec 32 (@SAWCoreScaffolding.Bool)) := + fun (n : @Num) (x : CryptolPrimitivesForSAWCore.Num_rect (fun (num : @Num) => Type) (fun (n1 : @SAWCoreScaffolding.Nat) => @SAWCoreVectorsAsCoqVectors.Vec n1 (@SAWCoreVectorsAsCoqVectors.Vec 16 (@SAWCoreVectorsAsCoqVectors.Vec 32 (@SAWCoreScaffolding.Bool)))) (@SAWCorePrelude.Stream (@SAWCoreVectorsAsCoqVectors.Vec 16 (@SAWCoreVectorsAsCoqVectors.Vec 32 (@SAWCoreScaffolding.Bool)))) n) => @SAWCoreScaffolding.error (@SAWCoreVectorsAsCoqVectors.Vec 7 (@SAWCoreVectorsAsCoqVectors.Vec 32 (@SAWCoreScaffolding.Bool))) "Unimplemented: processSHA2_224"%string. + +Definition processSHA2_256 : forall (n : @Num), @seq n (@SAWCoreVectorsAsCoqVectors.Vec 16 (@SAWCoreVectorsAsCoqVectors.Vec 32 (@SAWCoreScaffolding.Bool))) -> @SAWCoreVectorsAsCoqVectors.Vec 8 (@SAWCoreVectorsAsCoqVectors.Vec 32 (@SAWCoreScaffolding.Bool)) := + fun (n : @Num) (x : CryptolPrimitivesForSAWCore.Num_rect (fun (num : @Num) => Type) (fun (n1 : @SAWCoreScaffolding.Nat) => @SAWCoreVectorsAsCoqVectors.Vec n1 (@SAWCoreVectorsAsCoqVectors.Vec 16 (@SAWCoreVectorsAsCoqVectors.Vec 32 (@SAWCoreScaffolding.Bool)))) (@SAWCorePrelude.Stream (@SAWCoreVectorsAsCoqVectors.Vec 16 (@SAWCoreVectorsAsCoqVectors.Vec 32 (@SAWCoreScaffolding.Bool)))) n) => @SAWCoreScaffolding.error (@SAWCoreVectorsAsCoqVectors.Vec 8 (@SAWCoreVectorsAsCoqVectors.Vec 32 (@SAWCoreScaffolding.Bool))) "Unimplemented: processSHA2_256"%string. + +Definition processSHA2_384 : forall (n : @Num), @seq n (@SAWCoreVectorsAsCoqVectors.Vec 16 (@SAWCoreVectorsAsCoqVectors.Vec 64 (@SAWCoreScaffolding.Bool))) -> @SAWCoreVectorsAsCoqVectors.Vec 6 (@SAWCoreVectorsAsCoqVectors.Vec 64 (@SAWCoreScaffolding.Bool)) := + fun (n : @Num) (x : CryptolPrimitivesForSAWCore.Num_rect (fun (num : @Num) => Type) (fun (n1 : @SAWCoreScaffolding.Nat) => @SAWCoreVectorsAsCoqVectors.Vec n1 (@SAWCoreVectorsAsCoqVectors.Vec 16 (@SAWCoreVectorsAsCoqVectors.Vec 64 (@SAWCoreScaffolding.Bool)))) (@SAWCorePrelude.Stream (@SAWCoreVectorsAsCoqVectors.Vec 16 (@SAWCoreVectorsAsCoqVectors.Vec 64 (@SAWCoreScaffolding.Bool)))) n) => @SAWCoreScaffolding.error (@SAWCoreVectorsAsCoqVectors.Vec 6 (@SAWCoreVectorsAsCoqVectors.Vec 64 (@SAWCoreScaffolding.Bool))) "Unimplemented: processSHA2_384"%string. + +Definition processSHA2_512 : forall (n : @Num), @seq n (@SAWCoreVectorsAsCoqVectors.Vec 16 (@SAWCoreVectorsAsCoqVectors.Vec 64 (@SAWCoreScaffolding.Bool))) -> @SAWCoreVectorsAsCoqVectors.Vec 8 (@SAWCoreVectorsAsCoqVectors.Vec 64 (@SAWCoreScaffolding.Bool)) := + fun (n : @Num) (x : CryptolPrimitivesForSAWCore.Num_rect (fun (num : @Num) => Type) (fun (n1 : @SAWCoreScaffolding.Nat) => @SAWCoreVectorsAsCoqVectors.Vec n1 (@SAWCoreVectorsAsCoqVectors.Vec 16 (@SAWCoreVectorsAsCoqVectors.Vec 64 (@SAWCoreScaffolding.Bool)))) (@SAWCorePrelude.Stream (@SAWCoreVectorsAsCoqVectors.Vec 16 (@SAWCoreVectorsAsCoqVectors.Vec 64 (@SAWCoreScaffolding.Bool)))) n) => @SAWCoreScaffolding.error (@SAWCoreVectorsAsCoqVectors.Vec 8 (@SAWCoreVectorsAsCoqVectors.Vec 64 (@SAWCoreScaffolding.Bool))) "Unimplemented: processSHA2_512"%string. + +Definition ec_double : forall (p : @Num), prod (@IntModNum p) (prod (@IntModNum p) (@IntModNum p)) -> let var__0 := @IntModNum p in + prod var__0 (prod var__0 var__0) := + fun (p : @Num) (x : prod (CryptolPrimitivesForSAWCore.Num_rect (fun (n : @Num) => Type) (@SAWCoreScaffolding.IntMod) (@SAWCoreScaffolding.Integer) p) (prod (CryptolPrimitivesForSAWCore.Num_rect (fun (n : @Num) => Type) (@SAWCoreScaffolding.IntMod) (@SAWCoreScaffolding.Integer) p) (CryptolPrimitivesForSAWCore.Num_rect (fun (n : @Num) => Type) (@SAWCoreScaffolding.IntMod) (@SAWCoreScaffolding.Integer) p))) => @SAWCoreScaffolding.error (prod (@IntModNum p) (prod (@IntModNum p) (@IntModNum p))) "Unimplemented: ec_double"%string. + +Definition ec_add_nonzero : forall (p : @Num), prod (@IntModNum p) (prod (@IntModNum p) (@IntModNum p)) -> prod (@IntModNum p) (prod (@IntModNum p) (@IntModNum p)) -> let var__0 := @IntModNum p in + prod var__0 (prod var__0 var__0) := + fun (p : @Num) (x : prod (CryptolPrimitivesForSAWCore.Num_rect (fun (n : @Num) => Type) (@SAWCoreScaffolding.IntMod) (@SAWCoreScaffolding.Integer) p) (prod (CryptolPrimitivesForSAWCore.Num_rect (fun (n : @Num) => Type) (@SAWCoreScaffolding.IntMod) (@SAWCoreScaffolding.Integer) p) (CryptolPrimitivesForSAWCore.Num_rect (fun (n : @Num) => Type) (@SAWCoreScaffolding.IntMod) (@SAWCoreScaffolding.Integer) p))) (y : prod (CryptolPrimitivesForSAWCore.Num_rect (fun (n : @Num) => Type) (@SAWCoreScaffolding.IntMod) (@SAWCoreScaffolding.Integer) p) (prod (CryptolPrimitivesForSAWCore.Num_rect (fun (n : @Num) => Type) (@SAWCoreScaffolding.IntMod) (@SAWCoreScaffolding.Integer) p) (CryptolPrimitivesForSAWCore.Num_rect (fun (n : @Num) => Type) (@SAWCoreScaffolding.IntMod) (@SAWCoreScaffolding.Integer) p))) => @SAWCoreScaffolding.error (prod (@IntModNum p) (prod (@IntModNum p) (@IntModNum p))) "Unimplemented: ec_add_nonzero"%string. + +Definition ec_mult : forall (p : @Num), @IntModNum p -> prod (@IntModNum p) (prod (@IntModNum p) (@IntModNum p)) -> let var__0 := @IntModNum p in + prod var__0 (prod var__0 var__0) := + fun (p : @Num) (x : CryptolPrimitivesForSAWCore.Num_rect (fun (n : @Num) => Type) (@SAWCoreScaffolding.IntMod) (@SAWCoreScaffolding.Integer) p) (y : prod (CryptolPrimitivesForSAWCore.Num_rect (fun (n : @Num) => Type) (@SAWCoreScaffolding.IntMod) (@SAWCoreScaffolding.Integer) p) (prod (CryptolPrimitivesForSAWCore.Num_rect (fun (n : @Num) => Type) (@SAWCoreScaffolding.IntMod) (@SAWCoreScaffolding.Integer) p) (CryptolPrimitivesForSAWCore.Num_rect (fun (n : @Num) => Type) (@SAWCoreScaffolding.IntMod) (@SAWCoreScaffolding.Integer) p))) => @SAWCoreScaffolding.error (prod (@IntModNum p) (prod (@IntModNum p) (@IntModNum p))) "Unimplemented: ec_mult"%string. + +Definition ec_twin_mult : forall (p : @Num), @IntModNum p -> prod (@IntModNum p) (prod (@IntModNum p) (@IntModNum p)) -> prod (@IntModNum p) (prod (@IntModNum p) (@IntModNum p)) -> let var__0 := @IntModNum p in + prod var__0 (prod var__0 var__0) := + fun (p : @Num) (x : CryptolPrimitivesForSAWCore.Num_rect (fun (n : @Num) => Type) (@SAWCoreScaffolding.IntMod) (@SAWCoreScaffolding.Integer) p) (y : prod (CryptolPrimitivesForSAWCore.Num_rect (fun (n : @Num) => Type) (@SAWCoreScaffolding.IntMod) (@SAWCoreScaffolding.Integer) p) (prod (CryptolPrimitivesForSAWCore.Num_rect (fun (n : @Num) => Type) (@SAWCoreScaffolding.IntMod) (@SAWCoreScaffolding.Integer) p) (CryptolPrimitivesForSAWCore.Num_rect (fun (n : @Num) => Type) (@SAWCoreScaffolding.IntMod) (@SAWCoreScaffolding.Integer) p))) (z : prod (CryptolPrimitivesForSAWCore.Num_rect (fun (n : @Num) => Type) (@SAWCoreScaffolding.IntMod) (@SAWCoreScaffolding.Integer) p) (prod (CryptolPrimitivesForSAWCore.Num_rect (fun (n : @Num) => Type) (@SAWCoreScaffolding.IntMod) (@SAWCoreScaffolding.Integer) p) (CryptolPrimitivesForSAWCore.Num_rect (fun (n : @Num) => Type) (@SAWCoreScaffolding.IntMod) (@SAWCoreScaffolding.Integer) p))) => @SAWCoreScaffolding.error (prod (@IntModNum p) (prod (@IntModNum p) (@IntModNum p))) "Unimplemented: ec_twin_mult"%string. + Axiom replicate_False : forall (n : @SAWCoreScaffolding.Nat), @SAWCoreScaffolding.Eq (@SAWCoreVectorsAsCoqVectors.Vec n (@SAWCoreScaffolding.Bool)) (@SAWCorePrelude.replicate n (@SAWCoreScaffolding.Bool) (@SAWCoreScaffolding.false)) (@SAWCoreVectorsAsCoqVectors.bvNat n 0) . Axiom subNat_0 : forall (n : @SAWCoreScaffolding.Nat), @SAWCoreScaffolding.Eq (@SAWCoreScaffolding.Nat) (@SAWCorePrelude.subNat n 0) n . diff --git a/saw-core-coq/coq/generated/CryptolToCoq/SAWCorePrelude.v b/saw-core-coq/coq/generated/CryptolToCoq/SAWCorePrelude.v index 428d2342ba..2f3f7f6c86 100644 --- a/saw-core-coq/coq/generated/CryptolToCoq/SAWCorePrelude.v +++ b/saw-core-coq/coq/generated/CryptolToCoq/SAWCorePrelude.v @@ -324,10 +324,12 @@ Definition Either__rec : forall (s : Type), forall (t : Type), forall (p : @Eith Definition either : forall (a : Type), forall (b : Type), forall (c : Type), (a -> c) -> (b -> c) -> @Either a b -> c := fun (a : Type) (b : Type) (c : Type) (f : a -> c) (g : b -> c) (e : @Either a b) => @Either__rec a b (fun (p : @Either a b) => c) f g e. -Definition eitherCong0 : forall (t : Type), forall (x : Type), forall (y : Type), @SAWCoreScaffolding.Eq Type x y -> @SAWCoreScaffolding.Eq Type (@Either x t) (@Either y t) := +Definition eitherCong0 : forall (t : Type), forall (x : Type), forall (y : Type), @SAWCoreScaffolding.Eq Type x y -> let var__0 := forall (s : Type), forall (t1 : Type), Type in + @SAWCoreScaffolding.Eq Type (@Either x t) (@Either y t) := fun (t : Type) (x : Type) (y : Type) (eq : @SAWCoreScaffolding.Eq Type x y) => @eq_cong Type x y eq Type (fun (y' : Type) => @Either y' t). -Definition eitherCong1 : forall (t : Type), forall (x : Type), forall (y : Type), @SAWCoreScaffolding.Eq Type x y -> @SAWCoreScaffolding.Eq Type (@Either t x) (@Either t y) := +Definition eitherCong1 : forall (t : Type), forall (x : Type), forall (y : Type), @SAWCoreScaffolding.Eq Type x y -> let var__0 := forall (s : Type), forall (t1 : Type), Type in + @SAWCoreScaffolding.Eq Type (@Either t x) (@Either t y) := fun (t : Type) (x : Type) (y : Type) (eq : @SAWCoreScaffolding.Eq Type x y) => @eq_cong Type x y eq Type (fun (y' : Type) => @Either t y'). Definition boolToEither : @SAWCoreScaffolding.Bool -> @Either unit unit := @@ -358,7 +360,8 @@ Definition Nat_cases2 : forall (a : Type), (@SAWCoreScaffolding.Nat -> a) -> (@S Definition eqNat : @SAWCoreScaffolding.Nat -> @SAWCoreScaffolding.Nat -> Type := fun (x : @SAWCoreScaffolding.Nat) (y : @SAWCoreScaffolding.Nat) => @SAWCoreScaffolding.Eq (@SAWCoreScaffolding.Nat) x y. -Definition eqNatSucc : forall (x : @SAWCoreScaffolding.Nat), forall (y : @SAWCoreScaffolding.Nat), @eqNat x y -> @eqNat (@SAWCoreScaffolding.Succ x) (@SAWCoreScaffolding.Succ y) := +Definition eqNatSucc : forall (x : @SAWCoreScaffolding.Nat), forall (y : @SAWCoreScaffolding.Nat), @eqNat x y -> let var__0 := @SAWCoreScaffolding.Nat -> @SAWCoreScaffolding.Nat in + @eqNat (@SAWCoreScaffolding.Succ x) (@SAWCoreScaffolding.Succ y) := fun (x : @SAWCoreScaffolding.Nat) (y : @SAWCoreScaffolding.Nat) (eq : @SAWCoreScaffolding.Eq (@SAWCoreScaffolding.Nat) x y) => @eq_cong (@SAWCoreScaffolding.Nat) x y eq (@SAWCoreScaffolding.Nat) (fun (n : @SAWCoreScaffolding.Nat) => @SAWCoreScaffolding.Succ n). Definition pred : @SAWCoreScaffolding.Nat -> @SAWCoreScaffolding.Nat := @@ -390,13 +393,20 @@ Definition addNat : @SAWCoreScaffolding.Nat -> @SAWCoreScaffolding.Nat -> @SAWCo Definition eqNatAdd0 : forall (x : @SAWCoreScaffolding.Nat), @eqNat (@addNat x 0) x := fun (x : @SAWCoreScaffolding.Nat) => @Nat__rec (fun (n : @SAWCoreScaffolding.Nat) => @eqNat (@addNat n 0) n) (@SAWCoreScaffolding.Refl (@SAWCoreScaffolding.Nat) 0) (fun (n : @SAWCoreScaffolding.Nat) => @eqNatSucc (@addNat n 0) n) x. -Definition eqNatAddS : forall (x : @SAWCoreScaffolding.Nat), forall (y : @SAWCoreScaffolding.Nat), @eqNat (@addNat x (@SAWCoreScaffolding.Succ y)) (@SAWCoreScaffolding.Succ (@addNat x y)) := - fun (x : @SAWCoreScaffolding.Nat) (y : @SAWCoreScaffolding.Nat) => @Nat__rec (fun (x' : @SAWCoreScaffolding.Nat) => forall (y' : @SAWCoreScaffolding.Nat), @eqNat (@addNat x' (@SAWCoreScaffolding.Succ y')) (@SAWCoreScaffolding.Succ (@addNat x' y'))) (fun (y' : @SAWCoreScaffolding.Nat) => @SAWCoreScaffolding.Refl (@SAWCoreScaffolding.Nat) (@SAWCoreScaffolding.Succ y')) (fun (x' : @SAWCoreScaffolding.Nat) (eqF : forall (y' : @SAWCoreScaffolding.Nat), @SAWCoreScaffolding.Eq (@SAWCoreScaffolding.Nat) (SAWCoreScaffolding.Nat_rect (fun (n : @SAWCoreScaffolding.Nat) => @SAWCoreScaffolding.Nat) (@SAWCoreScaffolding.Succ y') (fun (_1 : @SAWCoreScaffolding.Nat) (prev_sum : @SAWCoreScaffolding.Nat) => @SAWCoreScaffolding.Succ prev_sum) x') (@SAWCoreScaffolding.Succ (@addNat x' y'))) (y' : @SAWCoreScaffolding.Nat) => @eqNatSucc (@addNat x' (@SAWCoreScaffolding.Succ y')) (@SAWCoreScaffolding.Succ (@addNat x' y')) (eqF y')) x y. +Definition eqNatAddS : forall (x : @SAWCoreScaffolding.Nat), forall (y : @SAWCoreScaffolding.Nat), let var__0 := @SAWCoreScaffolding.Nat -> @SAWCoreScaffolding.Nat in + @eqNat (@addNat x (@SAWCoreScaffolding.Succ y)) (@SAWCoreScaffolding.Succ (@addNat x y)) := + fun (x : @SAWCoreScaffolding.Nat) (y : @SAWCoreScaffolding.Nat) => @Nat__rec (fun (x' : @SAWCoreScaffolding.Nat) => forall (y' : @SAWCoreScaffolding.Nat), let var__0 := @SAWCoreScaffolding.Nat -> @SAWCoreScaffolding.Nat in + @eqNat (@addNat x' (@SAWCoreScaffolding.Succ y')) (@SAWCoreScaffolding.Succ (@addNat x' y'))) (fun (y' : @SAWCoreScaffolding.Nat) => @SAWCoreScaffolding.Refl (@SAWCoreScaffolding.Nat) (@SAWCoreScaffolding.Succ y')) (fun (x' : @SAWCoreScaffolding.Nat) (eqF : forall (y' : @SAWCoreScaffolding.Nat), let var__0 := @SAWCoreScaffolding.Nat -> @SAWCoreScaffolding.Nat in + @SAWCoreScaffolding.Eq (@SAWCoreScaffolding.Nat) (SAWCoreScaffolding.Nat_rect (fun (n : @SAWCoreScaffolding.Nat) => @SAWCoreScaffolding.Nat) (@SAWCoreScaffolding.Succ y') (fun (_1 : @SAWCoreScaffolding.Nat) (prev_sum : @SAWCoreScaffolding.Nat) => @SAWCoreScaffolding.Succ prev_sum) x') (@SAWCoreScaffolding.Succ (@addNat x' y'))) (y' : @SAWCoreScaffolding.Nat) => @eqNatSucc (@addNat x' (@SAWCoreScaffolding.Succ y')) (@SAWCoreScaffolding.Succ (@addNat x' y')) (eqF y')) x y. Definition eqNatAddComm : forall (x : @SAWCoreScaffolding.Nat), forall (y : @SAWCoreScaffolding.Nat), @eqNat (@addNat x y) (@addNat y x) := - fun (x : @SAWCoreScaffolding.Nat) (y : @SAWCoreScaffolding.Nat) => @Nat__rec (fun (y' : @SAWCoreScaffolding.Nat) => forall (x' : @SAWCoreScaffolding.Nat), @eqNat (@addNat x' y') (@addNat y' x')) (fun (x' : @SAWCoreScaffolding.Nat) => @eqNatAdd0 x') (fun (y' : @SAWCoreScaffolding.Nat) (eqF : forall (x' : @SAWCoreScaffolding.Nat), let var__0 := fun (n : @SAWCoreScaffolding.Nat) => @SAWCoreScaffolding.Nat in - let var__1 := fun (_1 : @SAWCoreScaffolding.Nat) (prev_sum : @SAWCoreScaffolding.Nat) => @SAWCoreScaffolding.Succ prev_sum in - @SAWCoreScaffolding.Eq (@SAWCoreScaffolding.Nat) (SAWCoreScaffolding.Nat_rect var__0 y' var__1 x') (SAWCoreScaffolding.Nat_rect var__0 x' var__1 y')) (x' : @SAWCoreScaffolding.Nat) => @trans (@SAWCoreScaffolding.Nat) (@addNat x' (@SAWCoreScaffolding.Succ y')) (@SAWCoreScaffolding.Succ (@addNat x' y')) (@SAWCoreScaffolding.Succ (@addNat y' x')) (@eqNatAddS x' y') (@eqNatSucc (@addNat x' y') (@addNat y' x') (eqF x'))) y x. + fun (x : @SAWCoreScaffolding.Nat) (y : @SAWCoreScaffolding.Nat) => @Nat__rec (fun (y' : @SAWCoreScaffolding.Nat) => forall (x' : @SAWCoreScaffolding.Nat), @eqNat (@addNat x' y') (@addNat y' x')) (fun (x' : @SAWCoreScaffolding.Nat) => @eqNatAdd0 x') (fun (y' : @SAWCoreScaffolding.Nat) (eqF : forall (x' : @SAWCoreScaffolding.Nat), let var__0 := @SAWCoreScaffolding.Nat -> @SAWCoreScaffolding.Nat in + let var__1 := @SAWCoreScaffolding.Nat -> Type in + let var__2 := fun (n : @SAWCoreScaffolding.Nat) => @SAWCoreScaffolding.Nat in + let var__3 := var__2 0 in + let var__4 := forall (n : @SAWCoreScaffolding.Nat), var__2 n -> (fun (n1 : @SAWCoreScaffolding.Nat) => @SAWCoreScaffolding.Nat) (@SAWCoreScaffolding.Succ n) in + let var__5 := fun (_1 : @SAWCoreScaffolding.Nat) (prev_sum : @SAWCoreScaffolding.Nat) => @SAWCoreScaffolding.Succ prev_sum in + @SAWCoreScaffolding.Eq (@SAWCoreScaffolding.Nat) (SAWCoreScaffolding.Nat_rect var__2 y' var__5 x') (SAWCoreScaffolding.Nat_rect var__2 x' var__5 y')) (x' : @SAWCoreScaffolding.Nat) => @trans (@SAWCoreScaffolding.Nat) (@addNat x' (@SAWCoreScaffolding.Succ y')) (@SAWCoreScaffolding.Succ (@addNat x' y')) (@SAWCoreScaffolding.Succ (@addNat y' x')) (@eqNatAddS x' y') (@eqNatSucc (@addNat x' y') (@addNat y' x') (eqF x'))) y x. Definition addNat_assoc : forall (x : @SAWCoreScaffolding.Nat), forall (y : @SAWCoreScaffolding.Nat), forall (z : @SAWCoreScaffolding.Nat), @eqNat (@addNat x (@addNat y z)) (@addNat (@addNat x y) z) := fun (x : @SAWCoreScaffolding.Nat) (y : @SAWCoreScaffolding.Nat) (z : @SAWCoreScaffolding.Nat) => @Nat__rec (fun (x' : @SAWCoreScaffolding.Nat) => @eqNat (@addNat x' (@addNat y z)) (@addNat (@addNat x' y) z)) (@SAWCoreScaffolding.Refl (@SAWCoreScaffolding.Nat) (@addNat y z)) (fun (x' : @SAWCoreScaffolding.Nat) (eq : @SAWCoreScaffolding.Eq (@SAWCoreScaffolding.Nat) (SAWCoreScaffolding.Nat_rect (fun (n : @SAWCoreScaffolding.Nat) => @SAWCoreScaffolding.Nat) (@addNat y z) (fun (_1 : @SAWCoreScaffolding.Nat) (prev_sum : @SAWCoreScaffolding.Nat) => @SAWCoreScaffolding.Succ prev_sum) x') (SAWCoreScaffolding.Nat_rect (fun (n : @SAWCoreScaffolding.Nat) => @SAWCoreScaffolding.Nat) z (fun (_1 : @SAWCoreScaffolding.Nat) (prev_sum : @SAWCoreScaffolding.Nat) => @SAWCoreScaffolding.Succ prev_sum) (SAWCoreScaffolding.Nat_rect (fun (n : @SAWCoreScaffolding.Nat) => @SAWCoreScaffolding.Nat) y (fun (_1 : @SAWCoreScaffolding.Nat) (prev_sum : @SAWCoreScaffolding.Nat) => @SAWCoreScaffolding.Succ prev_sum) x'))) => @eqNatSucc (@addNat x' (@addNat y z)) (@addNat (@addNat x' y) z) eq) x. @@ -896,6 +906,9 @@ Definition BVVec : forall (n : @SAWCoreScaffolding.Nat), @SAWCoreVectorsAsCoqVec Definition genBVVec : forall (n : @SAWCoreScaffolding.Nat), forall (len : @SAWCoreVectorsAsCoqVectors.Vec n (@SAWCoreScaffolding.Bool)), forall (a : Type), (forall (i : @SAWCoreVectorsAsCoqVectors.Vec n (@SAWCoreScaffolding.Bool)), @is_bvult n i len -> a) -> @BVVec n len a := fun (n : @SAWCoreScaffolding.Nat) (len : @SAWCoreVectorsAsCoqVectors.Vec n (@SAWCoreScaffolding.Bool)) (a : Type) (f : forall (i : @SAWCoreVectorsAsCoqVectors.Vec n (@SAWCoreScaffolding.Bool)), @SAWCoreScaffolding.Eq (@SAWCoreScaffolding.Bool) (@SAWCoreVectorsAsCoqVectors.bvult n i len) (@SAWCoreScaffolding.true) -> a) => @genWithProof (@SAWCoreVectorsAsCoqVectors.bvToNat n len) a (fun (i : @SAWCoreScaffolding.Nat) (pf : @IsLeNat (@SAWCoreScaffolding.Succ i) (@SAWCoreVectorsAsCoqVectors.bvToNat n len)) => f (@SAWCoreVectorsAsCoqVectors.bvNat n i) (@IsLtNat_to_bvult n len i pf)). +Definition genBVVecFromVec : forall (m : @SAWCoreScaffolding.Nat), forall (a : Type), @SAWCoreVectorsAsCoqVectors.Vec m a -> a -> forall (n : @SAWCoreScaffolding.Nat), forall (len : @SAWCoreVectorsAsCoqVectors.Vec n (@SAWCoreScaffolding.Bool)), @BVVec n len a := + fun (m : @SAWCoreScaffolding.Nat) (a : Type) (v : @SAWCoreVectorsAsCoqVectors.Vec m a) (def : a) (n : @SAWCoreScaffolding.Nat) (len : @SAWCoreVectorsAsCoqVectors.Vec n (@SAWCoreScaffolding.Bool)) => @genBVVec n len a (fun (i : @SAWCoreVectorsAsCoqVectors.Vec n (@SAWCoreScaffolding.Bool)) (_1 : @SAWCoreScaffolding.Eq (@SAWCoreScaffolding.Bool) (@SAWCoreVectorsAsCoqVectors.bvult n i len) (@SAWCoreScaffolding.true)) => @SAWCoreVectorsAsCoqVectors.atWithDefault m a def v (@SAWCoreVectorsAsCoqVectors.bvToNat n i)). + Definition efq : forall (a : Type), @SAWCoreScaffolding.Eq (@SAWCoreScaffolding.Bool) (@SAWCoreScaffolding.true) (@SAWCoreScaffolding.false) -> a := fun (a : Type) (contra : @SAWCoreScaffolding.Eq (@SAWCoreScaffolding.Bool) (@SAWCoreScaffolding.true) (@SAWCoreScaffolding.false)) => @SAWCoreScaffolding.coerce unit a (@trans Type unit (if @SAWCoreScaffolding.true then unit else a) a (@sym Type (if @SAWCoreScaffolding.true then unit else a) unit (@ite_true Type unit a)) (@trans Type (if @SAWCoreScaffolding.true then unit else a) (if @SAWCoreScaffolding.false then unit else a) a (@eq_cong (@SAWCoreScaffolding.Bool) (@SAWCoreScaffolding.true) (@SAWCoreScaffolding.false) contra Type (fun (b : @SAWCoreScaffolding.Bool) => if b then unit else a)) (@ite_false Type unit a))) tt. @@ -981,9 +994,11 @@ Definition UnfoldedIRT : forall (As : @ListSort), @IRTSubsts As -> @IRTDesc As - fun (As : @ListSort) (Ds : @IRTSubsts As) (D : @IRTDesc As) => @IRTDesc__rec As (fun (_1 : @IRTDesc As) => @IRTSubsts As -> Type) (fun (i : @SAWCoreScaffolding.Nat) (Ds1 : @IRTSubsts As) => @IRT As (@dropIRTs As Ds1 (@SAWCoreScaffolding.Succ i)) (@atIRTs As Ds1 i)) (fun (D1 : @IRTDesc As) (rec : @IRTSubsts As -> Type) (Ds1 : @IRTSubsts As) => rec (@IRTs_Cons As (@IRT_mu As D1) Ds1)) (fun (_1 : @IRTDesc As) (recl : @IRTSubsts As -> Type) (_2 : @IRTDesc As) (recr : @IRTSubsts As -> Type) (Ds1 : @IRTSubsts As) => @Either (recl Ds1) (recr Ds1)) (fun (_1 : @IRTDesc As) (recl : @IRTSubsts As -> Type) (_2 : @IRTDesc As) (recr : @IRTSubsts As -> Type) (Ds1 : @IRTSubsts As) => prod (recl Ds1) (recr Ds1)) (fun (i : @SAWCoreScaffolding.Nat) (_1 : SAWCorePrelude.ListSort_rect (fun (_1 : @ListSort) => @SAWCoreScaffolding.Nat -> Type) (fun (_1 : @SAWCoreScaffolding.Nat) => @SAWCoreScaffolding.Eq (@SAWCoreScaffolding.Bool) (@SAWCoreScaffolding.true) (@SAWCoreScaffolding.false)) (fun (A : Type) (_1 : @ListSort) (rec : @SAWCoreScaffolding.Nat -> Type) => @Nat_cases Type A (fun (n : @SAWCoreScaffolding.Nat) (_2 : Type) => rec n)) As i -> @IRTDesc As) (recf : SAWCorePrelude.ListSort_rect (fun (_2 : @ListSort) => @SAWCoreScaffolding.Nat -> Type) (fun (_2 : @SAWCoreScaffolding.Nat) => @SAWCoreScaffolding.Eq (@SAWCoreScaffolding.Bool) (@SAWCoreScaffolding.true) (@SAWCoreScaffolding.false)) (fun (A : Type) (_2 : @ListSort) (rec : @SAWCoreScaffolding.Nat -> Type) => @Nat_cases Type A (fun (n : @SAWCoreScaffolding.Nat) (_3 : Type) => rec n)) As i -> @IRTSubsts As -> Type) (Ds1 : @IRTSubsts As) => @sigT (@listSortGet As i) (fun (a : SAWCorePrelude.ListSort_rect (fun (_2 : @ListSort) => @SAWCoreScaffolding.Nat -> Type) (fun (_2 : @SAWCoreScaffolding.Nat) => @SAWCoreScaffolding.Eq (@SAWCoreScaffolding.Bool) (@SAWCoreScaffolding.true) (@SAWCoreScaffolding.false)) (fun (A : Type) (_2 : @ListSort) (rec : @SAWCoreScaffolding.Nat -> Type) => @Nat_cases Type A (fun (n : @SAWCoreScaffolding.Nat) (_3 : Type) => rec n)) As i) => recf a Ds1)) (fun (n : @SAWCoreScaffolding.Nat) (len : @SAWCoreVectorsAsCoqVectors.Vec n (@SAWCoreScaffolding.Bool)) (_1 : @IRTDesc As) (rec : @IRTSubsts As -> Type) (Ds1 : @IRTSubsts As) => @BVVec n len (rec Ds1)) (fun (_1 : @IRTSubsts As) => unit) (fun (_1 : @IRTSubsts As) => @SAWCoreScaffolding.Eq (@SAWCoreScaffolding.Bool) (@SAWCoreScaffolding.true) (@SAWCoreScaffolding.false)) (fun (i : @SAWCoreScaffolding.Nat) (_1 : @IRTSubsts As) => @listSortGet As i) D Ds. Definition unfoldIRT : forall (As : @ListSort), forall (Ds : @IRTSubsts As), forall (D : @IRTDesc As), @IRT As Ds D -> @UnfoldedIRT As Ds D := - fun (As : @ListSort) => @IRT__rec As (fun (Ds : @IRTSubsts As) (D : @IRTDesc As) (_1 : @IRT As Ds D) => @UnfoldedIRT As Ds D) (fun (Ds : @IRTSubsts As) (i : @SAWCoreScaffolding.Nat) (x : @IRT As (SAWCorePrelude.IRTSubsts_rect As (fun (_1 : @IRTSubsts As) => @SAWCoreScaffolding.Nat -> @IRTSubsts As) (fun (_1 : @SAWCoreScaffolding.Nat) => @IRTs_Nil As) (fun (_1 : @IRTDesc As) (Ds1 : @IRTSubsts As) (rec : @SAWCoreScaffolding.Nat -> @IRTSubsts As) => @Nat_cases (@IRTSubsts As) Ds1 (fun (n : @SAWCoreScaffolding.Nat) (_2 : @IRTSubsts As) => rec n)) Ds (@SAWCoreScaffolding.Succ i)) (SAWCorePrelude.IRTSubsts_rect As (fun (_1 : @IRTSubsts As) => @SAWCoreScaffolding.Nat -> @IRTDesc As) (fun (_1 : @SAWCoreScaffolding.Nat) => @IRT_empty As) (fun (D : @IRTDesc As) (_1 : @IRTSubsts As) (rec : @SAWCoreScaffolding.Nat -> @IRTDesc As) => @Nat_cases (@IRTDesc As) D (fun (n : @SAWCoreScaffolding.Nat) (_2 : @IRTDesc As) => rec n)) Ds i)) (_1 : SAWCorePrelude.IRTDesc_rect As (fun (_1 : @IRTDesc As) => @IRTSubsts As -> Type) (fun (i1 : @SAWCoreScaffolding.Nat) (Ds1 : @IRTSubsts As) => @IRT As (@dropIRTs As Ds1 (@SAWCoreScaffolding.Succ i1)) (@atIRTs As Ds1 i1)) (fun (D : @IRTDesc As) (rec : @IRTSubsts As -> Type) (Ds1 : @IRTSubsts As) => rec (@IRTs_Cons As (@IRT_mu As D) Ds1)) (fun (_1 : @IRTDesc As) (recl : @IRTSubsts As -> Type) (_2 : @IRTDesc As) (recr : @IRTSubsts As -> Type) (Ds1 : @IRTSubsts As) => @Either (recl Ds1) (recr Ds1)) (fun (_1 : @IRTDesc As) (recl : @IRTSubsts As -> Type) (_2 : @IRTDesc As) (recr : @IRTSubsts As -> Type) (Ds1 : @IRTSubsts As) => prod (recl Ds1) (recr Ds1)) (fun (i1 : @SAWCoreScaffolding.Nat) (_1 : SAWCorePrelude.ListSort_rect (fun (_1 : @ListSort) => @SAWCoreScaffolding.Nat -> Type) (fun (_1 : @SAWCoreScaffolding.Nat) => @SAWCoreScaffolding.Eq (@SAWCoreScaffolding.Bool) (@SAWCoreScaffolding.true) (@SAWCoreScaffolding.false)) (fun (A : Type) (_1 : @ListSort) (rec : @SAWCoreScaffolding.Nat -> Type) => @Nat_cases Type A (fun (n : @SAWCoreScaffolding.Nat) (_2 : Type) => rec n)) As i1 -> @IRTDesc As) (recf : SAWCorePrelude.ListSort_rect (fun (_2 : @ListSort) => @SAWCoreScaffolding.Nat -> Type) (fun (_2 : @SAWCoreScaffolding.Nat) => @SAWCoreScaffolding.Eq (@SAWCoreScaffolding.Bool) (@SAWCoreScaffolding.true) (@SAWCoreScaffolding.false)) (fun (A : Type) (_2 : @ListSort) (rec : @SAWCoreScaffolding.Nat -> Type) => @Nat_cases Type A (fun (n : @SAWCoreScaffolding.Nat) (_3 : Type) => rec n)) As i1 -> @IRTSubsts As -> Type) (Ds1 : @IRTSubsts As) => @sigT (@listSortGet As i1) (fun (a : SAWCorePrelude.ListSort_rect (fun (_2 : @ListSort) => @SAWCoreScaffolding.Nat -> Type) (fun (_2 : @SAWCoreScaffolding.Nat) => @SAWCoreScaffolding.Eq (@SAWCoreScaffolding.Bool) (@SAWCoreScaffolding.true) (@SAWCoreScaffolding.false)) (fun (A : Type) (_2 : @ListSort) (rec : @SAWCoreScaffolding.Nat -> Type) => @Nat_cases Type A (fun (n : @SAWCoreScaffolding.Nat) (_3 : Type) => rec n)) As i1) => recf a Ds1)) (fun (n : @SAWCoreScaffolding.Nat) (len : @SAWCoreVectorsAsCoqVectors.Vec n (@SAWCoreScaffolding.Bool)) (_1 : @IRTDesc As) (rec : @IRTSubsts As -> Type) (Ds1 : @IRTSubsts As) => @BVVec n len (rec Ds1)) (fun (_1 : @IRTSubsts As) => unit) (fun (_1 : @IRTSubsts As) => @SAWCoreScaffolding.Eq (@SAWCoreScaffolding.Bool) (@SAWCoreScaffolding.true) (@SAWCoreScaffolding.false)) (fun (i1 : @SAWCoreScaffolding.Nat) (_1 : @IRTSubsts As) => @listSortGet As i1) (SAWCorePrelude.IRTSubsts_rect As (fun (_1 : @IRTSubsts As) => @SAWCoreScaffolding.Nat -> @IRTDesc As) (fun (_1 : @SAWCoreScaffolding.Nat) => @IRT_empty As) (fun (D : @IRTDesc As) (_1 : @IRTSubsts As) (rec : @SAWCoreScaffolding.Nat -> @IRTDesc As) => @Nat_cases (@IRTDesc As) D (fun (n : @SAWCoreScaffolding.Nat) (_2 : @IRTDesc As) => rec n)) Ds i) (@dropIRTs As Ds (@SAWCoreScaffolding.Succ i))) => x) (fun (Ds : @IRTSubsts As) (D : @IRTDesc As) (_1 : @IRT As (@IRTs_Cons As (@IRT_mu As D) Ds) D) (rec : SAWCorePrelude.IRTDesc_rect As (fun (_2 : @IRTDesc As) => @IRTSubsts As -> Type) (fun (i : @SAWCoreScaffolding.Nat) (Ds1 : @IRTSubsts As) => @IRT As (@dropIRTs As Ds1 (@SAWCoreScaffolding.Succ i)) (@atIRTs As Ds1 i)) (fun (D1 : @IRTDesc As) (rec : @IRTSubsts As -> Type) (Ds1 : @IRTSubsts As) => rec (@IRTs_Cons As (@IRT_mu As D1) Ds1)) (fun (_2 : @IRTDesc As) (recl : @IRTSubsts As -> Type) (_3 : @IRTDesc As) (recr : @IRTSubsts As -> Type) (Ds1 : @IRTSubsts As) => @Either (recl Ds1) (recr Ds1)) (fun (_2 : @IRTDesc As) (recl : @IRTSubsts As -> Type) (_3 : @IRTDesc As) (recr : @IRTSubsts As -> Type) (Ds1 : @IRTSubsts As) => prod (recl Ds1) (recr Ds1)) (fun (i : @SAWCoreScaffolding.Nat) (_2 : SAWCorePrelude.ListSort_rect (fun (_2 : @ListSort) => @SAWCoreScaffolding.Nat -> Type) (fun (_2 : @SAWCoreScaffolding.Nat) => @SAWCoreScaffolding.Eq (@SAWCoreScaffolding.Bool) (@SAWCoreScaffolding.true) (@SAWCoreScaffolding.false)) (fun (A : Type) (_2 : @ListSort) (rec : @SAWCoreScaffolding.Nat -> Type) => @Nat_cases Type A (fun (n : @SAWCoreScaffolding.Nat) (_3 : Type) => rec n)) As i -> @IRTDesc As) (recf : SAWCorePrelude.ListSort_rect (fun (_3 : @ListSort) => @SAWCoreScaffolding.Nat -> Type) (fun (_3 : @SAWCoreScaffolding.Nat) => @SAWCoreScaffolding.Eq (@SAWCoreScaffolding.Bool) (@SAWCoreScaffolding.true) (@SAWCoreScaffolding.false)) (fun (A : Type) (_3 : @ListSort) (rec : @SAWCoreScaffolding.Nat -> Type) => @Nat_cases Type A (fun (n : @SAWCoreScaffolding.Nat) (_4 : Type) => rec n)) As i -> @IRTSubsts As -> Type) (Ds1 : @IRTSubsts As) => @sigT (@listSortGet As i) (fun (a : SAWCorePrelude.ListSort_rect (fun (_3 : @ListSort) => @SAWCoreScaffolding.Nat -> Type) (fun (_3 : @SAWCoreScaffolding.Nat) => @SAWCoreScaffolding.Eq (@SAWCoreScaffolding.Bool) (@SAWCoreScaffolding.true) (@SAWCoreScaffolding.false)) (fun (A : Type) (_3 : @ListSort) (rec : @SAWCoreScaffolding.Nat -> Type) => @Nat_cases Type A (fun (n : @SAWCoreScaffolding.Nat) (_4 : Type) => rec n)) As i) => recf a Ds1)) (fun (n : @SAWCoreScaffolding.Nat) (len : @SAWCoreVectorsAsCoqVectors.Vec n (@SAWCoreScaffolding.Bool)) (_2 : @IRTDesc As) (rec : @IRTSubsts As -> Type) (Ds1 : @IRTSubsts As) => @BVVec n len (rec Ds1)) (fun (_2 : @IRTSubsts As) => unit) (fun (_2 : @IRTSubsts As) => @SAWCoreScaffolding.Eq (@SAWCoreScaffolding.Bool) (@SAWCoreScaffolding.true) (@SAWCoreScaffolding.false)) (fun (i : @SAWCoreScaffolding.Nat) (_2 : @IRTSubsts As) => @listSortGet As i) D (@IRTs_Cons As (@IRT_mu As D) Ds)) => rec) (fun (Ds : @IRTSubsts As) (Dl : @IRTDesc As) (Dr : @IRTDesc As) (_1 : @IRT As Ds Dl) (recl : SAWCorePrelude.IRTDesc_rect As (fun (_2 : @IRTDesc As) => @IRTSubsts As -> Type) (fun (i : @SAWCoreScaffolding.Nat) (Ds1 : @IRTSubsts As) => @IRT As (@dropIRTs As Ds1 (@SAWCoreScaffolding.Succ i)) (@atIRTs As Ds1 i)) (fun (D : @IRTDesc As) (rec : @IRTSubsts As -> Type) (Ds1 : @IRTSubsts As) => rec (@IRTs_Cons As (@IRT_mu As D) Ds1)) (fun (_2 : @IRTDesc As) (recl : @IRTSubsts As -> Type) (_3 : @IRTDesc As) (recr : @IRTSubsts As -> Type) (Ds1 : @IRTSubsts As) => @Either (recl Ds1) (recr Ds1)) (fun (_2 : @IRTDesc As) (recl : @IRTSubsts As -> Type) (_3 : @IRTDesc As) (recr : @IRTSubsts As -> Type) (Ds1 : @IRTSubsts As) => prod (recl Ds1) (recr Ds1)) (fun (i : @SAWCoreScaffolding.Nat) (_2 : SAWCorePrelude.ListSort_rect (fun (_2 : @ListSort) => @SAWCoreScaffolding.Nat -> Type) (fun (_2 : @SAWCoreScaffolding.Nat) => @SAWCoreScaffolding.Eq (@SAWCoreScaffolding.Bool) (@SAWCoreScaffolding.true) (@SAWCoreScaffolding.false)) (fun (A : Type) (_2 : @ListSort) (rec : @SAWCoreScaffolding.Nat -> Type) => @Nat_cases Type A (fun (n : @SAWCoreScaffolding.Nat) (_3 : Type) => rec n)) As i -> @IRTDesc As) (recf : SAWCorePrelude.ListSort_rect (fun (_3 : @ListSort) => @SAWCoreScaffolding.Nat -> Type) (fun (_3 : @SAWCoreScaffolding.Nat) => @SAWCoreScaffolding.Eq (@SAWCoreScaffolding.Bool) (@SAWCoreScaffolding.true) (@SAWCoreScaffolding.false)) (fun (A : Type) (_3 : @ListSort) (rec : @SAWCoreScaffolding.Nat -> Type) => @Nat_cases Type A (fun (n : @SAWCoreScaffolding.Nat) (_4 : Type) => rec n)) As i -> @IRTSubsts As -> Type) (Ds1 : @IRTSubsts As) => @sigT (@listSortGet As i) (fun (a : SAWCorePrelude.ListSort_rect (fun (_3 : @ListSort) => @SAWCoreScaffolding.Nat -> Type) (fun (_3 : @SAWCoreScaffolding.Nat) => @SAWCoreScaffolding.Eq (@SAWCoreScaffolding.Bool) (@SAWCoreScaffolding.true) (@SAWCoreScaffolding.false)) (fun (A : Type) (_3 : @ListSort) (rec : @SAWCoreScaffolding.Nat -> Type) => @Nat_cases Type A (fun (n : @SAWCoreScaffolding.Nat) (_4 : Type) => rec n)) As i) => recf a Ds1)) (fun (n : @SAWCoreScaffolding.Nat) (len : @SAWCoreVectorsAsCoqVectors.Vec n (@SAWCoreScaffolding.Bool)) (_2 : @IRTDesc As) (rec : @IRTSubsts As -> Type) (Ds1 : @IRTSubsts As) => @BVVec n len (rec Ds1)) (fun (_2 : @IRTSubsts As) => unit) (fun (_2 : @IRTSubsts As) => @SAWCoreScaffolding.Eq (@SAWCoreScaffolding.Bool) (@SAWCoreScaffolding.true) (@SAWCoreScaffolding.false)) (fun (i : @SAWCoreScaffolding.Nat) (_2 : @IRTSubsts As) => @listSortGet As i) Dl Ds) => @Left (@UnfoldedIRT As Ds Dl) (@UnfoldedIRT As Ds Dr) recl) (fun (Ds : @IRTSubsts As) (Dl : @IRTDesc As) (Dr : @IRTDesc As) (_1 : @IRT As Ds Dr) (recr : SAWCorePrelude.IRTDesc_rect As (fun (_2 : @IRTDesc As) => @IRTSubsts As -> Type) (fun (i : @SAWCoreScaffolding.Nat) (Ds1 : @IRTSubsts As) => @IRT As (@dropIRTs As Ds1 (@SAWCoreScaffolding.Succ i)) (@atIRTs As Ds1 i)) (fun (D : @IRTDesc As) (rec : @IRTSubsts As -> Type) (Ds1 : @IRTSubsts As) => rec (@IRTs_Cons As (@IRT_mu As D) Ds1)) (fun (_2 : @IRTDesc As) (recl : @IRTSubsts As -> Type) (_3 : @IRTDesc As) (recr : @IRTSubsts As -> Type) (Ds1 : @IRTSubsts As) => @Either (recl Ds1) (recr Ds1)) (fun (_2 : @IRTDesc As) (recl : @IRTSubsts As -> Type) (_3 : @IRTDesc As) (recr : @IRTSubsts As -> Type) (Ds1 : @IRTSubsts As) => prod (recl Ds1) (recr Ds1)) (fun (i : @SAWCoreScaffolding.Nat) (_2 : SAWCorePrelude.ListSort_rect (fun (_2 : @ListSort) => @SAWCoreScaffolding.Nat -> Type) (fun (_2 : @SAWCoreScaffolding.Nat) => @SAWCoreScaffolding.Eq (@SAWCoreScaffolding.Bool) (@SAWCoreScaffolding.true) (@SAWCoreScaffolding.false)) (fun (A : Type) (_2 : @ListSort) (rec : @SAWCoreScaffolding.Nat -> Type) => @Nat_cases Type A (fun (n : @SAWCoreScaffolding.Nat) (_3 : Type) => rec n)) As i -> @IRTDesc As) (recf : SAWCorePrelude.ListSort_rect (fun (_3 : @ListSort) => @SAWCoreScaffolding.Nat -> Type) (fun (_3 : @SAWCoreScaffolding.Nat) => @SAWCoreScaffolding.Eq (@SAWCoreScaffolding.Bool) (@SAWCoreScaffolding.true) (@SAWCoreScaffolding.false)) (fun (A : Type) (_3 : @ListSort) (rec : @SAWCoreScaffolding.Nat -> Type) => @Nat_cases Type A (fun (n : @SAWCoreScaffolding.Nat) (_4 : Type) => rec n)) As i -> @IRTSubsts As -> Type) (Ds1 : @IRTSubsts As) => @sigT (@listSortGet As i) (fun (a : SAWCorePrelude.ListSort_rect (fun (_3 : @ListSort) => @SAWCoreScaffolding.Nat -> Type) (fun (_3 : @SAWCoreScaffolding.Nat) => @SAWCoreScaffolding.Eq (@SAWCoreScaffolding.Bool) (@SAWCoreScaffolding.true) (@SAWCoreScaffolding.false)) (fun (A : Type) (_3 : @ListSort) (rec : @SAWCoreScaffolding.Nat -> Type) => @Nat_cases Type A (fun (n : @SAWCoreScaffolding.Nat) (_4 : Type) => rec n)) As i) => recf a Ds1)) (fun (n : @SAWCoreScaffolding.Nat) (len : @SAWCoreVectorsAsCoqVectors.Vec n (@SAWCoreScaffolding.Bool)) (_2 : @IRTDesc As) (rec : @IRTSubsts As -> Type) (Ds1 : @IRTSubsts As) => @BVVec n len (rec Ds1)) (fun (_2 : @IRTSubsts As) => unit) (fun (_2 : @IRTSubsts As) => @SAWCoreScaffolding.Eq (@SAWCoreScaffolding.Bool) (@SAWCoreScaffolding.true) (@SAWCoreScaffolding.false)) (fun (i : @SAWCoreScaffolding.Nat) (_2 : @IRTSubsts As) => @listSortGet As i) Dr Ds) => @Right (@UnfoldedIRT As Ds Dl) (@UnfoldedIRT As Ds Dr) recr) (fun (Ds : @IRTSubsts As) (Dl : @IRTDesc As) (Dr : @IRTDesc As) (_1 : @IRT As Ds Dl) (recl : SAWCorePrelude.IRTDesc_rect As (fun (_2 : @IRTDesc As) => @IRTSubsts As -> Type) (fun (i : @SAWCoreScaffolding.Nat) (Ds1 : @IRTSubsts As) => @IRT As (@dropIRTs As Ds1 (@SAWCoreScaffolding.Succ i)) (@atIRTs As Ds1 i)) (fun (D : @IRTDesc As) (rec : @IRTSubsts As -> Type) (Ds1 : @IRTSubsts As) => rec (@IRTs_Cons As (@IRT_mu As D) Ds1)) (fun (_2 : @IRTDesc As) (recl : @IRTSubsts As -> Type) (_3 : @IRTDesc As) (recr : @IRTSubsts As -> Type) (Ds1 : @IRTSubsts As) => @Either (recl Ds1) (recr Ds1)) (fun (_2 : @IRTDesc As) (recl : @IRTSubsts As -> Type) (_3 : @IRTDesc As) (recr : @IRTSubsts As -> Type) (Ds1 : @IRTSubsts As) => prod (recl Ds1) (recr Ds1)) (fun (i : @SAWCoreScaffolding.Nat) (_2 : SAWCorePrelude.ListSort_rect (fun (_2 : @ListSort) => @SAWCoreScaffolding.Nat -> Type) (fun (_2 : @SAWCoreScaffolding.Nat) => @SAWCoreScaffolding.Eq (@SAWCoreScaffolding.Bool) (@SAWCoreScaffolding.true) (@SAWCoreScaffolding.false)) (fun (A : Type) (_2 : @ListSort) (rec : @SAWCoreScaffolding.Nat -> Type) => @Nat_cases Type A (fun (n : @SAWCoreScaffolding.Nat) (_3 : Type) => rec n)) As i -> @IRTDesc As) (recf : SAWCorePrelude.ListSort_rect (fun (_3 : @ListSort) => @SAWCoreScaffolding.Nat -> Type) (fun (_3 : @SAWCoreScaffolding.Nat) => @SAWCoreScaffolding.Eq (@SAWCoreScaffolding.Bool) (@SAWCoreScaffolding.true) (@SAWCoreScaffolding.false)) (fun (A : Type) (_3 : @ListSort) (rec : @SAWCoreScaffolding.Nat -> Type) => @Nat_cases Type A (fun (n : @SAWCoreScaffolding.Nat) (_4 : Type) => rec n)) As i -> @IRTSubsts As -> Type) (Ds1 : @IRTSubsts As) => @sigT (@listSortGet As i) (fun (a : SAWCorePrelude.ListSort_rect (fun (_3 : @ListSort) => @SAWCoreScaffolding.Nat -> Type) (fun (_3 : @SAWCoreScaffolding.Nat) => @SAWCoreScaffolding.Eq (@SAWCoreScaffolding.Bool) (@SAWCoreScaffolding.true) (@SAWCoreScaffolding.false)) (fun (A : Type) (_3 : @ListSort) (rec : @SAWCoreScaffolding.Nat -> Type) => @Nat_cases Type A (fun (n : @SAWCoreScaffolding.Nat) (_4 : Type) => rec n)) As i) => recf a Ds1)) (fun (n : @SAWCoreScaffolding.Nat) (len : @SAWCoreVectorsAsCoqVectors.Vec n (@SAWCoreScaffolding.Bool)) (_2 : @IRTDesc As) (rec : @IRTSubsts As -> Type) (Ds1 : @IRTSubsts As) => @BVVec n len (rec Ds1)) (fun (_2 : @IRTSubsts As) => unit) (fun (_2 : @IRTSubsts As) => @SAWCoreScaffolding.Eq (@SAWCoreScaffolding.Bool) (@SAWCoreScaffolding.true) (@SAWCoreScaffolding.false)) (fun (i : @SAWCoreScaffolding.Nat) (_2 : @IRTSubsts As) => @listSortGet As i) Dl Ds) (_2 : @IRT As Ds Dr) (recr : SAWCorePrelude.IRTDesc_rect As (fun (_3 : @IRTDesc As) => @IRTSubsts As -> Type) (fun (i : @SAWCoreScaffolding.Nat) (Ds1 : @IRTSubsts As) => @IRT As (@dropIRTs As Ds1 (@SAWCoreScaffolding.Succ i)) (@atIRTs As Ds1 i)) (fun (D : @IRTDesc As) (rec : @IRTSubsts As -> Type) (Ds1 : @IRTSubsts As) => rec (@IRTs_Cons As (@IRT_mu As D) Ds1)) (fun (_3 : @IRTDesc As) (recl1 : @IRTSubsts As -> Type) (_4 : @IRTDesc As) (recr : @IRTSubsts As -> Type) (Ds1 : @IRTSubsts As) => @Either (recl1 Ds1) (recr Ds1)) (fun (_3 : @IRTDesc As) (recl1 : @IRTSubsts As -> Type) (_4 : @IRTDesc As) (recr : @IRTSubsts As -> Type) (Ds1 : @IRTSubsts As) => prod (recl1 Ds1) (recr Ds1)) (fun (i : @SAWCoreScaffolding.Nat) (_3 : SAWCorePrelude.ListSort_rect (fun (_3 : @ListSort) => @SAWCoreScaffolding.Nat -> Type) (fun (_3 : @SAWCoreScaffolding.Nat) => @SAWCoreScaffolding.Eq (@SAWCoreScaffolding.Bool) (@SAWCoreScaffolding.true) (@SAWCoreScaffolding.false)) (fun (A : Type) (_3 : @ListSort) (rec : @SAWCoreScaffolding.Nat -> Type) => @Nat_cases Type A (fun (n : @SAWCoreScaffolding.Nat) (_4 : Type) => rec n)) As i -> @IRTDesc As) (recf : SAWCorePrelude.ListSort_rect (fun (_4 : @ListSort) => @SAWCoreScaffolding.Nat -> Type) (fun (_4 : @SAWCoreScaffolding.Nat) => @SAWCoreScaffolding.Eq (@SAWCoreScaffolding.Bool) (@SAWCoreScaffolding.true) (@SAWCoreScaffolding.false)) (fun (A : Type) (_4 : @ListSort) (rec : @SAWCoreScaffolding.Nat -> Type) => @Nat_cases Type A (fun (n : @SAWCoreScaffolding.Nat) (_5 : Type) => rec n)) As i -> @IRTSubsts As -> Type) (Ds1 : @IRTSubsts As) => @sigT (@listSortGet As i) (fun (a : SAWCorePrelude.ListSort_rect (fun (_4 : @ListSort) => @SAWCoreScaffolding.Nat -> Type) (fun (_4 : @SAWCoreScaffolding.Nat) => @SAWCoreScaffolding.Eq (@SAWCoreScaffolding.Bool) (@SAWCoreScaffolding.true) (@SAWCoreScaffolding.false)) (fun (A : Type) (_4 : @ListSort) (rec : @SAWCoreScaffolding.Nat -> Type) => @Nat_cases Type A (fun (n : @SAWCoreScaffolding.Nat) (_5 : Type) => rec n)) As i) => recf a Ds1)) (fun (n : @SAWCoreScaffolding.Nat) (len : @SAWCoreVectorsAsCoqVectors.Vec n (@SAWCoreScaffolding.Bool)) (_3 : @IRTDesc As) (rec : @IRTSubsts As -> Type) (Ds1 : @IRTSubsts As) => @BVVec n len (rec Ds1)) (fun (_3 : @IRTSubsts As) => unit) (fun (_3 : @IRTSubsts As) => @SAWCoreScaffolding.Eq (@SAWCoreScaffolding.Bool) (@SAWCoreScaffolding.true) (@SAWCoreScaffolding.false)) (fun (i : @SAWCoreScaffolding.Nat) (_3 : @IRTSubsts As) => @listSortGet As i) Dr Ds) => pair recl recr) (fun (Ds : @IRTSubsts As) (i : @SAWCoreScaffolding.Nat) (Df : SAWCorePrelude.ListSort_rect (fun (_1 : @ListSort) => @SAWCoreScaffolding.Nat -> Type) (fun (_1 : @SAWCoreScaffolding.Nat) => @SAWCoreScaffolding.Eq (@SAWCoreScaffolding.Bool) (@SAWCoreScaffolding.true) (@SAWCoreScaffolding.false)) (fun (A : Type) (_1 : @ListSort) (rec : @SAWCoreScaffolding.Nat -> Type) => @Nat_cases Type A (fun (n : @SAWCoreScaffolding.Nat) (_2 : Type) => rec n)) As i -> @IRTDesc As) (a : SAWCorePrelude.ListSort_rect (fun (_1 : @ListSort) => @SAWCoreScaffolding.Nat -> Type) (fun (_1 : @SAWCoreScaffolding.Nat) => @SAWCoreScaffolding.Eq (@SAWCoreScaffolding.Bool) (@SAWCoreScaffolding.true) (@SAWCoreScaffolding.false)) (fun (A : Type) (_1 : @ListSort) (rec : @SAWCoreScaffolding.Nat -> Type) => @Nat_cases Type A (fun (n : @SAWCoreScaffolding.Nat) (_2 : Type) => rec n)) As i) (_1 : @IRT As Ds (Df a)) (recf : SAWCorePrelude.IRTDesc_rect As (fun (_2 : @IRTDesc As) => @IRTSubsts As -> Type) (fun (i1 : @SAWCoreScaffolding.Nat) (Ds1 : @IRTSubsts As) => @IRT As (@dropIRTs As Ds1 (@SAWCoreScaffolding.Succ i1)) (@atIRTs As Ds1 i1)) (fun (D : @IRTDesc As) (rec : @IRTSubsts As -> Type) (Ds1 : @IRTSubsts As) => rec (@IRTs_Cons As (@IRT_mu As D) Ds1)) (fun (_2 : @IRTDesc As) (recl : @IRTSubsts As -> Type) (_3 : @IRTDesc As) (recr : @IRTSubsts As -> Type) (Ds1 : @IRTSubsts As) => @Either (recl Ds1) (recr Ds1)) (fun (_2 : @IRTDesc As) (recl : @IRTSubsts As -> Type) (_3 : @IRTDesc As) (recr : @IRTSubsts As -> Type) (Ds1 : @IRTSubsts As) => prod (recl Ds1) (recr Ds1)) (fun (i1 : @SAWCoreScaffolding.Nat) (_2 : SAWCorePrelude.ListSort_rect (fun (_2 : @ListSort) => @SAWCoreScaffolding.Nat -> Type) (fun (_2 : @SAWCoreScaffolding.Nat) => @SAWCoreScaffolding.Eq (@SAWCoreScaffolding.Bool) (@SAWCoreScaffolding.true) (@SAWCoreScaffolding.false)) (fun (A : Type) (_2 : @ListSort) (rec : @SAWCoreScaffolding.Nat -> Type) => @Nat_cases Type A (fun (n : @SAWCoreScaffolding.Nat) (_3 : Type) => rec n)) As i1 -> @IRTDesc As) (recf : SAWCorePrelude.ListSort_rect (fun (_3 : @ListSort) => @SAWCoreScaffolding.Nat -> Type) (fun (_3 : @SAWCoreScaffolding.Nat) => @SAWCoreScaffolding.Eq (@SAWCoreScaffolding.Bool) (@SAWCoreScaffolding.true) (@SAWCoreScaffolding.false)) (fun (A : Type) (_3 : @ListSort) (rec : @SAWCoreScaffolding.Nat -> Type) => @Nat_cases Type A (fun (n : @SAWCoreScaffolding.Nat) (_4 : Type) => rec n)) As i1 -> @IRTSubsts As -> Type) (Ds1 : @IRTSubsts As) => @sigT (@listSortGet As i1) (fun (a1 : SAWCorePrelude.ListSort_rect (fun (_3 : @ListSort) => @SAWCoreScaffolding.Nat -> Type) (fun (_3 : @SAWCoreScaffolding.Nat) => @SAWCoreScaffolding.Eq (@SAWCoreScaffolding.Bool) (@SAWCoreScaffolding.true) (@SAWCoreScaffolding.false)) (fun (A : Type) (_3 : @ListSort) (rec : @SAWCoreScaffolding.Nat -> Type) => @Nat_cases Type A (fun (n : @SAWCoreScaffolding.Nat) (_4 : Type) => rec n)) As i1) => recf a1 Ds1)) (fun (n : @SAWCoreScaffolding.Nat) (len : @SAWCoreVectorsAsCoqVectors.Vec n (@SAWCoreScaffolding.Bool)) (_2 : @IRTDesc As) (rec : @IRTSubsts As -> Type) (Ds1 : @IRTSubsts As) => @BVVec n len (rec Ds1)) (fun (_2 : @IRTSubsts As) => unit) (fun (_2 : @IRTSubsts As) => @SAWCoreScaffolding.Eq (@SAWCoreScaffolding.Bool) (@SAWCoreScaffolding.true) (@SAWCoreScaffolding.false)) (fun (i1 : @SAWCoreScaffolding.Nat) (_2 : @IRTSubsts As) => @listSortGet As i1) (Df a) Ds) => @existT (@listSortGet As i) (fun (a1 : SAWCorePrelude.ListSort_rect (fun (_2 : @ListSort) => @SAWCoreScaffolding.Nat -> Type) (fun (_2 : @SAWCoreScaffolding.Nat) => @SAWCoreScaffolding.Eq (@SAWCoreScaffolding.Bool) (@SAWCoreScaffolding.true) (@SAWCoreScaffolding.false)) (fun (A : Type) (_2 : @ListSort) (rec : @SAWCoreScaffolding.Nat -> Type) => @Nat_cases Type A (fun (n : @SAWCoreScaffolding.Nat) (_3 : Type) => rec n)) As i) => @UnfoldedIRT As Ds (Df a1)) a recf) (fun (Ds : @IRTSubsts As) (n : @SAWCoreScaffolding.Nat) (len : @SAWCoreVectorsAsCoqVectors.Vec n (@SAWCoreScaffolding.Bool)) (D : @IRTDesc As) (_1 : forall (i : @SAWCoreVectorsAsCoqVectors.Vec n (@SAWCoreScaffolding.Bool)), @SAWCoreScaffolding.Eq (@SAWCoreScaffolding.Bool) (@SAWCoreVectorsAsCoqVectors.bvult n i len) (@SAWCoreScaffolding.true) -> @IRT As Ds D) (recg : forall (i : @SAWCoreVectorsAsCoqVectors.Vec n (@SAWCoreScaffolding.Bool)), @SAWCoreScaffolding.Eq (@SAWCoreScaffolding.Bool) (@SAWCoreVectorsAsCoqVectors.bvult n i len) (@SAWCoreScaffolding.true) -> let var__0 := @IRTDesc As in - let var__1 := @IRTSubsts As in - SAWCorePrelude.IRTDesc_rect As (fun (_3 : var__0) => @IRTSubsts As -> Type) (fun (i1 : @SAWCoreScaffolding.Nat) (Ds1 : @IRTSubsts As) => @IRT As (@dropIRTs As Ds1 (@SAWCoreScaffolding.Succ i1)) (@atIRTs As Ds1 i1)) (fun (D1 : var__0) (rec : @IRTSubsts As -> Type) (Ds1 : @IRTSubsts As) => rec (@IRTs_Cons As (@IRT_mu As D1) Ds1)) (fun (_3 : var__0) (recl : @IRTSubsts As -> Type) (_4 : @IRTDesc As) (recr : @IRTSubsts As -> Type) (Ds1 : @IRTSubsts As) => @Either (recl Ds1) (recr Ds1)) (fun (_3 : var__0) (recl : @IRTSubsts As -> Type) (_4 : @IRTDesc As) (recr : @IRTSubsts As -> Type) (Ds1 : @IRTSubsts As) => prod (recl Ds1) (recr Ds1)) (fun (i1 : @SAWCoreScaffolding.Nat) (_3 : SAWCorePrelude.ListSort_rect (fun (_3 : @ListSort) => @SAWCoreScaffolding.Nat -> Type) (fun (_3 : @SAWCoreScaffolding.Nat) => @SAWCoreScaffolding.Eq (@SAWCoreScaffolding.Bool) (@SAWCoreScaffolding.true) (@SAWCoreScaffolding.false)) (fun (A : Type) (_3 : @ListSort) (rec : @SAWCoreScaffolding.Nat -> Type) => @Nat_cases Type A (fun (n1 : @SAWCoreScaffolding.Nat) (_4 : Type) => rec n1)) As i1 -> @IRTDesc As) (recf : SAWCorePrelude.ListSort_rect (fun (_4 : @ListSort) => @SAWCoreScaffolding.Nat -> Type) (fun (_4 : @SAWCoreScaffolding.Nat) => @SAWCoreScaffolding.Eq (@SAWCoreScaffolding.Bool) (@SAWCoreScaffolding.true) (@SAWCoreScaffolding.false)) (fun (A : Type) (_4 : @ListSort) (rec : @SAWCoreScaffolding.Nat -> Type) => @Nat_cases Type A (fun (n1 : @SAWCoreScaffolding.Nat) (_5 : Type) => rec n1)) As i1 -> @IRTSubsts As -> Type) (Ds1 : @IRTSubsts As) => @sigT (@listSortGet As i1) (fun (a : SAWCorePrelude.ListSort_rect (fun (_4 : @ListSort) => @SAWCoreScaffolding.Nat -> Type) (fun (_4 : @SAWCoreScaffolding.Nat) => @SAWCoreScaffolding.Eq (@SAWCoreScaffolding.Bool) (@SAWCoreScaffolding.true) (@SAWCoreScaffolding.false)) (fun (A : Type) (_4 : @ListSort) (rec : @SAWCoreScaffolding.Nat -> Type) => @Nat_cases Type A (fun (n1 : @SAWCoreScaffolding.Nat) (_5 : Type) => rec n1)) As i1) => recf a Ds1)) (fun (n1 : @SAWCoreScaffolding.Nat) (len1 : @SAWCoreVectorsAsCoqVectors.Vec n1 (@SAWCoreScaffolding.Bool)) (_3 : @IRTDesc As) (rec : @IRTSubsts As -> Type) (Ds1 : @IRTSubsts As) => @BVVec n1 len1 (rec Ds1)) (fun (_3 : var__1) => unit) (fun (_3 : var__1) => @SAWCoreScaffolding.Eq (@SAWCoreScaffolding.Bool) (@SAWCoreScaffolding.true) (@SAWCoreScaffolding.false)) (fun (i1 : @SAWCoreScaffolding.Nat) (_3 : @IRTSubsts As) => @listSortGet As i1) D Ds) => @genBVVec n len (@UnfoldedIRT As Ds D) recg) (fun (Ds : @IRTSubsts As) => tt) (fun (Ds : @IRTSubsts As) (i : @SAWCoreScaffolding.Nat) (a : SAWCorePrelude.ListSort_rect (fun (_1 : @ListSort) => @SAWCoreScaffolding.Nat -> Type) (fun (_1 : @SAWCoreScaffolding.Nat) => @SAWCoreScaffolding.Eq (@SAWCoreScaffolding.Bool) (@SAWCoreScaffolding.true) (@SAWCoreScaffolding.false)) (fun (A : Type) (_1 : @ListSort) (rec : @SAWCoreScaffolding.Nat -> Type) => @Nat_cases Type A (fun (n : @SAWCoreScaffolding.Nat) (_2 : Type) => rec n)) As i) => a). + fun (As : @ListSort) => @IRT__rec As (fun (Ds : @IRTSubsts As) (D : @IRTDesc As) (_1 : @IRT As Ds D) => @UnfoldedIRT As Ds D) (fun (Ds : @IRTSubsts As) (i : @SAWCoreScaffolding.Nat) (x : @IRT As (SAWCorePrelude.IRTSubsts_rect As (fun (_1 : @IRTSubsts As) => @SAWCoreScaffolding.Nat -> @IRTSubsts As) (fun (_1 : @SAWCoreScaffolding.Nat) => @IRTs_Nil As) (fun (_1 : @IRTDesc As) (Ds1 : @IRTSubsts As) (rec : @SAWCoreScaffolding.Nat -> @IRTSubsts As) => @Nat_cases (@IRTSubsts As) Ds1 (fun (n : @SAWCoreScaffolding.Nat) (_2 : @IRTSubsts As) => rec n)) Ds (@SAWCoreScaffolding.Succ i)) (SAWCorePrelude.IRTSubsts_rect As (fun (_1 : @IRTSubsts As) => @SAWCoreScaffolding.Nat -> @IRTDesc As) (fun (_1 : @SAWCoreScaffolding.Nat) => @IRT_empty As) (fun (D : @IRTDesc As) (_1 : @IRTSubsts As) (rec : @SAWCoreScaffolding.Nat -> @IRTDesc As) => @Nat_cases (@IRTDesc As) D (fun (n : @SAWCoreScaffolding.Nat) (_2 : @IRTDesc As) => rec n)) Ds i)) (_1 : SAWCorePrelude.IRTDesc_rect As (fun (_1 : @IRTDesc As) => @IRTSubsts As -> Type) (fun (i1 : @SAWCoreScaffolding.Nat) (Ds1 : @IRTSubsts As) => @IRT As (@dropIRTs As Ds1 (@SAWCoreScaffolding.Succ i1)) (@atIRTs As Ds1 i1)) (fun (D : @IRTDesc As) (rec : @IRTSubsts As -> Type) (Ds1 : @IRTSubsts As) => rec (@IRTs_Cons As (@IRT_mu As D) Ds1)) (fun (_1 : @IRTDesc As) (recl : @IRTSubsts As -> Type) (_2 : @IRTDesc As) (recr : @IRTSubsts As -> Type) (Ds1 : @IRTSubsts As) => @Either (recl Ds1) (recr Ds1)) (fun (_1 : @IRTDesc As) (recl : @IRTSubsts As -> Type) (_2 : @IRTDesc As) (recr : @IRTSubsts As -> Type) (Ds1 : @IRTSubsts As) => prod (recl Ds1) (recr Ds1)) (fun (i1 : @SAWCoreScaffolding.Nat) (_1 : SAWCorePrelude.ListSort_rect (fun (_1 : @ListSort) => @SAWCoreScaffolding.Nat -> Type) (fun (_1 : @SAWCoreScaffolding.Nat) => @SAWCoreScaffolding.Eq (@SAWCoreScaffolding.Bool) (@SAWCoreScaffolding.true) (@SAWCoreScaffolding.false)) (fun (A : Type) (_1 : @ListSort) (rec : @SAWCoreScaffolding.Nat -> Type) => @Nat_cases Type A (fun (n : @SAWCoreScaffolding.Nat) (_2 : Type) => rec n)) As i1 -> @IRTDesc As) (recf : SAWCorePrelude.ListSort_rect (fun (_2 : @ListSort) => @SAWCoreScaffolding.Nat -> Type) (fun (_2 : @SAWCoreScaffolding.Nat) => @SAWCoreScaffolding.Eq (@SAWCoreScaffolding.Bool) (@SAWCoreScaffolding.true) (@SAWCoreScaffolding.false)) (fun (A : Type) (_2 : @ListSort) (rec : @SAWCoreScaffolding.Nat -> Type) => @Nat_cases Type A (fun (n : @SAWCoreScaffolding.Nat) (_3 : Type) => rec n)) As i1 -> @IRTSubsts As -> Type) (Ds1 : @IRTSubsts As) => @sigT (@listSortGet As i1) (fun (a : SAWCorePrelude.ListSort_rect (fun (_2 : @ListSort) => @SAWCoreScaffolding.Nat -> Type) (fun (_2 : @SAWCoreScaffolding.Nat) => @SAWCoreScaffolding.Eq (@SAWCoreScaffolding.Bool) (@SAWCoreScaffolding.true) (@SAWCoreScaffolding.false)) (fun (A : Type) (_2 : @ListSort) (rec : @SAWCoreScaffolding.Nat -> Type) => @Nat_cases Type A (fun (n : @SAWCoreScaffolding.Nat) (_3 : Type) => rec n)) As i1) => recf a Ds1)) (fun (n : @SAWCoreScaffolding.Nat) (len : @SAWCoreVectorsAsCoqVectors.Vec n (@SAWCoreScaffolding.Bool)) (_1 : @IRTDesc As) (rec : @IRTSubsts As -> Type) (Ds1 : @IRTSubsts As) => @BVVec n len (rec Ds1)) (fun (_1 : @IRTSubsts As) => unit) (fun (_1 : @IRTSubsts As) => @SAWCoreScaffolding.Eq (@SAWCoreScaffolding.Bool) (@SAWCoreScaffolding.true) (@SAWCoreScaffolding.false)) (fun (i1 : @SAWCoreScaffolding.Nat) (_1 : @IRTSubsts As) => @listSortGet As i1) (SAWCorePrelude.IRTSubsts_rect As (fun (_1 : @IRTSubsts As) => @SAWCoreScaffolding.Nat -> @IRTDesc As) (fun (_1 : @SAWCoreScaffolding.Nat) => @IRT_empty As) (fun (D : @IRTDesc As) (_1 : @IRTSubsts As) (rec : @SAWCoreScaffolding.Nat -> @IRTDesc As) => @Nat_cases (@IRTDesc As) D (fun (n : @SAWCoreScaffolding.Nat) (_2 : @IRTDesc As) => rec n)) Ds i) (@dropIRTs As Ds (@SAWCoreScaffolding.Succ i))) => x) (fun (Ds : @IRTSubsts As) (D : @IRTDesc As) (_1 : @IRT As (@IRTs_Cons As (@IRT_mu As D) Ds) D) (rec : SAWCorePrelude.IRTDesc_rect As (fun (_2 : @IRTDesc As) => @IRTSubsts As -> Type) (fun (i : @SAWCoreScaffolding.Nat) (Ds1 : @IRTSubsts As) => @IRT As (@dropIRTs As Ds1 (@SAWCoreScaffolding.Succ i)) (@atIRTs As Ds1 i)) (fun (D1 : @IRTDesc As) (rec : @IRTSubsts As -> Type) (Ds1 : @IRTSubsts As) => rec (@IRTs_Cons As (@IRT_mu As D1) Ds1)) (fun (_2 : @IRTDesc As) (recl : @IRTSubsts As -> Type) (_3 : @IRTDesc As) (recr : @IRTSubsts As -> Type) (Ds1 : @IRTSubsts As) => @Either (recl Ds1) (recr Ds1)) (fun (_2 : @IRTDesc As) (recl : @IRTSubsts As -> Type) (_3 : @IRTDesc As) (recr : @IRTSubsts As -> Type) (Ds1 : @IRTSubsts As) => prod (recl Ds1) (recr Ds1)) (fun (i : @SAWCoreScaffolding.Nat) (_2 : SAWCorePrelude.ListSort_rect (fun (_2 : @ListSort) => @SAWCoreScaffolding.Nat -> Type) (fun (_2 : @SAWCoreScaffolding.Nat) => @SAWCoreScaffolding.Eq (@SAWCoreScaffolding.Bool) (@SAWCoreScaffolding.true) (@SAWCoreScaffolding.false)) (fun (A : Type) (_2 : @ListSort) (rec : @SAWCoreScaffolding.Nat -> Type) => @Nat_cases Type A (fun (n : @SAWCoreScaffolding.Nat) (_3 : Type) => rec n)) As i -> @IRTDesc As) (recf : SAWCorePrelude.ListSort_rect (fun (_3 : @ListSort) => @SAWCoreScaffolding.Nat -> Type) (fun (_3 : @SAWCoreScaffolding.Nat) => @SAWCoreScaffolding.Eq (@SAWCoreScaffolding.Bool) (@SAWCoreScaffolding.true) (@SAWCoreScaffolding.false)) (fun (A : Type) (_3 : @ListSort) (rec : @SAWCoreScaffolding.Nat -> Type) => @Nat_cases Type A (fun (n : @SAWCoreScaffolding.Nat) (_4 : Type) => rec n)) As i -> @IRTSubsts As -> Type) (Ds1 : @IRTSubsts As) => @sigT (@listSortGet As i) (fun (a : SAWCorePrelude.ListSort_rect (fun (_3 : @ListSort) => @SAWCoreScaffolding.Nat -> Type) (fun (_3 : @SAWCoreScaffolding.Nat) => @SAWCoreScaffolding.Eq (@SAWCoreScaffolding.Bool) (@SAWCoreScaffolding.true) (@SAWCoreScaffolding.false)) (fun (A : Type) (_3 : @ListSort) (rec : @SAWCoreScaffolding.Nat -> Type) => @Nat_cases Type A (fun (n : @SAWCoreScaffolding.Nat) (_4 : Type) => rec n)) As i) => recf a Ds1)) (fun (n : @SAWCoreScaffolding.Nat) (len : @SAWCoreVectorsAsCoqVectors.Vec n (@SAWCoreScaffolding.Bool)) (_2 : @IRTDesc As) (rec : @IRTSubsts As -> Type) (Ds1 : @IRTSubsts As) => @BVVec n len (rec Ds1)) (fun (_2 : @IRTSubsts As) => unit) (fun (_2 : @IRTSubsts As) => @SAWCoreScaffolding.Eq (@SAWCoreScaffolding.Bool) (@SAWCoreScaffolding.true) (@SAWCoreScaffolding.false)) (fun (i : @SAWCoreScaffolding.Nat) (_2 : @IRTSubsts As) => @listSortGet As i) D (@IRTs_Cons As (@IRT_mu As D) Ds)) => rec) (fun (Ds : @IRTSubsts As) (Dl : @IRTDesc As) (Dr : @IRTDesc As) (_1 : @IRT As Ds Dl) (recl : SAWCorePrelude.IRTDesc_rect As (fun (_2 : @IRTDesc As) => @IRTSubsts As -> Type) (fun (i : @SAWCoreScaffolding.Nat) (Ds1 : @IRTSubsts As) => @IRT As (@dropIRTs As Ds1 (@SAWCoreScaffolding.Succ i)) (@atIRTs As Ds1 i)) (fun (D : @IRTDesc As) (rec : @IRTSubsts As -> Type) (Ds1 : @IRTSubsts As) => rec (@IRTs_Cons As (@IRT_mu As D) Ds1)) (fun (_2 : @IRTDesc As) (recl : @IRTSubsts As -> Type) (_3 : @IRTDesc As) (recr : @IRTSubsts As -> Type) (Ds1 : @IRTSubsts As) => @Either (recl Ds1) (recr Ds1)) (fun (_2 : @IRTDesc As) (recl : @IRTSubsts As -> Type) (_3 : @IRTDesc As) (recr : @IRTSubsts As -> Type) (Ds1 : @IRTSubsts As) => prod (recl Ds1) (recr Ds1)) (fun (i : @SAWCoreScaffolding.Nat) (_2 : SAWCorePrelude.ListSort_rect (fun (_2 : @ListSort) => @SAWCoreScaffolding.Nat -> Type) (fun (_2 : @SAWCoreScaffolding.Nat) => @SAWCoreScaffolding.Eq (@SAWCoreScaffolding.Bool) (@SAWCoreScaffolding.true) (@SAWCoreScaffolding.false)) (fun (A : Type) (_2 : @ListSort) (rec : @SAWCoreScaffolding.Nat -> Type) => @Nat_cases Type A (fun (n : @SAWCoreScaffolding.Nat) (_3 : Type) => rec n)) As i -> @IRTDesc As) (recf : SAWCorePrelude.ListSort_rect (fun (_3 : @ListSort) => @SAWCoreScaffolding.Nat -> Type) (fun (_3 : @SAWCoreScaffolding.Nat) => @SAWCoreScaffolding.Eq (@SAWCoreScaffolding.Bool) (@SAWCoreScaffolding.true) (@SAWCoreScaffolding.false)) (fun (A : Type) (_3 : @ListSort) (rec : @SAWCoreScaffolding.Nat -> Type) => @Nat_cases Type A (fun (n : @SAWCoreScaffolding.Nat) (_4 : Type) => rec n)) As i -> @IRTSubsts As -> Type) (Ds1 : @IRTSubsts As) => @sigT (@listSortGet As i) (fun (a : SAWCorePrelude.ListSort_rect (fun (_3 : @ListSort) => @SAWCoreScaffolding.Nat -> Type) (fun (_3 : @SAWCoreScaffolding.Nat) => @SAWCoreScaffolding.Eq (@SAWCoreScaffolding.Bool) (@SAWCoreScaffolding.true) (@SAWCoreScaffolding.false)) (fun (A : Type) (_3 : @ListSort) (rec : @SAWCoreScaffolding.Nat -> Type) => @Nat_cases Type A (fun (n : @SAWCoreScaffolding.Nat) (_4 : Type) => rec n)) As i) => recf a Ds1)) (fun (n : @SAWCoreScaffolding.Nat) (len : @SAWCoreVectorsAsCoqVectors.Vec n (@SAWCoreScaffolding.Bool)) (_2 : @IRTDesc As) (rec : @IRTSubsts As -> Type) (Ds1 : @IRTSubsts As) => @BVVec n len (rec Ds1)) (fun (_2 : @IRTSubsts As) => unit) (fun (_2 : @IRTSubsts As) => @SAWCoreScaffolding.Eq (@SAWCoreScaffolding.Bool) (@SAWCoreScaffolding.true) (@SAWCoreScaffolding.false)) (fun (i : @SAWCoreScaffolding.Nat) (_2 : @IRTSubsts As) => @listSortGet As i) Dl Ds) => @Left (@UnfoldedIRT As Ds Dl) (@UnfoldedIRT As Ds Dr) recl) (fun (Ds : @IRTSubsts As) (Dl : @IRTDesc As) (Dr : @IRTDesc As) (_1 : @IRT As Ds Dr) (recr : SAWCorePrelude.IRTDesc_rect As (fun (_2 : @IRTDesc As) => @IRTSubsts As -> Type) (fun (i : @SAWCoreScaffolding.Nat) (Ds1 : @IRTSubsts As) => @IRT As (@dropIRTs As Ds1 (@SAWCoreScaffolding.Succ i)) (@atIRTs As Ds1 i)) (fun (D : @IRTDesc As) (rec : @IRTSubsts As -> Type) (Ds1 : @IRTSubsts As) => rec (@IRTs_Cons As (@IRT_mu As D) Ds1)) (fun (_2 : @IRTDesc As) (recl : @IRTSubsts As -> Type) (_3 : @IRTDesc As) (recr : @IRTSubsts As -> Type) (Ds1 : @IRTSubsts As) => @Either (recl Ds1) (recr Ds1)) (fun (_2 : @IRTDesc As) (recl : @IRTSubsts As -> Type) (_3 : @IRTDesc As) (recr : @IRTSubsts As -> Type) (Ds1 : @IRTSubsts As) => prod (recl Ds1) (recr Ds1)) (fun (i : @SAWCoreScaffolding.Nat) (_2 : SAWCorePrelude.ListSort_rect (fun (_2 : @ListSort) => @SAWCoreScaffolding.Nat -> Type) (fun (_2 : @SAWCoreScaffolding.Nat) => @SAWCoreScaffolding.Eq (@SAWCoreScaffolding.Bool) (@SAWCoreScaffolding.true) (@SAWCoreScaffolding.false)) (fun (A : Type) (_2 : @ListSort) (rec : @SAWCoreScaffolding.Nat -> Type) => @Nat_cases Type A (fun (n : @SAWCoreScaffolding.Nat) (_3 : Type) => rec n)) As i -> @IRTDesc As) (recf : SAWCorePrelude.ListSort_rect (fun (_3 : @ListSort) => @SAWCoreScaffolding.Nat -> Type) (fun (_3 : @SAWCoreScaffolding.Nat) => @SAWCoreScaffolding.Eq (@SAWCoreScaffolding.Bool) (@SAWCoreScaffolding.true) (@SAWCoreScaffolding.false)) (fun (A : Type) (_3 : @ListSort) (rec : @SAWCoreScaffolding.Nat -> Type) => @Nat_cases Type A (fun (n : @SAWCoreScaffolding.Nat) (_4 : Type) => rec n)) As i -> @IRTSubsts As -> Type) (Ds1 : @IRTSubsts As) => @sigT (@listSortGet As i) (fun (a : SAWCorePrelude.ListSort_rect (fun (_3 : @ListSort) => @SAWCoreScaffolding.Nat -> Type) (fun (_3 : @SAWCoreScaffolding.Nat) => @SAWCoreScaffolding.Eq (@SAWCoreScaffolding.Bool) (@SAWCoreScaffolding.true) (@SAWCoreScaffolding.false)) (fun (A : Type) (_3 : @ListSort) (rec : @SAWCoreScaffolding.Nat -> Type) => @Nat_cases Type A (fun (n : @SAWCoreScaffolding.Nat) (_4 : Type) => rec n)) As i) => recf a Ds1)) (fun (n : @SAWCoreScaffolding.Nat) (len : @SAWCoreVectorsAsCoqVectors.Vec n (@SAWCoreScaffolding.Bool)) (_2 : @IRTDesc As) (rec : @IRTSubsts As -> Type) (Ds1 : @IRTSubsts As) => @BVVec n len (rec Ds1)) (fun (_2 : @IRTSubsts As) => unit) (fun (_2 : @IRTSubsts As) => @SAWCoreScaffolding.Eq (@SAWCoreScaffolding.Bool) (@SAWCoreScaffolding.true) (@SAWCoreScaffolding.false)) (fun (i : @SAWCoreScaffolding.Nat) (_2 : @IRTSubsts As) => @listSortGet As i) Dr Ds) => @Right (@UnfoldedIRT As Ds Dl) (@UnfoldedIRT As Ds Dr) recr) (fun (Ds : @IRTSubsts As) (Dl : @IRTDesc As) (Dr : @IRTDesc As) (_1 : @IRT As Ds Dl) (recl : SAWCorePrelude.IRTDesc_rect As (fun (_2 : @IRTDesc As) => @IRTSubsts As -> Type) (fun (i : @SAWCoreScaffolding.Nat) (Ds1 : @IRTSubsts As) => @IRT As (@dropIRTs As Ds1 (@SAWCoreScaffolding.Succ i)) (@atIRTs As Ds1 i)) (fun (D : @IRTDesc As) (rec : @IRTSubsts As -> Type) (Ds1 : @IRTSubsts As) => rec (@IRTs_Cons As (@IRT_mu As D) Ds1)) (fun (_2 : @IRTDesc As) (recl : @IRTSubsts As -> Type) (_3 : @IRTDesc As) (recr : @IRTSubsts As -> Type) (Ds1 : @IRTSubsts As) => @Either (recl Ds1) (recr Ds1)) (fun (_2 : @IRTDesc As) (recl : @IRTSubsts As -> Type) (_3 : @IRTDesc As) (recr : @IRTSubsts As -> Type) (Ds1 : @IRTSubsts As) => prod (recl Ds1) (recr Ds1)) (fun (i : @SAWCoreScaffolding.Nat) (_2 : SAWCorePrelude.ListSort_rect (fun (_2 : @ListSort) => @SAWCoreScaffolding.Nat -> Type) (fun (_2 : @SAWCoreScaffolding.Nat) => @SAWCoreScaffolding.Eq (@SAWCoreScaffolding.Bool) (@SAWCoreScaffolding.true) (@SAWCoreScaffolding.false)) (fun (A : Type) (_2 : @ListSort) (rec : @SAWCoreScaffolding.Nat -> Type) => @Nat_cases Type A (fun (n : @SAWCoreScaffolding.Nat) (_3 : Type) => rec n)) As i -> @IRTDesc As) (recf : SAWCorePrelude.ListSort_rect (fun (_3 : @ListSort) => @SAWCoreScaffolding.Nat -> Type) (fun (_3 : @SAWCoreScaffolding.Nat) => @SAWCoreScaffolding.Eq (@SAWCoreScaffolding.Bool) (@SAWCoreScaffolding.true) (@SAWCoreScaffolding.false)) (fun (A : Type) (_3 : @ListSort) (rec : @SAWCoreScaffolding.Nat -> Type) => @Nat_cases Type A (fun (n : @SAWCoreScaffolding.Nat) (_4 : Type) => rec n)) As i -> @IRTSubsts As -> Type) (Ds1 : @IRTSubsts As) => @sigT (@listSortGet As i) (fun (a : SAWCorePrelude.ListSort_rect (fun (_3 : @ListSort) => @SAWCoreScaffolding.Nat -> Type) (fun (_3 : @SAWCoreScaffolding.Nat) => @SAWCoreScaffolding.Eq (@SAWCoreScaffolding.Bool) (@SAWCoreScaffolding.true) (@SAWCoreScaffolding.false)) (fun (A : Type) (_3 : @ListSort) (rec : @SAWCoreScaffolding.Nat -> Type) => @Nat_cases Type A (fun (n : @SAWCoreScaffolding.Nat) (_4 : Type) => rec n)) As i) => recf a Ds1)) (fun (n : @SAWCoreScaffolding.Nat) (len : @SAWCoreVectorsAsCoqVectors.Vec n (@SAWCoreScaffolding.Bool)) (_2 : @IRTDesc As) (rec : @IRTSubsts As -> Type) (Ds1 : @IRTSubsts As) => @BVVec n len (rec Ds1)) (fun (_2 : @IRTSubsts As) => unit) (fun (_2 : @IRTSubsts As) => @SAWCoreScaffolding.Eq (@SAWCoreScaffolding.Bool) (@SAWCoreScaffolding.true) (@SAWCoreScaffolding.false)) (fun (i : @SAWCoreScaffolding.Nat) (_2 : @IRTSubsts As) => @listSortGet As i) Dl Ds) (_2 : @IRT As Ds Dr) (recr : SAWCorePrelude.IRTDesc_rect As (fun (_3 : @IRTDesc As) => @IRTSubsts As -> Type) (fun (i : @SAWCoreScaffolding.Nat) (Ds1 : @IRTSubsts As) => @IRT As (@dropIRTs As Ds1 (@SAWCoreScaffolding.Succ i)) (@atIRTs As Ds1 i)) (fun (D : @IRTDesc As) (rec : @IRTSubsts As -> Type) (Ds1 : @IRTSubsts As) => rec (@IRTs_Cons As (@IRT_mu As D) Ds1)) (fun (_3 : @IRTDesc As) (recl1 : @IRTSubsts As -> Type) (_4 : @IRTDesc As) (recr : @IRTSubsts As -> Type) (Ds1 : @IRTSubsts As) => @Either (recl1 Ds1) (recr Ds1)) (fun (_3 : @IRTDesc As) (recl1 : @IRTSubsts As -> Type) (_4 : @IRTDesc As) (recr : @IRTSubsts As -> Type) (Ds1 : @IRTSubsts As) => prod (recl1 Ds1) (recr Ds1)) (fun (i : @SAWCoreScaffolding.Nat) (_3 : SAWCorePrelude.ListSort_rect (fun (_3 : @ListSort) => @SAWCoreScaffolding.Nat -> Type) (fun (_3 : @SAWCoreScaffolding.Nat) => @SAWCoreScaffolding.Eq (@SAWCoreScaffolding.Bool) (@SAWCoreScaffolding.true) (@SAWCoreScaffolding.false)) (fun (A : Type) (_3 : @ListSort) (rec : @SAWCoreScaffolding.Nat -> Type) => @Nat_cases Type A (fun (n : @SAWCoreScaffolding.Nat) (_4 : Type) => rec n)) As i -> @IRTDesc As) (recf : SAWCorePrelude.ListSort_rect (fun (_4 : @ListSort) => @SAWCoreScaffolding.Nat -> Type) (fun (_4 : @SAWCoreScaffolding.Nat) => @SAWCoreScaffolding.Eq (@SAWCoreScaffolding.Bool) (@SAWCoreScaffolding.true) (@SAWCoreScaffolding.false)) (fun (A : Type) (_4 : @ListSort) (rec : @SAWCoreScaffolding.Nat -> Type) => @Nat_cases Type A (fun (n : @SAWCoreScaffolding.Nat) (_5 : Type) => rec n)) As i -> @IRTSubsts As -> Type) (Ds1 : @IRTSubsts As) => @sigT (@listSortGet As i) (fun (a : SAWCorePrelude.ListSort_rect (fun (_4 : @ListSort) => @SAWCoreScaffolding.Nat -> Type) (fun (_4 : @SAWCoreScaffolding.Nat) => @SAWCoreScaffolding.Eq (@SAWCoreScaffolding.Bool) (@SAWCoreScaffolding.true) (@SAWCoreScaffolding.false)) (fun (A : Type) (_4 : @ListSort) (rec : @SAWCoreScaffolding.Nat -> Type) => @Nat_cases Type A (fun (n : @SAWCoreScaffolding.Nat) (_5 : Type) => rec n)) As i) => recf a Ds1)) (fun (n : @SAWCoreScaffolding.Nat) (len : @SAWCoreVectorsAsCoqVectors.Vec n (@SAWCoreScaffolding.Bool)) (_3 : @IRTDesc As) (rec : @IRTSubsts As -> Type) (Ds1 : @IRTSubsts As) => @BVVec n len (rec Ds1)) (fun (_3 : @IRTSubsts As) => unit) (fun (_3 : @IRTSubsts As) => @SAWCoreScaffolding.Eq (@SAWCoreScaffolding.Bool) (@SAWCoreScaffolding.true) (@SAWCoreScaffolding.false)) (fun (i : @SAWCoreScaffolding.Nat) (_3 : @IRTSubsts As) => @listSortGet As i) Dr Ds) => pair recl recr) (fun (Ds : @IRTSubsts As) (i : @SAWCoreScaffolding.Nat) (Df : SAWCorePrelude.ListSort_rect (fun (_1 : @ListSort) => @SAWCoreScaffolding.Nat -> Type) (fun (_1 : @SAWCoreScaffolding.Nat) => @SAWCoreScaffolding.Eq (@SAWCoreScaffolding.Bool) (@SAWCoreScaffolding.true) (@SAWCoreScaffolding.false)) (fun (A : Type) (_1 : @ListSort) (rec : @SAWCoreScaffolding.Nat -> Type) => @Nat_cases Type A (fun (n : @SAWCoreScaffolding.Nat) (_2 : Type) => rec n)) As i -> @IRTDesc As) (a : SAWCorePrelude.ListSort_rect (fun (_1 : @ListSort) => @SAWCoreScaffolding.Nat -> Type) (fun (_1 : @SAWCoreScaffolding.Nat) => @SAWCoreScaffolding.Eq (@SAWCoreScaffolding.Bool) (@SAWCoreScaffolding.true) (@SAWCoreScaffolding.false)) (fun (A : Type) (_1 : @ListSort) (rec : @SAWCoreScaffolding.Nat -> Type) => @Nat_cases Type A (fun (n : @SAWCoreScaffolding.Nat) (_2 : Type) => rec n)) As i) (_1 : @IRT As Ds (Df a)) (recf : SAWCorePrelude.IRTDesc_rect As (fun (_2 : @IRTDesc As) => @IRTSubsts As -> Type) (fun (i1 : @SAWCoreScaffolding.Nat) (Ds1 : @IRTSubsts As) => @IRT As (@dropIRTs As Ds1 (@SAWCoreScaffolding.Succ i1)) (@atIRTs As Ds1 i1)) (fun (D : @IRTDesc As) (rec : @IRTSubsts As -> Type) (Ds1 : @IRTSubsts As) => rec (@IRTs_Cons As (@IRT_mu As D) Ds1)) (fun (_2 : @IRTDesc As) (recl : @IRTSubsts As -> Type) (_3 : @IRTDesc As) (recr : @IRTSubsts As -> Type) (Ds1 : @IRTSubsts As) => @Either (recl Ds1) (recr Ds1)) (fun (_2 : @IRTDesc As) (recl : @IRTSubsts As -> Type) (_3 : @IRTDesc As) (recr : @IRTSubsts As -> Type) (Ds1 : @IRTSubsts As) => prod (recl Ds1) (recr Ds1)) (fun (i1 : @SAWCoreScaffolding.Nat) (_2 : SAWCorePrelude.ListSort_rect (fun (_2 : @ListSort) => @SAWCoreScaffolding.Nat -> Type) (fun (_2 : @SAWCoreScaffolding.Nat) => @SAWCoreScaffolding.Eq (@SAWCoreScaffolding.Bool) (@SAWCoreScaffolding.true) (@SAWCoreScaffolding.false)) (fun (A : Type) (_2 : @ListSort) (rec : @SAWCoreScaffolding.Nat -> Type) => @Nat_cases Type A (fun (n : @SAWCoreScaffolding.Nat) (_3 : Type) => rec n)) As i1 -> @IRTDesc As) (recf : SAWCorePrelude.ListSort_rect (fun (_3 : @ListSort) => @SAWCoreScaffolding.Nat -> Type) (fun (_3 : @SAWCoreScaffolding.Nat) => @SAWCoreScaffolding.Eq (@SAWCoreScaffolding.Bool) (@SAWCoreScaffolding.true) (@SAWCoreScaffolding.false)) (fun (A : Type) (_3 : @ListSort) (rec : @SAWCoreScaffolding.Nat -> Type) => @Nat_cases Type A (fun (n : @SAWCoreScaffolding.Nat) (_4 : Type) => rec n)) As i1 -> @IRTSubsts As -> Type) (Ds1 : @IRTSubsts As) => @sigT (@listSortGet As i1) (fun (a1 : SAWCorePrelude.ListSort_rect (fun (_3 : @ListSort) => @SAWCoreScaffolding.Nat -> Type) (fun (_3 : @SAWCoreScaffolding.Nat) => @SAWCoreScaffolding.Eq (@SAWCoreScaffolding.Bool) (@SAWCoreScaffolding.true) (@SAWCoreScaffolding.false)) (fun (A : Type) (_3 : @ListSort) (rec : @SAWCoreScaffolding.Nat -> Type) => @Nat_cases Type A (fun (n : @SAWCoreScaffolding.Nat) (_4 : Type) => rec n)) As i1) => recf a1 Ds1)) (fun (n : @SAWCoreScaffolding.Nat) (len : @SAWCoreVectorsAsCoqVectors.Vec n (@SAWCoreScaffolding.Bool)) (_2 : @IRTDesc As) (rec : @IRTSubsts As -> Type) (Ds1 : @IRTSubsts As) => @BVVec n len (rec Ds1)) (fun (_2 : @IRTSubsts As) => unit) (fun (_2 : @IRTSubsts As) => @SAWCoreScaffolding.Eq (@SAWCoreScaffolding.Bool) (@SAWCoreScaffolding.true) (@SAWCoreScaffolding.false)) (fun (i1 : @SAWCoreScaffolding.Nat) (_2 : @IRTSubsts As) => @listSortGet As i1) (Df a) Ds) => @existT (@listSortGet As i) (fun (a1 : SAWCorePrelude.ListSort_rect (fun (_2 : @ListSort) => @SAWCoreScaffolding.Nat -> Type) (fun (_2 : @SAWCoreScaffolding.Nat) => @SAWCoreScaffolding.Eq (@SAWCoreScaffolding.Bool) (@SAWCoreScaffolding.true) (@SAWCoreScaffolding.false)) (fun (A : Type) (_2 : @ListSort) (rec : @SAWCoreScaffolding.Nat -> Type) => @Nat_cases Type A (fun (n : @SAWCoreScaffolding.Nat) (_3 : Type) => rec n)) As i) => @UnfoldedIRT As Ds (Df a1)) a recf) (fun (Ds : @IRTSubsts As) (n : @SAWCoreScaffolding.Nat) (len : @SAWCoreVectorsAsCoqVectors.Vec n (@SAWCoreScaffolding.Bool)) (D : @IRTDesc As) (_1 : forall (i : @SAWCoreVectorsAsCoqVectors.Vec n (@SAWCoreScaffolding.Bool)), @SAWCoreScaffolding.Eq (@SAWCoreScaffolding.Bool) (@SAWCoreVectorsAsCoqVectors.bvult n i len) (@SAWCoreScaffolding.true) -> @IRT As Ds D) (recg : forall (i : @SAWCoreVectorsAsCoqVectors.Vec n (@SAWCoreScaffolding.Bool)), @SAWCoreScaffolding.Eq (@SAWCoreScaffolding.Bool) (@SAWCoreVectorsAsCoqVectors.bvult n i len) (@SAWCoreScaffolding.true) -> let var__0 := forall (As1 : @ListSort), Type in + let var__1 := forall (As1 : @ListSort), @IRTDesc As1 -> @IRTDesc As1 -> @IRTDesc As1 in + let var__2 := forall (As1 : @ListSort), @IRTDesc As1 in + let var__3 := @IRTDesc As in let var__4 := @IRTSubsts As in + SAWCorePrelude.IRTDesc_rect As (fun (_3 : var__3) => @IRTSubsts As -> Type) (fun (i1 : @SAWCoreScaffolding.Nat) (Ds1 : @IRTSubsts As) => @IRT As (@dropIRTs As Ds1 (@SAWCoreScaffolding.Succ i1)) (@atIRTs As Ds1 i1)) (fun (D1 : var__3) (rec : @IRTSubsts As -> Type) (Ds1 : @IRTSubsts As) => rec (@IRTs_Cons As (@IRT_mu As D1) Ds1)) (fun (_3 : var__3) (recl : @IRTSubsts As -> Type) (_4 : @IRTDesc As) (recr : @IRTSubsts As -> Type) (Ds1 : @IRTSubsts As) => @Either (recl Ds1) (recr Ds1)) (fun (_3 : var__3) (recl : @IRTSubsts As -> Type) (_4 : @IRTDesc As) (recr : @IRTSubsts As -> Type) (Ds1 : @IRTSubsts As) => prod (recl Ds1) (recr Ds1)) (fun (i1 : @SAWCoreScaffolding.Nat) (_3 : SAWCorePrelude.ListSort_rect (fun (_3 : @ListSort) => @SAWCoreScaffolding.Nat -> Type) (fun (_3 : @SAWCoreScaffolding.Nat) => @SAWCoreScaffolding.Eq (@SAWCoreScaffolding.Bool) (@SAWCoreScaffolding.true) (@SAWCoreScaffolding.false)) (fun (A : Type) (_3 : @ListSort) (rec : @SAWCoreScaffolding.Nat -> Type) => @Nat_cases Type A (fun (n1 : @SAWCoreScaffolding.Nat) (_4 : Type) => rec n1)) As i1 -> @IRTDesc As) (recf : SAWCorePrelude.ListSort_rect (fun (_4 : @ListSort) => @SAWCoreScaffolding.Nat -> Type) (fun (_4 : @SAWCoreScaffolding.Nat) => @SAWCoreScaffolding.Eq (@SAWCoreScaffolding.Bool) (@SAWCoreScaffolding.true) (@SAWCoreScaffolding.false)) (fun (A : Type) (_4 : @ListSort) (rec : @SAWCoreScaffolding.Nat -> Type) => @Nat_cases Type A (fun (n1 : @SAWCoreScaffolding.Nat) (_5 : Type) => rec n1)) As i1 -> @IRTSubsts As -> Type) (Ds1 : @IRTSubsts As) => @sigT (@listSortGet As i1) (fun (a : SAWCorePrelude.ListSort_rect (fun (_4 : @ListSort) => @SAWCoreScaffolding.Nat -> Type) (fun (_4 : @SAWCoreScaffolding.Nat) => @SAWCoreScaffolding.Eq (@SAWCoreScaffolding.Bool) (@SAWCoreScaffolding.true) (@SAWCoreScaffolding.false)) (fun (A : Type) (_4 : @ListSort) (rec : @SAWCoreScaffolding.Nat -> Type) => @Nat_cases Type A (fun (n1 : @SAWCoreScaffolding.Nat) (_5 : Type) => rec n1)) As i1) => recf a Ds1)) (fun (n1 : @SAWCoreScaffolding.Nat) (len1 : @SAWCoreVectorsAsCoqVectors.Vec n1 (@SAWCoreScaffolding.Bool)) (_3 : @IRTDesc As) (rec : @IRTSubsts As -> Type) (Ds1 : @IRTSubsts As) => @BVVec n1 len1 (rec Ds1)) (fun (_3 : var__4) => unit) (fun (_3 : var__4) => @SAWCoreScaffolding.Eq (@SAWCoreScaffolding.Bool) (@SAWCoreScaffolding.true) (@SAWCoreScaffolding.false)) (fun (i1 : @SAWCoreScaffolding.Nat) (_3 : @IRTSubsts As) => @listSortGet As i1) D Ds) => @genBVVec n len (@UnfoldedIRT As Ds D) recg) (fun (Ds : @IRTSubsts As) => tt) (fun (Ds : @IRTSubsts As) (i : @SAWCoreScaffolding.Nat) (a : SAWCorePrelude.ListSort_rect (fun (_1 : @ListSort) => @SAWCoreScaffolding.Nat -> Type) (fun (_1 : @SAWCoreScaffolding.Nat) => @SAWCoreScaffolding.Eq (@SAWCoreScaffolding.Bool) (@SAWCoreScaffolding.true) (@SAWCoreScaffolding.false)) (fun (A : Type) (_1 : @ListSort) (rec : @SAWCoreScaffolding.Nat -> Type) => @Nat_cases Type A (fun (n : @SAWCoreScaffolding.Nat) (_2 : Type) => rec n)) As i) => a). Definition foldIRT : forall (As : @ListSort), forall (Ds : @IRTSubsts As), forall (D : @IRTDesc As), @UnfoldedIRT As Ds D -> @IRT As Ds D := fun (As : @ListSort) (Ds : @IRTSubsts As) (D : @IRTDesc As) => @IRTDesc__rec As (fun (D1 : @IRTDesc As) => forall (Ds1 : @IRTSubsts As), @UnfoldedIRT As Ds1 D1 -> @IRT As Ds1 D1) (fun (i : @SAWCoreScaffolding.Nat) (Ds1 : @IRTSubsts As) (x : @IRT As (SAWCorePrelude.IRTSubsts_rect As (fun (_1 : @IRTSubsts As) => @SAWCoreScaffolding.Nat -> @IRTSubsts As) (fun (_1 : @SAWCoreScaffolding.Nat) => @IRTs_Nil As) (fun (_1 : @IRTDesc As) (Ds2 : @IRTSubsts As) (rec : @SAWCoreScaffolding.Nat -> @IRTSubsts As) => @Nat_cases (@IRTSubsts As) Ds2 (fun (n : @SAWCoreScaffolding.Nat) (_2 : @IRTSubsts As) => rec n)) Ds1 (@SAWCoreScaffolding.Succ i)) (SAWCorePrelude.IRTSubsts_rect As (fun (_1 : @IRTSubsts As) => @SAWCoreScaffolding.Nat -> @IRTDesc As) (fun (_1 : @SAWCoreScaffolding.Nat) => @IRT_empty As) (fun (D1 : @IRTDesc As) (_1 : @IRTSubsts As) (rec : @SAWCoreScaffolding.Nat -> @IRTDesc As) => @Nat_cases (@IRTDesc As) D1 (fun (n : @SAWCoreScaffolding.Nat) (_2 : @IRTDesc As) => rec n)) Ds1 i)) => @IRT_elemD As Ds1 i x) (fun (D1 : @IRTDesc As) (rec : forall (Ds1 : @IRTSubsts As), SAWCorePrelude.IRTDesc_rect As (fun (_1 : @IRTDesc As) => @IRTSubsts As -> Type) (fun (i : @SAWCoreScaffolding.Nat) (Ds2 : @IRTSubsts As) => @IRT As (@dropIRTs As Ds2 (@SAWCoreScaffolding.Succ i)) (@atIRTs As Ds2 i)) (fun (D2 : @IRTDesc As) (rec : @IRTSubsts As -> Type) (Ds2 : @IRTSubsts As) => rec (@IRTs_Cons As (@IRT_mu As D2) Ds2)) (fun (_1 : @IRTDesc As) (recl : @IRTSubsts As -> Type) (_2 : @IRTDesc As) (recr : @IRTSubsts As -> Type) (Ds2 : @IRTSubsts As) => @Either (recl Ds2) (recr Ds2)) (fun (_1 : @IRTDesc As) (recl : @IRTSubsts As -> Type) (_2 : @IRTDesc As) (recr : @IRTSubsts As -> Type) (Ds2 : @IRTSubsts As) => prod (recl Ds2) (recr Ds2)) (fun (i : @SAWCoreScaffolding.Nat) (_1 : SAWCorePrelude.ListSort_rect (fun (_1 : @ListSort) => @SAWCoreScaffolding.Nat -> Type) (fun (_1 : @SAWCoreScaffolding.Nat) => @SAWCoreScaffolding.Eq (@SAWCoreScaffolding.Bool) (@SAWCoreScaffolding.true) (@SAWCoreScaffolding.false)) (fun (A : Type) (_1 : @ListSort) (rec : @SAWCoreScaffolding.Nat -> Type) => @Nat_cases Type A (fun (n : @SAWCoreScaffolding.Nat) (_2 : Type) => rec n)) As i -> @IRTDesc As) (recf : SAWCorePrelude.ListSort_rect (fun (_2 : @ListSort) => @SAWCoreScaffolding.Nat -> Type) (fun (_2 : @SAWCoreScaffolding.Nat) => @SAWCoreScaffolding.Eq (@SAWCoreScaffolding.Bool) (@SAWCoreScaffolding.true) (@SAWCoreScaffolding.false)) (fun (A : Type) (_2 : @ListSort) (rec : @SAWCoreScaffolding.Nat -> Type) => @Nat_cases Type A (fun (n : @SAWCoreScaffolding.Nat) (_3 : Type) => rec n)) As i -> @IRTSubsts As -> Type) (Ds2 : @IRTSubsts As) => @sigT (@listSortGet As i) (fun (a : SAWCorePrelude.ListSort_rect (fun (_2 : @ListSort) => @SAWCoreScaffolding.Nat -> Type) (fun (_2 : @SAWCoreScaffolding.Nat) => @SAWCoreScaffolding.Eq (@SAWCoreScaffolding.Bool) (@SAWCoreScaffolding.true) (@SAWCoreScaffolding.false)) (fun (A : Type) (_2 : @ListSort) (rec : @SAWCoreScaffolding.Nat -> Type) => @Nat_cases Type A (fun (n : @SAWCoreScaffolding.Nat) (_3 : Type) => rec n)) As i) => recf a Ds2)) (fun (n : @SAWCoreScaffolding.Nat) (len : @SAWCoreVectorsAsCoqVectors.Vec n (@SAWCoreScaffolding.Bool)) (_1 : @IRTDesc As) (rec : @IRTSubsts As -> Type) (Ds2 : @IRTSubsts As) => @BVVec n len (rec Ds2)) (fun (_1 : @IRTSubsts As) => unit) (fun (_1 : @IRTSubsts As) => @SAWCoreScaffolding.Eq (@SAWCoreScaffolding.Bool) (@SAWCoreScaffolding.true) (@SAWCoreScaffolding.false)) (fun (i : @SAWCoreScaffolding.Nat) (_1 : @IRTSubsts As) => @listSortGet As i) D1 Ds1 -> @IRT As Ds1 D1) (Ds1 : @IRTSubsts As) (x : SAWCorePrelude.IRTDesc_rect As (fun (_1 : @IRTDesc As) => @IRTSubsts As -> Type) (fun (i : @SAWCoreScaffolding.Nat) (Ds2 : @IRTSubsts As) => @IRT As (@dropIRTs As Ds2 (@SAWCoreScaffolding.Succ i)) (@atIRTs As Ds2 i)) (fun (D2 : @IRTDesc As) (rec1 : @IRTSubsts As -> Type) (Ds2 : @IRTSubsts As) => rec1 (@IRTs_Cons As (@IRT_mu As D2) Ds2)) (fun (_1 : @IRTDesc As) (recl : @IRTSubsts As -> Type) (_2 : @IRTDesc As) (recr : @IRTSubsts As -> Type) (Ds2 : @IRTSubsts As) => @Either (recl Ds2) (recr Ds2)) (fun (_1 : @IRTDesc As) (recl : @IRTSubsts As -> Type) (_2 : @IRTDesc As) (recr : @IRTSubsts As -> Type) (Ds2 : @IRTSubsts As) => prod (recl Ds2) (recr Ds2)) (fun (i : @SAWCoreScaffolding.Nat) (_1 : SAWCorePrelude.ListSort_rect (fun (_1 : @ListSort) => @SAWCoreScaffolding.Nat -> Type) (fun (_1 : @SAWCoreScaffolding.Nat) => @SAWCoreScaffolding.Eq (@SAWCoreScaffolding.Bool) (@SAWCoreScaffolding.true) (@SAWCoreScaffolding.false)) (fun (A : Type) (_1 : @ListSort) (rec1 : @SAWCoreScaffolding.Nat -> Type) => @Nat_cases Type A (fun (n : @SAWCoreScaffolding.Nat) (_2 : Type) => rec1 n)) As i -> @IRTDesc As) (recf : SAWCorePrelude.ListSort_rect (fun (_2 : @ListSort) => @SAWCoreScaffolding.Nat -> Type) (fun (_2 : @SAWCoreScaffolding.Nat) => @SAWCoreScaffolding.Eq (@SAWCoreScaffolding.Bool) (@SAWCoreScaffolding.true) (@SAWCoreScaffolding.false)) (fun (A : Type) (_2 : @ListSort) (rec1 : @SAWCoreScaffolding.Nat -> Type) => @Nat_cases Type A (fun (n : @SAWCoreScaffolding.Nat) (_3 : Type) => rec1 n)) As i -> @IRTSubsts As -> Type) (Ds2 : @IRTSubsts As) => @sigT (@listSortGet As i) (fun (a : SAWCorePrelude.ListSort_rect (fun (_2 : @ListSort) => @SAWCoreScaffolding.Nat -> Type) (fun (_2 : @SAWCoreScaffolding.Nat) => @SAWCoreScaffolding.Eq (@SAWCoreScaffolding.Bool) (@SAWCoreScaffolding.true) (@SAWCoreScaffolding.false)) (fun (A : Type) (_2 : @ListSort) (rec1 : @SAWCoreScaffolding.Nat -> Type) => @Nat_cases Type A (fun (n : @SAWCoreScaffolding.Nat) (_3 : Type) => rec1 n)) As i) => recf a Ds2)) (fun (n : @SAWCoreScaffolding.Nat) (len : @SAWCoreVectorsAsCoqVectors.Vec n (@SAWCoreScaffolding.Bool)) (_1 : @IRTDesc As) (rec1 : @IRTSubsts As -> Type) (Ds2 : @IRTSubsts As) => @BVVec n len (rec1 Ds2)) (fun (_1 : @IRTSubsts As) => unit) (fun (_1 : @IRTSubsts As) => @SAWCoreScaffolding.Eq (@SAWCoreScaffolding.Bool) (@SAWCoreScaffolding.true) (@SAWCoreScaffolding.false)) (fun (i : @SAWCoreScaffolding.Nat) (_1 : @IRTSubsts As) => @listSortGet As i) D1 (@IRTs_Cons As (@IRT_mu As D1) Ds1)) => @IRT_fold As Ds1 D1 (rec (@IRTs_Cons As (@IRT_mu As D1) Ds1) x)) (fun (Dl : @IRTDesc As) (recl : forall (Ds1 : @IRTSubsts As), SAWCorePrelude.IRTDesc_rect As (fun (_1 : @IRTDesc As) => @IRTSubsts As -> Type) (fun (i : @SAWCoreScaffolding.Nat) (Ds2 : @IRTSubsts As) => @IRT As (@dropIRTs As Ds2 (@SAWCoreScaffolding.Succ i)) (@atIRTs As Ds2 i)) (fun (D1 : @IRTDesc As) (rec : @IRTSubsts As -> Type) (Ds2 : @IRTSubsts As) => rec (@IRTs_Cons As (@IRT_mu As D1) Ds2)) (fun (_1 : @IRTDesc As) (recl : @IRTSubsts As -> Type) (_2 : @IRTDesc As) (recr : @IRTSubsts As -> Type) (Ds2 : @IRTSubsts As) => @Either (recl Ds2) (recr Ds2)) (fun (_1 : @IRTDesc As) (recl : @IRTSubsts As -> Type) (_2 : @IRTDesc As) (recr : @IRTSubsts As -> Type) (Ds2 : @IRTSubsts As) => prod (recl Ds2) (recr Ds2)) (fun (i : @SAWCoreScaffolding.Nat) (_1 : SAWCorePrelude.ListSort_rect (fun (_1 : @ListSort) => @SAWCoreScaffolding.Nat -> Type) (fun (_1 : @SAWCoreScaffolding.Nat) => @SAWCoreScaffolding.Eq (@SAWCoreScaffolding.Bool) (@SAWCoreScaffolding.true) (@SAWCoreScaffolding.false)) (fun (A : Type) (_1 : @ListSort) (rec : @SAWCoreScaffolding.Nat -> Type) => @Nat_cases Type A (fun (n : @SAWCoreScaffolding.Nat) (_2 : Type) => rec n)) As i -> @IRTDesc As) (recf : SAWCorePrelude.ListSort_rect (fun (_2 : @ListSort) => @SAWCoreScaffolding.Nat -> Type) (fun (_2 : @SAWCoreScaffolding.Nat) => @SAWCoreScaffolding.Eq (@SAWCoreScaffolding.Bool) (@SAWCoreScaffolding.true) (@SAWCoreScaffolding.false)) (fun (A : Type) (_2 : @ListSort) (rec : @SAWCoreScaffolding.Nat -> Type) => @Nat_cases Type A (fun (n : @SAWCoreScaffolding.Nat) (_3 : Type) => rec n)) As i -> @IRTSubsts As -> Type) (Ds2 : @IRTSubsts As) => @sigT (@listSortGet As i) (fun (a : SAWCorePrelude.ListSort_rect (fun (_2 : @ListSort) => @SAWCoreScaffolding.Nat -> Type) (fun (_2 : @SAWCoreScaffolding.Nat) => @SAWCoreScaffolding.Eq (@SAWCoreScaffolding.Bool) (@SAWCoreScaffolding.true) (@SAWCoreScaffolding.false)) (fun (A : Type) (_2 : @ListSort) (rec : @SAWCoreScaffolding.Nat -> Type) => @Nat_cases Type A (fun (n : @SAWCoreScaffolding.Nat) (_3 : Type) => rec n)) As i) => recf a Ds2)) (fun (n : @SAWCoreScaffolding.Nat) (len : @SAWCoreVectorsAsCoqVectors.Vec n (@SAWCoreScaffolding.Bool)) (_1 : @IRTDesc As) (rec : @IRTSubsts As -> Type) (Ds2 : @IRTSubsts As) => @BVVec n len (rec Ds2)) (fun (_1 : @IRTSubsts As) => unit) (fun (_1 : @IRTSubsts As) => @SAWCoreScaffolding.Eq (@SAWCoreScaffolding.Bool) (@SAWCoreScaffolding.true) (@SAWCoreScaffolding.false)) (fun (i : @SAWCoreScaffolding.Nat) (_1 : @IRTSubsts As) => @listSortGet As i) Dl Ds1 -> @IRT As Ds1 Dl) (Dr : @IRTDesc As) (recr : forall (Ds1 : @IRTSubsts As), SAWCorePrelude.IRTDesc_rect As (fun (_1 : @IRTDesc As) => @IRTSubsts As -> Type) (fun (i : @SAWCoreScaffolding.Nat) (Ds2 : @IRTSubsts As) => @IRT As (@dropIRTs As Ds2 (@SAWCoreScaffolding.Succ i)) (@atIRTs As Ds2 i)) (fun (D1 : @IRTDesc As) (rec : @IRTSubsts As -> Type) (Ds2 : @IRTSubsts As) => rec (@IRTs_Cons As (@IRT_mu As D1) Ds2)) (fun (_1 : @IRTDesc As) (recl1 : @IRTSubsts As -> Type) (_2 : @IRTDesc As) (recr : @IRTSubsts As -> Type) (Ds2 : @IRTSubsts As) => @Either (recl1 Ds2) (recr Ds2)) (fun (_1 : @IRTDesc As) (recl1 : @IRTSubsts As -> Type) (_2 : @IRTDesc As) (recr : @IRTSubsts As -> Type) (Ds2 : @IRTSubsts As) => prod (recl1 Ds2) (recr Ds2)) (fun (i : @SAWCoreScaffolding.Nat) (_1 : SAWCorePrelude.ListSort_rect (fun (_1 : @ListSort) => @SAWCoreScaffolding.Nat -> Type) (fun (_1 : @SAWCoreScaffolding.Nat) => @SAWCoreScaffolding.Eq (@SAWCoreScaffolding.Bool) (@SAWCoreScaffolding.true) (@SAWCoreScaffolding.false)) (fun (A : Type) (_1 : @ListSort) (rec : @SAWCoreScaffolding.Nat -> Type) => @Nat_cases Type A (fun (n : @SAWCoreScaffolding.Nat) (_2 : Type) => rec n)) As i -> @IRTDesc As) (recf : SAWCorePrelude.ListSort_rect (fun (_2 : @ListSort) => @SAWCoreScaffolding.Nat -> Type) (fun (_2 : @SAWCoreScaffolding.Nat) => @SAWCoreScaffolding.Eq (@SAWCoreScaffolding.Bool) (@SAWCoreScaffolding.true) (@SAWCoreScaffolding.false)) (fun (A : Type) (_2 : @ListSort) (rec : @SAWCoreScaffolding.Nat -> Type) => @Nat_cases Type A (fun (n : @SAWCoreScaffolding.Nat) (_3 : Type) => rec n)) As i -> @IRTSubsts As -> Type) (Ds2 : @IRTSubsts As) => @sigT (@listSortGet As i) (fun (a : SAWCorePrelude.ListSort_rect (fun (_2 : @ListSort) => @SAWCoreScaffolding.Nat -> Type) (fun (_2 : @SAWCoreScaffolding.Nat) => @SAWCoreScaffolding.Eq (@SAWCoreScaffolding.Bool) (@SAWCoreScaffolding.true) (@SAWCoreScaffolding.false)) (fun (A : Type) (_2 : @ListSort) (rec : @SAWCoreScaffolding.Nat -> Type) => @Nat_cases Type A (fun (n : @SAWCoreScaffolding.Nat) (_3 : Type) => rec n)) As i) => recf a Ds2)) (fun (n : @SAWCoreScaffolding.Nat) (len : @SAWCoreVectorsAsCoqVectors.Vec n (@SAWCoreScaffolding.Bool)) (_1 : @IRTDesc As) (rec : @IRTSubsts As -> Type) (Ds2 : @IRTSubsts As) => @BVVec n len (rec Ds2)) (fun (_1 : @IRTSubsts As) => unit) (fun (_1 : @IRTSubsts As) => @SAWCoreScaffolding.Eq (@SAWCoreScaffolding.Bool) (@SAWCoreScaffolding.true) (@SAWCoreScaffolding.false)) (fun (i : @SAWCoreScaffolding.Nat) (_1 : @IRTSubsts As) => @listSortGet As i) Dr Ds1 -> @IRT As Ds1 Dr) (Ds1 : @IRTSubsts As) (x : @Either (SAWCorePrelude.IRTDesc_rect As (fun (_1 : @IRTDesc As) => @IRTSubsts As -> Type) (fun (i : @SAWCoreScaffolding.Nat) (Ds2 : @IRTSubsts As) => @IRT As (@dropIRTs As Ds2 (@SAWCoreScaffolding.Succ i)) (@atIRTs As Ds2 i)) (fun (D1 : @IRTDesc As) (rec : @IRTSubsts As -> Type) (Ds2 : @IRTSubsts As) => rec (@IRTs_Cons As (@IRT_mu As D1) Ds2)) (fun (_1 : @IRTDesc As) (recl1 : @IRTSubsts As -> Type) (_2 : @IRTDesc As) (recr1 : @IRTSubsts As -> Type) (Ds2 : @IRTSubsts As) => @Either (recl1 Ds2) (recr1 Ds2)) (fun (_1 : @IRTDesc As) (recl1 : @IRTSubsts As -> Type) (_2 : @IRTDesc As) (recr1 : @IRTSubsts As -> Type) (Ds2 : @IRTSubsts As) => prod (recl1 Ds2) (recr1 Ds2)) (fun (i : @SAWCoreScaffolding.Nat) (_1 : SAWCorePrelude.ListSort_rect (fun (_1 : @ListSort) => @SAWCoreScaffolding.Nat -> Type) (fun (_1 : @SAWCoreScaffolding.Nat) => @SAWCoreScaffolding.Eq (@SAWCoreScaffolding.Bool) (@SAWCoreScaffolding.true) (@SAWCoreScaffolding.false)) (fun (A : Type) (_1 : @ListSort) (rec : @SAWCoreScaffolding.Nat -> Type) => @Nat_cases Type A (fun (n : @SAWCoreScaffolding.Nat) (_2 : Type) => rec n)) As i -> @IRTDesc As) (recf : SAWCorePrelude.ListSort_rect (fun (_2 : @ListSort) => @SAWCoreScaffolding.Nat -> Type) (fun (_2 : @SAWCoreScaffolding.Nat) => @SAWCoreScaffolding.Eq (@SAWCoreScaffolding.Bool) (@SAWCoreScaffolding.true) (@SAWCoreScaffolding.false)) (fun (A : Type) (_2 : @ListSort) (rec : @SAWCoreScaffolding.Nat -> Type) => @Nat_cases Type A (fun (n : @SAWCoreScaffolding.Nat) (_3 : Type) => rec n)) As i -> @IRTSubsts As -> Type) (Ds2 : @IRTSubsts As) => @sigT (@listSortGet As i) (fun (a : SAWCorePrelude.ListSort_rect (fun (_2 : @ListSort) => @SAWCoreScaffolding.Nat -> Type) (fun (_2 : @SAWCoreScaffolding.Nat) => @SAWCoreScaffolding.Eq (@SAWCoreScaffolding.Bool) (@SAWCoreScaffolding.true) (@SAWCoreScaffolding.false)) (fun (A : Type) (_2 : @ListSort) (rec : @SAWCoreScaffolding.Nat -> Type) => @Nat_cases Type A (fun (n : @SAWCoreScaffolding.Nat) (_3 : Type) => rec n)) As i) => recf a Ds2)) (fun (n : @SAWCoreScaffolding.Nat) (len : @SAWCoreVectorsAsCoqVectors.Vec n (@SAWCoreScaffolding.Bool)) (_1 : @IRTDesc As) (rec : @IRTSubsts As -> Type) (Ds2 : @IRTSubsts As) => @BVVec n len (rec Ds2)) (fun (_1 : @IRTSubsts As) => unit) (fun (_1 : @IRTSubsts As) => @SAWCoreScaffolding.Eq (@SAWCoreScaffolding.Bool) (@SAWCoreScaffolding.true) (@SAWCoreScaffolding.false)) (fun (i : @SAWCoreScaffolding.Nat) (_1 : @IRTSubsts As) => @listSortGet As i) Dl Ds1) (SAWCorePrelude.IRTDesc_rect As (fun (_1 : @IRTDesc As) => @IRTSubsts As -> Type) (fun (i : @SAWCoreScaffolding.Nat) (Ds2 : @IRTSubsts As) => @IRT As (@dropIRTs As Ds2 (@SAWCoreScaffolding.Succ i)) (@atIRTs As Ds2 i)) (fun (D1 : @IRTDesc As) (rec : @IRTSubsts As -> Type) (Ds2 : @IRTSubsts As) => rec (@IRTs_Cons As (@IRT_mu As D1) Ds2)) (fun (_1 : @IRTDesc As) (recl1 : @IRTSubsts As -> Type) (_2 : @IRTDesc As) (recr1 : @IRTSubsts As -> Type) (Ds2 : @IRTSubsts As) => @Either (recl1 Ds2) (recr1 Ds2)) (fun (_1 : @IRTDesc As) (recl1 : @IRTSubsts As -> Type) (_2 : @IRTDesc As) (recr1 : @IRTSubsts As -> Type) (Ds2 : @IRTSubsts As) => prod (recl1 Ds2) (recr1 Ds2)) (fun (i : @SAWCoreScaffolding.Nat) (_1 : SAWCorePrelude.ListSort_rect (fun (_1 : @ListSort) => @SAWCoreScaffolding.Nat -> Type) (fun (_1 : @SAWCoreScaffolding.Nat) => @SAWCoreScaffolding.Eq (@SAWCoreScaffolding.Bool) (@SAWCoreScaffolding.true) (@SAWCoreScaffolding.false)) (fun (A : Type) (_1 : @ListSort) (rec : @SAWCoreScaffolding.Nat -> Type) => @Nat_cases Type A (fun (n : @SAWCoreScaffolding.Nat) (_2 : Type) => rec n)) As i -> @IRTDesc As) (recf : SAWCorePrelude.ListSort_rect (fun (_2 : @ListSort) => @SAWCoreScaffolding.Nat -> Type) (fun (_2 : @SAWCoreScaffolding.Nat) => @SAWCoreScaffolding.Eq (@SAWCoreScaffolding.Bool) (@SAWCoreScaffolding.true) (@SAWCoreScaffolding.false)) (fun (A : Type) (_2 : @ListSort) (rec : @SAWCoreScaffolding.Nat -> Type) => @Nat_cases Type A (fun (n : @SAWCoreScaffolding.Nat) (_3 : Type) => rec n)) As i -> @IRTSubsts As -> Type) (Ds2 : @IRTSubsts As) => @sigT (@listSortGet As i) (fun (a : SAWCorePrelude.ListSort_rect (fun (_2 : @ListSort) => @SAWCoreScaffolding.Nat -> Type) (fun (_2 : @SAWCoreScaffolding.Nat) => @SAWCoreScaffolding.Eq (@SAWCoreScaffolding.Bool) (@SAWCoreScaffolding.true) (@SAWCoreScaffolding.false)) (fun (A : Type) (_2 : @ListSort) (rec : @SAWCoreScaffolding.Nat -> Type) => @Nat_cases Type A (fun (n : @SAWCoreScaffolding.Nat) (_3 : Type) => rec n)) As i) => recf a Ds2)) (fun (n : @SAWCoreScaffolding.Nat) (len : @SAWCoreVectorsAsCoqVectors.Vec n (@SAWCoreScaffolding.Bool)) (_1 : @IRTDesc As) (rec : @IRTSubsts As -> Type) (Ds2 : @IRTSubsts As) => @BVVec n len (rec Ds2)) (fun (_1 : @IRTSubsts As) => unit) (fun (_1 : @IRTSubsts As) => @SAWCoreScaffolding.Eq (@SAWCoreScaffolding.Bool) (@SAWCoreScaffolding.true) (@SAWCoreScaffolding.false)) (fun (i : @SAWCoreScaffolding.Nat) (_1 : @IRTSubsts As) => @listSortGet As i) Dr Ds1)) => @either (@UnfoldedIRT As Ds1 Dl) (@UnfoldedIRT As Ds1 Dr) (@IRT As Ds1 (@IRT_Either As Dl Dr)) (fun (xl : SAWCorePrelude.IRTDesc_rect As (fun (_1 : @IRTDesc As) => @IRTSubsts As -> Type) (fun (i : @SAWCoreScaffolding.Nat) (Ds2 : @IRTSubsts As) => @IRT As (@dropIRTs As Ds2 (@SAWCoreScaffolding.Succ i)) (@atIRTs As Ds2 i)) (fun (D1 : @IRTDesc As) (rec : @IRTSubsts As -> Type) (Ds2 : @IRTSubsts As) => rec (@IRTs_Cons As (@IRT_mu As D1) Ds2)) (fun (_1 : @IRTDesc As) (recl1 : @IRTSubsts As -> Type) (_2 : @IRTDesc As) (recr1 : @IRTSubsts As -> Type) (Ds2 : @IRTSubsts As) => @Either (recl1 Ds2) (recr1 Ds2)) (fun (_1 : @IRTDesc As) (recl1 : @IRTSubsts As -> Type) (_2 : @IRTDesc As) (recr1 : @IRTSubsts As -> Type) (Ds2 : @IRTSubsts As) => prod (recl1 Ds2) (recr1 Ds2)) (fun (i : @SAWCoreScaffolding.Nat) (_1 : SAWCorePrelude.ListSort_rect (fun (_1 : @ListSort) => @SAWCoreScaffolding.Nat -> Type) (fun (_1 : @SAWCoreScaffolding.Nat) => @SAWCoreScaffolding.Eq (@SAWCoreScaffolding.Bool) (@SAWCoreScaffolding.true) (@SAWCoreScaffolding.false)) (fun (A : Type) (_1 : @ListSort) (rec : @SAWCoreScaffolding.Nat -> Type) => @Nat_cases Type A (fun (n : @SAWCoreScaffolding.Nat) (_2 : Type) => rec n)) As i -> @IRTDesc As) (recf : SAWCorePrelude.ListSort_rect (fun (_2 : @ListSort) => @SAWCoreScaffolding.Nat -> Type) (fun (_2 : @SAWCoreScaffolding.Nat) => @SAWCoreScaffolding.Eq (@SAWCoreScaffolding.Bool) (@SAWCoreScaffolding.true) (@SAWCoreScaffolding.false)) (fun (A : Type) (_2 : @ListSort) (rec : @SAWCoreScaffolding.Nat -> Type) => @Nat_cases Type A (fun (n : @SAWCoreScaffolding.Nat) (_3 : Type) => rec n)) As i -> @IRTSubsts As -> Type) (Ds2 : @IRTSubsts As) => @sigT (@listSortGet As i) (fun (a : SAWCorePrelude.ListSort_rect (fun (_2 : @ListSort) => @SAWCoreScaffolding.Nat -> Type) (fun (_2 : @SAWCoreScaffolding.Nat) => @SAWCoreScaffolding.Eq (@SAWCoreScaffolding.Bool) (@SAWCoreScaffolding.true) (@SAWCoreScaffolding.false)) (fun (A : Type) (_2 : @ListSort) (rec : @SAWCoreScaffolding.Nat -> Type) => @Nat_cases Type A (fun (n : @SAWCoreScaffolding.Nat) (_3 : Type) => rec n)) As i) => recf a Ds2)) (fun (n : @SAWCoreScaffolding.Nat) (len : @SAWCoreVectorsAsCoqVectors.Vec n (@SAWCoreScaffolding.Bool)) (_1 : @IRTDesc As) (rec : @IRTSubsts As -> Type) (Ds2 : @IRTSubsts As) => @BVVec n len (rec Ds2)) (fun (_1 : @IRTSubsts As) => unit) (fun (_1 : @IRTSubsts As) => @SAWCoreScaffolding.Eq (@SAWCoreScaffolding.Bool) (@SAWCoreScaffolding.true) (@SAWCoreScaffolding.false)) (fun (i : @SAWCoreScaffolding.Nat) (_1 : @IRTSubsts As) => @listSortGet As i) Dl Ds1) => @IRT_Left As Ds1 Dl Dr (recl Ds1 xl)) (fun (xr : SAWCorePrelude.IRTDesc_rect As (fun (_1 : @IRTDesc As) => @IRTSubsts As -> Type) (fun (i : @SAWCoreScaffolding.Nat) (Ds2 : @IRTSubsts As) => @IRT As (@dropIRTs As Ds2 (@SAWCoreScaffolding.Succ i)) (@atIRTs As Ds2 i)) (fun (D1 : @IRTDesc As) (rec : @IRTSubsts As -> Type) (Ds2 : @IRTSubsts As) => rec (@IRTs_Cons As (@IRT_mu As D1) Ds2)) (fun (_1 : @IRTDesc As) (recl1 : @IRTSubsts As -> Type) (_2 : @IRTDesc As) (recr1 : @IRTSubsts As -> Type) (Ds2 : @IRTSubsts As) => @Either (recl1 Ds2) (recr1 Ds2)) (fun (_1 : @IRTDesc As) (recl1 : @IRTSubsts As -> Type) (_2 : @IRTDesc As) (recr1 : @IRTSubsts As -> Type) (Ds2 : @IRTSubsts As) => prod (recl1 Ds2) (recr1 Ds2)) (fun (i : @SAWCoreScaffolding.Nat) (_1 : SAWCorePrelude.ListSort_rect (fun (_1 : @ListSort) => @SAWCoreScaffolding.Nat -> Type) (fun (_1 : @SAWCoreScaffolding.Nat) => @SAWCoreScaffolding.Eq (@SAWCoreScaffolding.Bool) (@SAWCoreScaffolding.true) (@SAWCoreScaffolding.false)) (fun (A : Type) (_1 : @ListSort) (rec : @SAWCoreScaffolding.Nat -> Type) => @Nat_cases Type A (fun (n : @SAWCoreScaffolding.Nat) (_2 : Type) => rec n)) As i -> @IRTDesc As) (recf : SAWCorePrelude.ListSort_rect (fun (_2 : @ListSort) => @SAWCoreScaffolding.Nat -> Type) (fun (_2 : @SAWCoreScaffolding.Nat) => @SAWCoreScaffolding.Eq (@SAWCoreScaffolding.Bool) (@SAWCoreScaffolding.true) (@SAWCoreScaffolding.false)) (fun (A : Type) (_2 : @ListSort) (rec : @SAWCoreScaffolding.Nat -> Type) => @Nat_cases Type A (fun (n : @SAWCoreScaffolding.Nat) (_3 : Type) => rec n)) As i -> @IRTSubsts As -> Type) (Ds2 : @IRTSubsts As) => @sigT (@listSortGet As i) (fun (a : SAWCorePrelude.ListSort_rect (fun (_2 : @ListSort) => @SAWCoreScaffolding.Nat -> Type) (fun (_2 : @SAWCoreScaffolding.Nat) => @SAWCoreScaffolding.Eq (@SAWCoreScaffolding.Bool) (@SAWCoreScaffolding.true) (@SAWCoreScaffolding.false)) (fun (A : Type) (_2 : @ListSort) (rec : @SAWCoreScaffolding.Nat -> Type) => @Nat_cases Type A (fun (n : @SAWCoreScaffolding.Nat) (_3 : Type) => rec n)) As i) => recf a Ds2)) (fun (n : @SAWCoreScaffolding.Nat) (len : @SAWCoreVectorsAsCoqVectors.Vec n (@SAWCoreScaffolding.Bool)) (_1 : @IRTDesc As) (rec : @IRTSubsts As -> Type) (Ds2 : @IRTSubsts As) => @BVVec n len (rec Ds2)) (fun (_1 : @IRTSubsts As) => unit) (fun (_1 : @IRTSubsts As) => @SAWCoreScaffolding.Eq (@SAWCoreScaffolding.Bool) (@SAWCoreScaffolding.true) (@SAWCoreScaffolding.false)) (fun (i : @SAWCoreScaffolding.Nat) (_1 : @IRTSubsts As) => @listSortGet As i) Dr Ds1) => @IRT_Right As Ds1 Dl Dr (recr Ds1 xr)) x) (fun (Dl : @IRTDesc As) (recl : forall (Ds1 : @IRTSubsts As), SAWCorePrelude.IRTDesc_rect As (fun (_1 : @IRTDesc As) => @IRTSubsts As -> Type) (fun (i : @SAWCoreScaffolding.Nat) (Ds2 : @IRTSubsts As) => @IRT As (@dropIRTs As Ds2 (@SAWCoreScaffolding.Succ i)) (@atIRTs As Ds2 i)) (fun (D1 : @IRTDesc As) (rec : @IRTSubsts As -> Type) (Ds2 : @IRTSubsts As) => rec (@IRTs_Cons As (@IRT_mu As D1) Ds2)) (fun (_1 : @IRTDesc As) (recl : @IRTSubsts As -> Type) (_2 : @IRTDesc As) (recr : @IRTSubsts As -> Type) (Ds2 : @IRTSubsts As) => @Either (recl Ds2) (recr Ds2)) (fun (_1 : @IRTDesc As) (recl : @IRTSubsts As -> Type) (_2 : @IRTDesc As) (recr : @IRTSubsts As -> Type) (Ds2 : @IRTSubsts As) => prod (recl Ds2) (recr Ds2)) (fun (i : @SAWCoreScaffolding.Nat) (_1 : SAWCorePrelude.ListSort_rect (fun (_1 : @ListSort) => @SAWCoreScaffolding.Nat -> Type) (fun (_1 : @SAWCoreScaffolding.Nat) => @SAWCoreScaffolding.Eq (@SAWCoreScaffolding.Bool) (@SAWCoreScaffolding.true) (@SAWCoreScaffolding.false)) (fun (A : Type) (_1 : @ListSort) (rec : @SAWCoreScaffolding.Nat -> Type) => @Nat_cases Type A (fun (n : @SAWCoreScaffolding.Nat) (_2 : Type) => rec n)) As i -> @IRTDesc As) (recf : SAWCorePrelude.ListSort_rect (fun (_2 : @ListSort) => @SAWCoreScaffolding.Nat -> Type) (fun (_2 : @SAWCoreScaffolding.Nat) => @SAWCoreScaffolding.Eq (@SAWCoreScaffolding.Bool) (@SAWCoreScaffolding.true) (@SAWCoreScaffolding.false)) (fun (A : Type) (_2 : @ListSort) (rec : @SAWCoreScaffolding.Nat -> Type) => @Nat_cases Type A (fun (n : @SAWCoreScaffolding.Nat) (_3 : Type) => rec n)) As i -> @IRTSubsts As -> Type) (Ds2 : @IRTSubsts As) => @sigT (@listSortGet As i) (fun (a : SAWCorePrelude.ListSort_rect (fun (_2 : @ListSort) => @SAWCoreScaffolding.Nat -> Type) (fun (_2 : @SAWCoreScaffolding.Nat) => @SAWCoreScaffolding.Eq (@SAWCoreScaffolding.Bool) (@SAWCoreScaffolding.true) (@SAWCoreScaffolding.false)) (fun (A : Type) (_2 : @ListSort) (rec : @SAWCoreScaffolding.Nat -> Type) => @Nat_cases Type A (fun (n : @SAWCoreScaffolding.Nat) (_3 : Type) => rec n)) As i) => recf a Ds2)) (fun (n : @SAWCoreScaffolding.Nat) (len : @SAWCoreVectorsAsCoqVectors.Vec n (@SAWCoreScaffolding.Bool)) (_1 : @IRTDesc As) (rec : @IRTSubsts As -> Type) (Ds2 : @IRTSubsts As) => @BVVec n len (rec Ds2)) (fun (_1 : @IRTSubsts As) => unit) (fun (_1 : @IRTSubsts As) => @SAWCoreScaffolding.Eq (@SAWCoreScaffolding.Bool) (@SAWCoreScaffolding.true) (@SAWCoreScaffolding.false)) (fun (i : @SAWCoreScaffolding.Nat) (_1 : @IRTSubsts As) => @listSortGet As i) Dl Ds1 -> @IRT As Ds1 Dl) (Dr : @IRTDesc As) (recr : forall (Ds1 : @IRTSubsts As), SAWCorePrelude.IRTDesc_rect As (fun (_1 : @IRTDesc As) => @IRTSubsts As -> Type) (fun (i : @SAWCoreScaffolding.Nat) (Ds2 : @IRTSubsts As) => @IRT As (@dropIRTs As Ds2 (@SAWCoreScaffolding.Succ i)) (@atIRTs As Ds2 i)) (fun (D1 : @IRTDesc As) (rec : @IRTSubsts As -> Type) (Ds2 : @IRTSubsts As) => rec (@IRTs_Cons As (@IRT_mu As D1) Ds2)) (fun (_1 : @IRTDesc As) (recl1 : @IRTSubsts As -> Type) (_2 : @IRTDesc As) (recr : @IRTSubsts As -> Type) (Ds2 : @IRTSubsts As) => @Either (recl1 Ds2) (recr Ds2)) (fun (_1 : @IRTDesc As) (recl1 : @IRTSubsts As -> Type) (_2 : @IRTDesc As) (recr : @IRTSubsts As -> Type) (Ds2 : @IRTSubsts As) => prod (recl1 Ds2) (recr Ds2)) (fun (i : @SAWCoreScaffolding.Nat) (_1 : SAWCorePrelude.ListSort_rect (fun (_1 : @ListSort) => @SAWCoreScaffolding.Nat -> Type) (fun (_1 : @SAWCoreScaffolding.Nat) => @SAWCoreScaffolding.Eq (@SAWCoreScaffolding.Bool) (@SAWCoreScaffolding.true) (@SAWCoreScaffolding.false)) (fun (A : Type) (_1 : @ListSort) (rec : @SAWCoreScaffolding.Nat -> Type) => @Nat_cases Type A (fun (n : @SAWCoreScaffolding.Nat) (_2 : Type) => rec n)) As i -> @IRTDesc As) (recf : SAWCorePrelude.ListSort_rect (fun (_2 : @ListSort) => @SAWCoreScaffolding.Nat -> Type) (fun (_2 : @SAWCoreScaffolding.Nat) => @SAWCoreScaffolding.Eq (@SAWCoreScaffolding.Bool) (@SAWCoreScaffolding.true) (@SAWCoreScaffolding.false)) (fun (A : Type) (_2 : @ListSort) (rec : @SAWCoreScaffolding.Nat -> Type) => @Nat_cases Type A (fun (n : @SAWCoreScaffolding.Nat) (_3 : Type) => rec n)) As i -> @IRTSubsts As -> Type) (Ds2 : @IRTSubsts As) => @sigT (@listSortGet As i) (fun (a : SAWCorePrelude.ListSort_rect (fun (_2 : @ListSort) => @SAWCoreScaffolding.Nat -> Type) (fun (_2 : @SAWCoreScaffolding.Nat) => @SAWCoreScaffolding.Eq (@SAWCoreScaffolding.Bool) (@SAWCoreScaffolding.true) (@SAWCoreScaffolding.false)) (fun (A : Type) (_2 : @ListSort) (rec : @SAWCoreScaffolding.Nat -> Type) => @Nat_cases Type A (fun (n : @SAWCoreScaffolding.Nat) (_3 : Type) => rec n)) As i) => recf a Ds2)) (fun (n : @SAWCoreScaffolding.Nat) (len : @SAWCoreVectorsAsCoqVectors.Vec n (@SAWCoreScaffolding.Bool)) (_1 : @IRTDesc As) (rec : @IRTSubsts As -> Type) (Ds2 : @IRTSubsts As) => @BVVec n len (rec Ds2)) (fun (_1 : @IRTSubsts As) => unit) (fun (_1 : @IRTSubsts As) => @SAWCoreScaffolding.Eq (@SAWCoreScaffolding.Bool) (@SAWCoreScaffolding.true) (@SAWCoreScaffolding.false)) (fun (i : @SAWCoreScaffolding.Nat) (_1 : @IRTSubsts As) => @listSortGet As i) Dr Ds1 -> @IRT As Ds1 Dr) (Ds1 : @IRTSubsts As) (x : prod (SAWCorePrelude.IRTDesc_rect As (fun (_1 : @IRTDesc As) => @IRTSubsts As -> Type) (fun (i : @SAWCoreScaffolding.Nat) (Ds2 : @IRTSubsts As) => @IRT As (@dropIRTs As Ds2 (@SAWCoreScaffolding.Succ i)) (@atIRTs As Ds2 i)) (fun (D1 : @IRTDesc As) (rec : @IRTSubsts As -> Type) (Ds2 : @IRTSubsts As) => rec (@IRTs_Cons As (@IRT_mu As D1) Ds2)) (fun (_1 : @IRTDesc As) (recl1 : @IRTSubsts As -> Type) (_2 : @IRTDesc As) (recr1 : @IRTSubsts As -> Type) (Ds2 : @IRTSubsts As) => @Either (recl1 Ds2) (recr1 Ds2)) (fun (_1 : @IRTDesc As) (recl1 : @IRTSubsts As -> Type) (_2 : @IRTDesc As) (recr1 : @IRTSubsts As -> Type) (Ds2 : @IRTSubsts As) => prod (recl1 Ds2) (recr1 Ds2)) (fun (i : @SAWCoreScaffolding.Nat) (_1 : SAWCorePrelude.ListSort_rect (fun (_1 : @ListSort) => @SAWCoreScaffolding.Nat -> Type) (fun (_1 : @SAWCoreScaffolding.Nat) => @SAWCoreScaffolding.Eq (@SAWCoreScaffolding.Bool) (@SAWCoreScaffolding.true) (@SAWCoreScaffolding.false)) (fun (A : Type) (_1 : @ListSort) (rec : @SAWCoreScaffolding.Nat -> Type) => @Nat_cases Type A (fun (n : @SAWCoreScaffolding.Nat) (_2 : Type) => rec n)) As i -> @IRTDesc As) (recf : SAWCorePrelude.ListSort_rect (fun (_2 : @ListSort) => @SAWCoreScaffolding.Nat -> Type) (fun (_2 : @SAWCoreScaffolding.Nat) => @SAWCoreScaffolding.Eq (@SAWCoreScaffolding.Bool) (@SAWCoreScaffolding.true) (@SAWCoreScaffolding.false)) (fun (A : Type) (_2 : @ListSort) (rec : @SAWCoreScaffolding.Nat -> Type) => @Nat_cases Type A (fun (n : @SAWCoreScaffolding.Nat) (_3 : Type) => rec n)) As i -> @IRTSubsts As -> Type) (Ds2 : @IRTSubsts As) => @sigT (@listSortGet As i) (fun (a : SAWCorePrelude.ListSort_rect (fun (_2 : @ListSort) => @SAWCoreScaffolding.Nat -> Type) (fun (_2 : @SAWCoreScaffolding.Nat) => @SAWCoreScaffolding.Eq (@SAWCoreScaffolding.Bool) (@SAWCoreScaffolding.true) (@SAWCoreScaffolding.false)) (fun (A : Type) (_2 : @ListSort) (rec : @SAWCoreScaffolding.Nat -> Type) => @Nat_cases Type A (fun (n : @SAWCoreScaffolding.Nat) (_3 : Type) => rec n)) As i) => recf a Ds2)) (fun (n : @SAWCoreScaffolding.Nat) (len : @SAWCoreVectorsAsCoqVectors.Vec n (@SAWCoreScaffolding.Bool)) (_1 : @IRTDesc As) (rec : @IRTSubsts As -> Type) (Ds2 : @IRTSubsts As) => @BVVec n len (rec Ds2)) (fun (_1 : @IRTSubsts As) => unit) (fun (_1 : @IRTSubsts As) => @SAWCoreScaffolding.Eq (@SAWCoreScaffolding.Bool) (@SAWCoreScaffolding.true) (@SAWCoreScaffolding.false)) (fun (i : @SAWCoreScaffolding.Nat) (_1 : @IRTSubsts As) => @listSortGet As i) Dl Ds1) (SAWCorePrelude.IRTDesc_rect As (fun (_1 : @IRTDesc As) => @IRTSubsts As -> Type) (fun (i : @SAWCoreScaffolding.Nat) (Ds2 : @IRTSubsts As) => @IRT As (@dropIRTs As Ds2 (@SAWCoreScaffolding.Succ i)) (@atIRTs As Ds2 i)) (fun (D1 : @IRTDesc As) (rec : @IRTSubsts As -> Type) (Ds2 : @IRTSubsts As) => rec (@IRTs_Cons As (@IRT_mu As D1) Ds2)) (fun (_1 : @IRTDesc As) (recl1 : @IRTSubsts As -> Type) (_2 : @IRTDesc As) (recr1 : @IRTSubsts As -> Type) (Ds2 : @IRTSubsts As) => @Either (recl1 Ds2) (recr1 Ds2)) (fun (_1 : @IRTDesc As) (recl1 : @IRTSubsts As -> Type) (_2 : @IRTDesc As) (recr1 : @IRTSubsts As -> Type) (Ds2 : @IRTSubsts As) => prod (recl1 Ds2) (recr1 Ds2)) (fun (i : @SAWCoreScaffolding.Nat) (_1 : SAWCorePrelude.ListSort_rect (fun (_1 : @ListSort) => @SAWCoreScaffolding.Nat -> Type) (fun (_1 : @SAWCoreScaffolding.Nat) => @SAWCoreScaffolding.Eq (@SAWCoreScaffolding.Bool) (@SAWCoreScaffolding.true) (@SAWCoreScaffolding.false)) (fun (A : Type) (_1 : @ListSort) (rec : @SAWCoreScaffolding.Nat -> Type) => @Nat_cases Type A (fun (n : @SAWCoreScaffolding.Nat) (_2 : Type) => rec n)) As i -> @IRTDesc As) (recf : SAWCorePrelude.ListSort_rect (fun (_2 : @ListSort) => @SAWCoreScaffolding.Nat -> Type) (fun (_2 : @SAWCoreScaffolding.Nat) => @SAWCoreScaffolding.Eq (@SAWCoreScaffolding.Bool) (@SAWCoreScaffolding.true) (@SAWCoreScaffolding.false)) (fun (A : Type) (_2 : @ListSort) (rec : @SAWCoreScaffolding.Nat -> Type) => @Nat_cases Type A (fun (n : @SAWCoreScaffolding.Nat) (_3 : Type) => rec n)) As i -> @IRTSubsts As -> Type) (Ds2 : @IRTSubsts As) => @sigT (@listSortGet As i) (fun (a : SAWCorePrelude.ListSort_rect (fun (_2 : @ListSort) => @SAWCoreScaffolding.Nat -> Type) (fun (_2 : @SAWCoreScaffolding.Nat) => @SAWCoreScaffolding.Eq (@SAWCoreScaffolding.Bool) (@SAWCoreScaffolding.true) (@SAWCoreScaffolding.false)) (fun (A : Type) (_2 : @ListSort) (rec : @SAWCoreScaffolding.Nat -> Type) => @Nat_cases Type A (fun (n : @SAWCoreScaffolding.Nat) (_3 : Type) => rec n)) As i) => recf a Ds2)) (fun (n : @SAWCoreScaffolding.Nat) (len : @SAWCoreVectorsAsCoqVectors.Vec n (@SAWCoreScaffolding.Bool)) (_1 : @IRTDesc As) (rec : @IRTSubsts As -> Type) (Ds2 : @IRTSubsts As) => @BVVec n len (rec Ds2)) (fun (_1 : @IRTSubsts As) => unit) (fun (_1 : @IRTSubsts As) => @SAWCoreScaffolding.Eq (@SAWCoreScaffolding.Bool) (@SAWCoreScaffolding.true) (@SAWCoreScaffolding.false)) (fun (i : @SAWCoreScaffolding.Nat) (_1 : @IRTSubsts As) => @listSortGet As i) Dr Ds1)) => @uncurry (@UnfoldedIRT As Ds1 Dl) (@UnfoldedIRT As Ds1 Dr) (@IRT As Ds1 (@IRT_prod As Dl Dr)) (fun (xl : SAWCorePrelude.IRTDesc_rect As (fun (_1 : @IRTDesc As) => @IRTSubsts As -> Type) (fun (i : @SAWCoreScaffolding.Nat) (Ds2 : @IRTSubsts As) => @IRT As (@dropIRTs As Ds2 (@SAWCoreScaffolding.Succ i)) (@atIRTs As Ds2 i)) (fun (D1 : @IRTDesc As) (rec : @IRTSubsts As -> Type) (Ds2 : @IRTSubsts As) => rec (@IRTs_Cons As (@IRT_mu As D1) Ds2)) (fun (_1 : @IRTDesc As) (recl1 : @IRTSubsts As -> Type) (_2 : @IRTDesc As) (recr1 : @IRTSubsts As -> Type) (Ds2 : @IRTSubsts As) => @Either (recl1 Ds2) (recr1 Ds2)) (fun (_1 : @IRTDesc As) (recl1 : @IRTSubsts As -> Type) (_2 : @IRTDesc As) (recr1 : @IRTSubsts As -> Type) (Ds2 : @IRTSubsts As) => prod (recl1 Ds2) (recr1 Ds2)) (fun (i : @SAWCoreScaffolding.Nat) (_1 : SAWCorePrelude.ListSort_rect (fun (_1 : @ListSort) => @SAWCoreScaffolding.Nat -> Type) (fun (_1 : @SAWCoreScaffolding.Nat) => @SAWCoreScaffolding.Eq (@SAWCoreScaffolding.Bool) (@SAWCoreScaffolding.true) (@SAWCoreScaffolding.false)) (fun (A : Type) (_1 : @ListSort) (rec : @SAWCoreScaffolding.Nat -> Type) => @Nat_cases Type A (fun (n : @SAWCoreScaffolding.Nat) (_2 : Type) => rec n)) As i -> @IRTDesc As) (recf : SAWCorePrelude.ListSort_rect (fun (_2 : @ListSort) => @SAWCoreScaffolding.Nat -> Type) (fun (_2 : @SAWCoreScaffolding.Nat) => @SAWCoreScaffolding.Eq (@SAWCoreScaffolding.Bool) (@SAWCoreScaffolding.true) (@SAWCoreScaffolding.false)) (fun (A : Type) (_2 : @ListSort) (rec : @SAWCoreScaffolding.Nat -> Type) => @Nat_cases Type A (fun (n : @SAWCoreScaffolding.Nat) (_3 : Type) => rec n)) As i -> @IRTSubsts As -> Type) (Ds2 : @IRTSubsts As) => @sigT (@listSortGet As i) (fun (a : SAWCorePrelude.ListSort_rect (fun (_2 : @ListSort) => @SAWCoreScaffolding.Nat -> Type) (fun (_2 : @SAWCoreScaffolding.Nat) => @SAWCoreScaffolding.Eq (@SAWCoreScaffolding.Bool) (@SAWCoreScaffolding.true) (@SAWCoreScaffolding.false)) (fun (A : Type) (_2 : @ListSort) (rec : @SAWCoreScaffolding.Nat -> Type) => @Nat_cases Type A (fun (n : @SAWCoreScaffolding.Nat) (_3 : Type) => rec n)) As i) => recf a Ds2)) (fun (n : @SAWCoreScaffolding.Nat) (len : @SAWCoreVectorsAsCoqVectors.Vec n (@SAWCoreScaffolding.Bool)) (_1 : @IRTDesc As) (rec : @IRTSubsts As -> Type) (Ds2 : @IRTSubsts As) => @BVVec n len (rec Ds2)) (fun (_1 : @IRTSubsts As) => unit) (fun (_1 : @IRTSubsts As) => @SAWCoreScaffolding.Eq (@SAWCoreScaffolding.Bool) (@SAWCoreScaffolding.true) (@SAWCoreScaffolding.false)) (fun (i : @SAWCoreScaffolding.Nat) (_1 : @IRTSubsts As) => @listSortGet As i) Dl Ds1) (xr : SAWCorePrelude.IRTDesc_rect As (fun (_1 : @IRTDesc As) => @IRTSubsts As -> Type) (fun (i : @SAWCoreScaffolding.Nat) (Ds2 : @IRTSubsts As) => @IRT As (@dropIRTs As Ds2 (@SAWCoreScaffolding.Succ i)) (@atIRTs As Ds2 i)) (fun (D1 : @IRTDesc As) (rec : @IRTSubsts As -> Type) (Ds2 : @IRTSubsts As) => rec (@IRTs_Cons As (@IRT_mu As D1) Ds2)) (fun (_1 : @IRTDesc As) (recl1 : @IRTSubsts As -> Type) (_2 : @IRTDesc As) (recr1 : @IRTSubsts As -> Type) (Ds2 : @IRTSubsts As) => @Either (recl1 Ds2) (recr1 Ds2)) (fun (_1 : @IRTDesc As) (recl1 : @IRTSubsts As -> Type) (_2 : @IRTDesc As) (recr1 : @IRTSubsts As -> Type) (Ds2 : @IRTSubsts As) => prod (recl1 Ds2) (recr1 Ds2)) (fun (i : @SAWCoreScaffolding.Nat) (_1 : SAWCorePrelude.ListSort_rect (fun (_1 : @ListSort) => @SAWCoreScaffolding.Nat -> Type) (fun (_1 : @SAWCoreScaffolding.Nat) => @SAWCoreScaffolding.Eq (@SAWCoreScaffolding.Bool) (@SAWCoreScaffolding.true) (@SAWCoreScaffolding.false)) (fun (A : Type) (_1 : @ListSort) (rec : @SAWCoreScaffolding.Nat -> Type) => @Nat_cases Type A (fun (n : @SAWCoreScaffolding.Nat) (_2 : Type) => rec n)) As i -> @IRTDesc As) (recf : SAWCorePrelude.ListSort_rect (fun (_2 : @ListSort) => @SAWCoreScaffolding.Nat -> Type) (fun (_2 : @SAWCoreScaffolding.Nat) => @SAWCoreScaffolding.Eq (@SAWCoreScaffolding.Bool) (@SAWCoreScaffolding.true) (@SAWCoreScaffolding.false)) (fun (A : Type) (_2 : @ListSort) (rec : @SAWCoreScaffolding.Nat -> Type) => @Nat_cases Type A (fun (n : @SAWCoreScaffolding.Nat) (_3 : Type) => rec n)) As i -> @IRTSubsts As -> Type) (Ds2 : @IRTSubsts As) => @sigT (@listSortGet As i) (fun (a : SAWCorePrelude.ListSort_rect (fun (_2 : @ListSort) => @SAWCoreScaffolding.Nat -> Type) (fun (_2 : @SAWCoreScaffolding.Nat) => @SAWCoreScaffolding.Eq (@SAWCoreScaffolding.Bool) (@SAWCoreScaffolding.true) (@SAWCoreScaffolding.false)) (fun (A : Type) (_2 : @ListSort) (rec : @SAWCoreScaffolding.Nat -> Type) => @Nat_cases Type A (fun (n : @SAWCoreScaffolding.Nat) (_3 : Type) => rec n)) As i) => recf a Ds2)) (fun (n : @SAWCoreScaffolding.Nat) (len : @SAWCoreVectorsAsCoqVectors.Vec n (@SAWCoreScaffolding.Bool)) (_1 : @IRTDesc As) (rec : @IRTSubsts As -> Type) (Ds2 : @IRTSubsts As) => @BVVec n len (rec Ds2)) (fun (_1 : @IRTSubsts As) => unit) (fun (_1 : @IRTSubsts As) => @SAWCoreScaffolding.Eq (@SAWCoreScaffolding.Bool) (@SAWCoreScaffolding.true) (@SAWCoreScaffolding.false)) (fun (i : @SAWCoreScaffolding.Nat) (_1 : @IRTSubsts As) => @listSortGet As i) Dr Ds1) => @IRT_pair As Ds1 Dl Dr (recl Ds1 xl) (recr Ds1 xr)) x) (fun (i : @SAWCoreScaffolding.Nat) (Df : SAWCorePrelude.ListSort_rect (fun (_1 : @ListSort) => @SAWCoreScaffolding.Nat -> Type) (fun (_1 : @SAWCoreScaffolding.Nat) => @SAWCoreScaffolding.Eq (@SAWCoreScaffolding.Bool) (@SAWCoreScaffolding.true) (@SAWCoreScaffolding.false)) (fun (A : Type) (_1 : @ListSort) (rec : @SAWCoreScaffolding.Nat -> Type) => @Nat_cases Type A (fun (n : @SAWCoreScaffolding.Nat) (_2 : Type) => rec n)) As i -> @IRTDesc As) (recf : forall (a : SAWCorePrelude.ListSort_rect (fun (_1 : @ListSort) => @SAWCoreScaffolding.Nat -> Type) (fun (_1 : @SAWCoreScaffolding.Nat) => @SAWCoreScaffolding.Eq (@SAWCoreScaffolding.Bool) (@SAWCoreScaffolding.true) (@SAWCoreScaffolding.false)) (fun (A : Type) (_1 : @ListSort) (rec : @SAWCoreScaffolding.Nat -> Type) => @Nat_cases Type A (fun (n : @SAWCoreScaffolding.Nat) (_2 : Type) => rec n)) As i), forall (Ds1 : @IRTSubsts As), SAWCorePrelude.IRTDesc_rect As (fun (_1 : @IRTDesc As) => @IRTSubsts As -> Type) (fun (i1 : @SAWCoreScaffolding.Nat) (Ds2 : @IRTSubsts As) => @IRT As (@dropIRTs As Ds2 (@SAWCoreScaffolding.Succ i1)) (@atIRTs As Ds2 i1)) (fun (D1 : @IRTDesc As) (rec : @IRTSubsts As -> Type) (Ds2 : @IRTSubsts As) => rec (@IRTs_Cons As (@IRT_mu As D1) Ds2)) (fun (_1 : @IRTDesc As) (recl : @IRTSubsts As -> Type) (_2 : @IRTDesc As) (recr : @IRTSubsts As -> Type) (Ds2 : @IRTSubsts As) => @Either (recl Ds2) (recr Ds2)) (fun (_1 : @IRTDesc As) (recl : @IRTSubsts As -> Type) (_2 : @IRTDesc As) (recr : @IRTSubsts As -> Type) (Ds2 : @IRTSubsts As) => prod (recl Ds2) (recr Ds2)) (fun (i1 : @SAWCoreScaffolding.Nat) (_1 : SAWCorePrelude.ListSort_rect (fun (_1 : @ListSort) => @SAWCoreScaffolding.Nat -> Type) (fun (_1 : @SAWCoreScaffolding.Nat) => @SAWCoreScaffolding.Eq (@SAWCoreScaffolding.Bool) (@SAWCoreScaffolding.true) (@SAWCoreScaffolding.false)) (fun (A : Type) (_1 : @ListSort) (rec : @SAWCoreScaffolding.Nat -> Type) => @Nat_cases Type A (fun (n : @SAWCoreScaffolding.Nat) (_2 : Type) => rec n)) As i1 -> @IRTDesc As) (recf : SAWCorePrelude.ListSort_rect (fun (_2 : @ListSort) => @SAWCoreScaffolding.Nat -> Type) (fun (_2 : @SAWCoreScaffolding.Nat) => @SAWCoreScaffolding.Eq (@SAWCoreScaffolding.Bool) (@SAWCoreScaffolding.true) (@SAWCoreScaffolding.false)) (fun (A : Type) (_2 : @ListSort) (rec : @SAWCoreScaffolding.Nat -> Type) => @Nat_cases Type A (fun (n : @SAWCoreScaffolding.Nat) (_3 : Type) => rec n)) As i1 -> @IRTSubsts As -> Type) (Ds2 : @IRTSubsts As) => @sigT (@listSortGet As i1) (fun (a1 : SAWCorePrelude.ListSort_rect (fun (_2 : @ListSort) => @SAWCoreScaffolding.Nat -> Type) (fun (_2 : @SAWCoreScaffolding.Nat) => @SAWCoreScaffolding.Eq (@SAWCoreScaffolding.Bool) (@SAWCoreScaffolding.true) (@SAWCoreScaffolding.false)) (fun (A : Type) (_2 : @ListSort) (rec : @SAWCoreScaffolding.Nat -> Type) => @Nat_cases Type A (fun (n : @SAWCoreScaffolding.Nat) (_3 : Type) => rec n)) As i1) => recf a1 Ds2)) (fun (n : @SAWCoreScaffolding.Nat) (len : @SAWCoreVectorsAsCoqVectors.Vec n (@SAWCoreScaffolding.Bool)) (_1 : @IRTDesc As) (rec : @IRTSubsts As -> Type) (Ds2 : @IRTSubsts As) => @BVVec n len (rec Ds2)) (fun (_1 : @IRTSubsts As) => unit) (fun (_1 : @IRTSubsts As) => @SAWCoreScaffolding.Eq (@SAWCoreScaffolding.Bool) (@SAWCoreScaffolding.true) (@SAWCoreScaffolding.false)) (fun (i1 : @SAWCoreScaffolding.Nat) (_1 : @IRTSubsts As) => @listSortGet As i1) (Df a) Ds1 -> @IRT As Ds1 (Df a)) (Ds1 : @IRTSubsts As) (x : @sigT (SAWCorePrelude.ListSort_rect (fun (_1 : @ListSort) => @SAWCoreScaffolding.Nat -> Type) (fun (_1 : @SAWCoreScaffolding.Nat) => @SAWCoreScaffolding.Eq (@SAWCoreScaffolding.Bool) (@SAWCoreScaffolding.true) (@SAWCoreScaffolding.false)) (fun (A : Type) (_1 : @ListSort) (rec : @SAWCoreScaffolding.Nat -> Type) => @Nat_cases Type A (fun (n : @SAWCoreScaffolding.Nat) (_2 : Type) => rec n)) As i) (fun (a : SAWCorePrelude.ListSort_rect (fun (_1 : @ListSort) => @SAWCoreScaffolding.Nat -> Type) (fun (_1 : @SAWCoreScaffolding.Nat) => @SAWCoreScaffolding.Eq (@SAWCoreScaffolding.Bool) (@SAWCoreScaffolding.true) (@SAWCoreScaffolding.false)) (fun (A : Type) (_1 : @ListSort) (rec : @SAWCoreScaffolding.Nat -> Type) => @Nat_cases Type A (fun (n : @SAWCoreScaffolding.Nat) (_2 : Type) => rec n)) As i) => @UnfoldedIRT As Ds1 (Df a))) => @uncurrySigma (@listSortGet As i) (fun (a : SAWCorePrelude.ListSort_rect (fun (_1 : @ListSort) => @SAWCoreScaffolding.Nat -> Type) (fun (_1 : @SAWCoreScaffolding.Nat) => @SAWCoreScaffolding.Eq (@SAWCoreScaffolding.Bool) (@SAWCoreScaffolding.true) (@SAWCoreScaffolding.false)) (fun (A : Type) (_1 : @ListSort) (rec : @SAWCoreScaffolding.Nat -> Type) => @Nat_cases Type A (fun (n : @SAWCoreScaffolding.Nat) (_2 : Type) => rec n)) As i) => @UnfoldedIRT As Ds1 (Df a)) (@IRT As Ds1 (@IRT_sigT As i Df)) (fun (a : SAWCorePrelude.ListSort_rect (fun (_1 : @ListSort) => @SAWCoreScaffolding.Nat -> Type) (fun (_1 : @SAWCoreScaffolding.Nat) => @SAWCoreScaffolding.Eq (@SAWCoreScaffolding.Bool) (@SAWCoreScaffolding.true) (@SAWCoreScaffolding.false)) (fun (A : Type) (_1 : @ListSort) (rec : @SAWCoreScaffolding.Nat -> Type) => @Nat_cases Type A (fun (n : @SAWCoreScaffolding.Nat) (_2 : Type) => rec n)) As i) (xf : SAWCorePrelude.IRTDesc_rect As (fun (_1 : @IRTDesc As) => @IRTSubsts As -> Type) (fun (i1 : @SAWCoreScaffolding.Nat) (Ds2 : @IRTSubsts As) => @IRT As (@dropIRTs As Ds2 (@SAWCoreScaffolding.Succ i1)) (@atIRTs As Ds2 i1)) (fun (D1 : @IRTDesc As) (rec : @IRTSubsts As -> Type) (Ds2 : @IRTSubsts As) => rec (@IRTs_Cons As (@IRT_mu As D1) Ds2)) (fun (_1 : @IRTDesc As) (recl : @IRTSubsts As -> Type) (_2 : @IRTDesc As) (recr : @IRTSubsts As -> Type) (Ds2 : @IRTSubsts As) => @Either (recl Ds2) (recr Ds2)) (fun (_1 : @IRTDesc As) (recl : @IRTSubsts As -> Type) (_2 : @IRTDesc As) (recr : @IRTSubsts As -> Type) (Ds2 : @IRTSubsts As) => prod (recl Ds2) (recr Ds2)) (fun (i1 : @SAWCoreScaffolding.Nat) (_1 : SAWCorePrelude.ListSort_rect (fun (_1 : @ListSort) => @SAWCoreScaffolding.Nat -> Type) (fun (_1 : @SAWCoreScaffolding.Nat) => @SAWCoreScaffolding.Eq (@SAWCoreScaffolding.Bool) (@SAWCoreScaffolding.true) (@SAWCoreScaffolding.false)) (fun (A : Type) (_1 : @ListSort) (rec : @SAWCoreScaffolding.Nat -> Type) => @Nat_cases Type A (fun (n : @SAWCoreScaffolding.Nat) (_2 : Type) => rec n)) As i1 -> @IRTDesc As) (recf1 : SAWCorePrelude.ListSort_rect (fun (_2 : @ListSort) => @SAWCoreScaffolding.Nat -> Type) (fun (_2 : @SAWCoreScaffolding.Nat) => @SAWCoreScaffolding.Eq (@SAWCoreScaffolding.Bool) (@SAWCoreScaffolding.true) (@SAWCoreScaffolding.false)) (fun (A : Type) (_2 : @ListSort) (rec : @SAWCoreScaffolding.Nat -> Type) => @Nat_cases Type A (fun (n : @SAWCoreScaffolding.Nat) (_3 : Type) => rec n)) As i1 -> @IRTSubsts As -> Type) (Ds2 : @IRTSubsts As) => @sigT (@listSortGet As i1) (fun (a1 : SAWCorePrelude.ListSort_rect (fun (_2 : @ListSort) => @SAWCoreScaffolding.Nat -> Type) (fun (_2 : @SAWCoreScaffolding.Nat) => @SAWCoreScaffolding.Eq (@SAWCoreScaffolding.Bool) (@SAWCoreScaffolding.true) (@SAWCoreScaffolding.false)) (fun (A : Type) (_2 : @ListSort) (rec : @SAWCoreScaffolding.Nat -> Type) => @Nat_cases Type A (fun (n : @SAWCoreScaffolding.Nat) (_3 : Type) => rec n)) As i1) => recf1 a1 Ds2)) (fun (n : @SAWCoreScaffolding.Nat) (len : @SAWCoreVectorsAsCoqVectors.Vec n (@SAWCoreScaffolding.Bool)) (_1 : @IRTDesc As) (rec : @IRTSubsts As -> Type) (Ds2 : @IRTSubsts As) => @BVVec n len (rec Ds2)) (fun (_1 : @IRTSubsts As) => unit) (fun (_1 : @IRTSubsts As) => @SAWCoreScaffolding.Eq (@SAWCoreScaffolding.Bool) (@SAWCoreScaffolding.true) (@SAWCoreScaffolding.false)) (fun (i1 : @SAWCoreScaffolding.Nat) (_1 : @IRTSubsts As) => @listSortGet As i1) (Df a) Ds1) => @IRT_existT As Ds1 i Df a (recf a Ds1 xf)) x) (fun (n : @SAWCoreScaffolding.Nat) (len : @SAWCoreVectorsAsCoqVectors.Vec n (@SAWCoreScaffolding.Bool)) (D1 : @IRTDesc As) (recg : forall (Ds1 : @IRTSubsts As), SAWCorePrelude.IRTDesc_rect As (fun (_1 : @IRTDesc As) => @IRTSubsts As -> Type) (fun (i : @SAWCoreScaffolding.Nat) (Ds2 : @IRTSubsts As) => @IRT As (@dropIRTs As Ds2 (@SAWCoreScaffolding.Succ i)) (@atIRTs As Ds2 i)) (fun (D2 : @IRTDesc As) (rec : @IRTSubsts As -> Type) (Ds2 : @IRTSubsts As) => rec (@IRTs_Cons As (@IRT_mu As D2) Ds2)) (fun (_1 : @IRTDesc As) (recl : @IRTSubsts As -> Type) (_2 : @IRTDesc As) (recr : @IRTSubsts As -> Type) (Ds2 : @IRTSubsts As) => @Either (recl Ds2) (recr Ds2)) (fun (_1 : @IRTDesc As) (recl : @IRTSubsts As -> Type) (_2 : @IRTDesc As) (recr : @IRTSubsts As -> Type) (Ds2 : @IRTSubsts As) => prod (recl Ds2) (recr Ds2)) (fun (i : @SAWCoreScaffolding.Nat) (_1 : SAWCorePrelude.ListSort_rect (fun (_1 : @ListSort) => @SAWCoreScaffolding.Nat -> Type) (fun (_1 : @SAWCoreScaffolding.Nat) => @SAWCoreScaffolding.Eq (@SAWCoreScaffolding.Bool) (@SAWCoreScaffolding.true) (@SAWCoreScaffolding.false)) (fun (A : Type) (_1 : @ListSort) (rec : @SAWCoreScaffolding.Nat -> Type) => @Nat_cases Type A (fun (n1 : @SAWCoreScaffolding.Nat) (_2 : Type) => rec n1)) As i -> @IRTDesc As) (recf : SAWCorePrelude.ListSort_rect (fun (_2 : @ListSort) => @SAWCoreScaffolding.Nat -> Type) (fun (_2 : @SAWCoreScaffolding.Nat) => @SAWCoreScaffolding.Eq (@SAWCoreScaffolding.Bool) (@SAWCoreScaffolding.true) (@SAWCoreScaffolding.false)) (fun (A : Type) (_2 : @ListSort) (rec : @SAWCoreScaffolding.Nat -> Type) => @Nat_cases Type A (fun (n1 : @SAWCoreScaffolding.Nat) (_3 : Type) => rec n1)) As i -> @IRTSubsts As -> Type) (Ds2 : @IRTSubsts As) => @sigT (@listSortGet As i) (fun (a : SAWCorePrelude.ListSort_rect (fun (_2 : @ListSort) => @SAWCoreScaffolding.Nat -> Type) (fun (_2 : @SAWCoreScaffolding.Nat) => @SAWCoreScaffolding.Eq (@SAWCoreScaffolding.Bool) (@SAWCoreScaffolding.true) (@SAWCoreScaffolding.false)) (fun (A : Type) (_2 : @ListSort) (rec : @SAWCoreScaffolding.Nat -> Type) => @Nat_cases Type A (fun (n1 : @SAWCoreScaffolding.Nat) (_3 : Type) => rec n1)) As i) => recf a Ds2)) (fun (n1 : @SAWCoreScaffolding.Nat) (len1 : @SAWCoreVectorsAsCoqVectors.Vec n1 (@SAWCoreScaffolding.Bool)) (_1 : @IRTDesc As) (rec : @IRTSubsts As -> Type) (Ds2 : @IRTSubsts As) => @BVVec n1 len1 (rec Ds2)) (fun (_1 : @IRTSubsts As) => unit) (fun (_1 : @IRTSubsts As) => @SAWCoreScaffolding.Eq (@SAWCoreScaffolding.Bool) (@SAWCoreScaffolding.true) (@SAWCoreScaffolding.false)) (fun (i : @SAWCoreScaffolding.Nat) (_1 : @IRTSubsts As) => @listSortGet As i) D1 Ds1 -> @IRT As Ds1 D1) (Ds1 : @IRTSubsts As) (x : @SAWCoreVectorsAsCoqVectors.Vec (@SAWCoreVectorsAsCoqVectors.bvToNat n len) (@UnfoldedIRT As Ds1 D1)) => @IRT_genBVVec As Ds1 n len D1 (fun (i : @SAWCoreVectorsAsCoqVectors.Vec n (@SAWCoreScaffolding.Bool)) (pf : @SAWCoreScaffolding.Eq (@SAWCoreScaffolding.Bool) (@SAWCoreVectorsAsCoqVectors.bvult n i len) (@SAWCoreScaffolding.true)) => recg Ds1 (@atBVVec n len (@UnfoldedIRT As Ds1 D1) x i pf))) (fun (Ds1 : @IRTSubsts As) (x : unit) => @IRT_tt As Ds1) (fun (Ds1 : @IRTSubsts As) (x : @SAWCoreScaffolding.Eq (@SAWCoreScaffolding.Bool) (@SAWCoreScaffolding.true) (@SAWCoreScaffolding.false)) => @efq (@IRT As Ds1 (@IRT_empty As)) x) (fun (i : @SAWCoreScaffolding.Nat) (Ds1 : @IRTSubsts As) (x : SAWCorePrelude.ListSort_rect (fun (_1 : @ListSort) => @SAWCoreScaffolding.Nat -> Type) (fun (_1 : @SAWCoreScaffolding.Nat) => @SAWCoreScaffolding.Eq (@SAWCoreScaffolding.Bool) (@SAWCoreScaffolding.true) (@SAWCoreScaffolding.false)) (fun (A : Type) (_1 : @ListSort) (rec : @SAWCoreScaffolding.Nat -> Type) => @Nat_cases Type A (fun (n : @SAWCoreScaffolding.Nat) (_2 : Type) => rec n)) As i) => @IRT_elemT As Ds1 i x) D Ds. @@ -1046,6 +1061,12 @@ Axiom arrayLookup : forall (a : Type), forall (b : Type), @Array a b -> a -> b . Axiom arrayUpdate : forall (a : Type), forall (b : Type), @Array a b -> a -> b -> @Array a b . +Axiom arrayCopy : forall (n : @SAWCoreScaffolding.Nat), forall (a : Type), @Array (@SAWCoreVectorsAsCoqVectors.Vec n (@SAWCoreScaffolding.Bool)) a -> @SAWCoreVectorsAsCoqVectors.Vec n (@SAWCoreScaffolding.Bool) -> @Array (@SAWCoreVectorsAsCoqVectors.Vec n (@SAWCoreScaffolding.Bool)) a -> @SAWCoreVectorsAsCoqVectors.Vec n (@SAWCoreScaffolding.Bool) -> @SAWCoreVectorsAsCoqVectors.Vec n (@SAWCoreScaffolding.Bool) -> @Array (@SAWCoreVectorsAsCoqVectors.Vec n (@SAWCoreScaffolding.Bool)) a . + +Axiom arraySet : forall (n : @SAWCoreScaffolding.Nat), forall (a : Type), @Array (@SAWCoreVectorsAsCoqVectors.Vec n (@SAWCoreScaffolding.Bool)) a -> @SAWCoreVectorsAsCoqVectors.Vec n (@SAWCoreScaffolding.Bool) -> a -> @SAWCoreVectorsAsCoqVectors.Vec n (@SAWCoreScaffolding.Bool) -> @Array (@SAWCoreVectorsAsCoqVectors.Vec n (@SAWCoreScaffolding.Bool)) a . + +Axiom arrayRangeEq : forall (n : @SAWCoreScaffolding.Nat), forall (a : Type), @Array (@SAWCoreVectorsAsCoqVectors.Vec n (@SAWCoreScaffolding.Bool)) a -> @SAWCoreVectorsAsCoqVectors.Vec n (@SAWCoreScaffolding.Bool) -> @Array (@SAWCoreVectorsAsCoqVectors.Vec n (@SAWCoreScaffolding.Bool)) a -> @SAWCoreVectorsAsCoqVectors.Vec n (@SAWCoreScaffolding.Bool) -> @SAWCoreVectorsAsCoqVectors.Vec n (@SAWCoreScaffolding.Bool) -> @SAWCoreScaffolding.Bool . + Axiom arrayEq : forall (a : Type), forall (b : Type), @Array a b -> @Array a b -> @SAWCoreScaffolding.Bool . (* Prelude.bveq_sameL was skipped *) From 6a62a561091aa40068cdcff066a5d0bed1c36f59 Mon Sep 17 00:00:00 2001 From: Eddy Westbrook Date: Tue, 14 Sep 2021 14:26:52 -0700 Subject: [PATCH 31/98] added support for the Crucible BVZext and BVTrunc instructions, and fixed up that for BVSext --- heapster-saw/src/Verifier/SAW/Heapster/TypedCrucible.hs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/heapster-saw/src/Verifier/SAW/Heapster/TypedCrucible.hs b/heapster-saw/src/Verifier/SAW/Heapster/TypedCrucible.hs index 37f01075a7..fdd44e7d78 100644 --- a/heapster-saw/src/Verifier/SAW/Heapster/TypedCrucible.hs +++ b/heapster-saw/src/Verifier/SAW/Heapster/TypedCrucible.hs @@ -2796,8 +2796,12 @@ tcExpr (BVUndef _w) = tcExpr (BVLit w (BV.BV i)) = withKnownNat w $ pure $ Just $ bvInt i -tcExpr (BVSext w2 _ (RegWithVal _ (bvMatchConstInt -> Just i))) = - withKnownNat w2 $ pure $ Just $ bvInt i +tcExpr (BVTrunc w2 _ (RegWithVal _ (bvMatchConst -> Just bv))) = + withKnownNat w2 $ pure $ Just $ bvBV $ BV.trunc w2 bv +tcExpr (BVZext w2 _ (RegWithVal _ (bvMatchConst -> Just bv))) = + withKnownNat w2 $ pure $ Just $ bvBV $ BV.zext w2 bv +tcExpr (BVSext w2 w (RegWithVal _ (bvMatchConst -> Just bv))) = + withKnownNat w2 $ pure $ Just $ bvBV $ BV.sext w w2 bv tcExpr (BVAdd w (RegWithVal _ e1) (RegWithVal _ e2)) = withKnownNat w $ pure $ Just $ bvAdd e1 e2 From 0b6bf9da4a6b5ff8438a165e1d360526a8ec2351 Mon Sep 17 00:00:00 2001 From: Eddy Westbrook Date: Wed, 15 Sep 2021 07:11:25 -0700 Subject: [PATCH 32/98] added heapster_init_env_debug and heapster_init_env_from_file_debug commands --- src/SAWScript/HeapsterBuiltins.hs | 49 +++++++++++++++++++++++-------- src/SAWScript/Interpreter.hs | 17 +++++++++++ 2 files changed, 53 insertions(+), 13 deletions(-) diff --git a/src/SAWScript/HeapsterBuiltins.hs b/src/SAWScript/HeapsterBuiltins.hs index 33777a420d..5eb3b2c91f 100644 --- a/src/SAWScript/HeapsterBuiltins.hs +++ b/src/SAWScript/HeapsterBuiltins.hs @@ -13,7 +13,9 @@ module SAWScript.HeapsterBuiltins ( heapster_init_env + , heapster_init_env_debug , heapster_init_env_from_file + , heapster_init_env_from_file_debug , heapster_init_env_for_files , load_sawcore_from_file , heapster_get_cfg @@ -260,32 +262,41 @@ parseAndInsDef henv nm term_tp term_string = -- | Build a 'HeapsterEnv' associated with the given SAW core module and the -- given 'LLVMModule's. Add any globals in the 'LLVMModule's to the returned -- 'HeapsterEnv'. -mkHeapsterEnv :: ModuleName -> [Some LLVMModule] -> TopLevel HeapsterEnv -mkHeapsterEnv saw_mod_name llvm_mods@(Some first_mod:_) = +mkHeapsterEnv :: DebugLevel -> ModuleName -> [Some LLVMModule] -> + TopLevel HeapsterEnv +mkHeapsterEnv dlevel saw_mod_name llvm_mods@(Some first_mod:_) = do let w = llvmModuleArchReprWidth first_mod leq_proof <- case decideLeq (knownNat @1) w of Left pf -> return pf Right _ -> fail "LLVM arch width is 0!" let globals = concatMap (\(Some lm) -> L.modGlobals $ modAST lm) llvm_mods - dlevel = noDebugLevel -- FIXME: how to set the debug level for - -- permEnvAddGlobalConst? env = withKnownNat w $ withLeqProof leq_proof $ foldl (permEnvAddGlobalConst dlevel w) heapster_default_env globals env_ref <- liftIO $ newIORef env - dlevel_ref <- liftIO $ newIORef noDebugLevel + dlevel_ref <- liftIO $ newIORef dlevel return $ HeapsterEnv { heapsterEnvSAWModule = saw_mod_name, heapsterEnvPermEnvRef = env_ref, heapsterEnvLLVMModules = llvm_mods, heapsterEnvDebugLevel = dlevel_ref } -mkHeapsterEnv _ [] = fail "mkHeapsterEnv: empty list of LLVM modules!" +mkHeapsterEnv _ _ [] = fail "mkHeapsterEnv: empty list of LLVM modules!" -heapster_init_env :: BuiltinContext -> Options -> Text -> String -> - TopLevel HeapsterEnv -heapster_init_env _bic _opts mod_str llvm_filename = +heapster_init_env :: BuiltinContext -> Options -> + Text -> String -> TopLevel HeapsterEnv +heapster_init_env bic opts mod_str llvm_filename = + heapster_init_env_gen bic opts noDebugLevel mod_str llvm_filename + +heapster_init_env_debug :: BuiltinContext -> Options -> + Text -> String -> TopLevel HeapsterEnv +heapster_init_env_debug bic opts mod_str llvm_filename = + heapster_init_env_gen bic opts traceDebugLevel mod_str llvm_filename + +heapster_init_env_gen :: BuiltinContext -> Options -> DebugLevel -> + Text -> String -> TopLevel HeapsterEnv +heapster_init_env_gen _bic _opts dlevel mod_str llvm_filename = do llvm_mod <- llvm_load_module llvm_filename sc <- getSharedContext let saw_mod_name = mkModuleName [mod_str] @@ -297,7 +308,7 @@ heapster_init_env _bic _opts mod_str llvm_filename = preludeMod <- liftIO $ scFindModule sc preludeModuleName liftIO $ scLoadModule sc (insImport (const True) preludeMod $ emptyModule saw_mod_name) - mkHeapsterEnv saw_mod_name [llvm_mod] + mkHeapsterEnv dlevel saw_mod_name [llvm_mod] load_sawcore_from_file :: BuiltinContext -> Options -> String -> TopLevel () load_sawcore_from_file _ _ mod_filename = @@ -307,12 +318,24 @@ load_sawcore_from_file _ _ mod_filename = heapster_init_env_from_file :: BuiltinContext -> Options -> String -> String -> TopLevel HeapsterEnv -heapster_init_env_from_file _bic _opts mod_filename llvm_filename = +heapster_init_env_from_file bic opts mod_filename llvm_filename = + heapster_init_env_from_file_gen + bic opts noDebugLevel mod_filename llvm_filename + +heapster_init_env_from_file_debug :: BuiltinContext -> Options -> + String -> String -> TopLevel HeapsterEnv +heapster_init_env_from_file_debug bic opts mod_filename llvm_filename = + heapster_init_env_from_file_gen + bic opts traceDebugLevel mod_filename llvm_filename + +heapster_init_env_from_file_gen :: BuiltinContext -> Options -> DebugLevel -> + String -> String -> TopLevel HeapsterEnv +heapster_init_env_from_file_gen _bic _opts dlevel mod_filename llvm_filename = do llvm_mod <- llvm_load_module llvm_filename sc <- getSharedContext (saw_mod, saw_mod_name) <- readModuleFromFile mod_filename liftIO $ tcInsertModule sc saw_mod - mkHeapsterEnv saw_mod_name [llvm_mod] + mkHeapsterEnv dlevel saw_mod_name [llvm_mod] heapster_init_env_for_files :: BuiltinContext -> Options -> String -> [String] -> TopLevel HeapsterEnv @@ -321,7 +344,7 @@ heapster_init_env_for_files _bic _opts mod_filename llvm_filenames = sc <- getSharedContext (saw_mod, saw_mod_name) <- readModuleFromFile mod_filename liftIO $ tcInsertModule sc saw_mod - mkHeapsterEnv saw_mod_name llvm_mods + mkHeapsterEnv noDebugLevel saw_mod_name llvm_mods -- | Look up the CFG associated with a symbol name in a Heapster environment heapster_get_cfg :: BuiltinContext -> Options -> HeapsterEnv -> diff --git a/src/SAWScript/Interpreter.hs b/src/SAWScript/Interpreter.hs index c063ba0c42..02d0e99175 100644 --- a/src/SAWScript/Interpreter.hs +++ b/src/SAWScript/Interpreter.hs @@ -3011,6 +3011,14 @@ primitives = Map.fromList , " from the named LLVM bitcode file." ] + , prim "heapster_init_env_debug" + "String -> String -> TopLevel HeapsterEnv" + (bicVal heapster_init_env) + Experimental + [ "Create a new Heapster environment with the given SAW module name" + , " from the named LLVM bitcode file with debug tracing turned on" + ] + , prim "heapster_init_env_from_file" "String -> String -> TopLevel HeapsterEnv" (bicVal heapster_init_env_from_file) @@ -3019,6 +3027,15 @@ primitives = Map.fromList , " initialized with the module in the given SAW core file." ] + , prim "heapster_init_env_from_file_debug" + "String -> String -> TopLevel HeapsterEnv" + (bicVal heapster_init_env_from_file_debug) + Experimental + [ "Create a new Heapster environment from the named LLVM bitcode file," + , " initialized with the module in the given SAW core file, with debug" + , " tracing turned on" + ] + , prim "load_sawcore_from_file" "String -> TopLevel ()" (bicVal load_sawcore_from_file) From 495e95846f9596d08bc2887eadbc827e766f401b Mon Sep 17 00:00:00 2001 From: Eddy Westbrook Date: Wed, 15 Sep 2021 09:11:28 -0700 Subject: [PATCH 33/98] small tweaks to rust_data.saw to get it to work --- heapster-saw/examples/rust_data.saw | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/heapster-saw/examples/rust_data.saw b/heapster-saw/examples/rust_data.saw index 6c897879df..198164c2b7 100644 --- a/heapster-saw/examples/rust_data.saw +++ b/heapster-saw/examples/rust_data.saw @@ -1,6 +1,5 @@ enable_experimental; env <- heapster_init_env_from_file "rust_data.sawcore" "rust_data.bc"; -heapster_set_debug_level env 1; /*** *** Types @@ -32,7 +31,10 @@ heapster_define_rust_type env "pub enum Sum { Left (X), Right (Y) }"; heapster_define_rust_type env "pub enum Option { None, Some (X) }"; // The str type -heapster_define_llvmshape env "str" 64 "" "exsh len:bv 64.arraysh(len,1,[(8,int8<>)])"; +// For now we have to define the shape explicitly without the int8 name because +// we don't yet have implications on array cells +//heapster_define_llvmshape env "str" 64 "" "exsh len:bv 64.arraysh(len,1,[(8,int8<>)])"; +heapster_define_llvmshape env "str" 64 "" "exsh len:bv 64.arraysh(len,1,[(8,exists x:bv 8.eq(llvmword(x)))])"; //heapster_define_rust_type env "type str = [u8];"; // The String type @@ -135,7 +137,8 @@ heapster_assume_fun_rename env to_string_str "to_string_str" "(len:bv 64). arg0: // HashMap::insert // FIXME: we currently pretend this always returns None hashmap_u64_u64_insert_sym <- heapster_find_symbol env "std11collections4hash3map24HashMap$LT$K$C$V$C$S$GT$6insert"; -heapster_assume_fun_rename env hashmap_u64_u64_insert_sym "hashmap_u64_u64_insert" "<'a> fn (&'a mut HashMap,u64,u64) -> Option" "\\ (endl:HashMap (Vec 64 Bool) (Vec 64 Bool) * #() -> CompM (HashMap (Vec 64 Bool) (Vec 64 Bool) * #())) (h:HashMap (Vec 64 Bool) (Vec 64 Bool)) (k:Vec 64 Bool) (v:Vec 64 Bool) -> returnM ((#() -> CompM (HashMap (Vec 64 Bool) (Vec 64 Bool) * #())) * Either #() (Vec 64 Bool) * #()) ((\\ (_:#()) -> returnM (HashMap (Vec 64 Bool) (Vec 64 Bool) * #()) (Cons (Vec 64 Bool * Vec 64 Bool) (k,v) h, ())), Left #() (Vec 64 Bool) (), ())"; +heapster_assume_fun_rename_prim env hashmap_u64_u64_insert_sym "hashmap_u64_u64_insert" "<'a> fn (&'a mut HashMap,u64,u64) -> Option"; +//heapster_assume_fun_rename env hashmap_u64_u64_insert_sym "hashmap_u64_u64_insert" "<'a> fn (&'a mut HashMap,u64,u64) -> Option" "\\ (endl:HashMap (Vec 64 Bool) (Vec 64 Bool) * #() -> CompM (HashMap (Vec 64 Bool) (Vec 64 Bool) * #())) (h:HashMap (Vec 64 Bool) (Vec 64 Bool)) (k:Vec 64 Bool) (v:Vec 64 Bool) -> returnM ((#() -> CompM (HashMap (Vec 64 Bool) (Vec 64 Bool) * #())) * Either #() (Vec 64 Bool) * #()) ((\\ (_:#()) -> returnM (HashMap (Vec 64 Bool) (Vec 64 Bool) * #()) (Cons (Vec 64 Bool * Vec 64 Bool) (k,v) h, ())), Left #() (Vec 64 Bool) (), ())"; /* String__fmt_sym <- heapster_find_trait_method_symbol env "core::fmt::Display::fmt"; From 7e94ba7524e5d3f8aa62ea66bfbc8eda4246b242 Mon Sep 17 00:00:00 2001 From: Eddy Westbrook Date: Wed, 15 Sep 2021 09:12:52 -0700 Subject: [PATCH 34/98] added another formatting example that we cannot handle yet... --- heapster-saw/examples/rust_data.bc | Bin 206464 -> 209232 bytes heapster-saw/examples/rust_data.rs | 6 ++++++ 2 files changed, 6 insertions(+) diff --git a/heapster-saw/examples/rust_data.bc b/heapster-saw/examples/rust_data.bc index 6abc2c8f1baaea87d2b6391fc47e19031137c0b2..05b3c11a68a9a42e6dd1e825389a2bcfa83c8620 100644 GIT binary patch literal 209232 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 z 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

-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 diff --git a/heapster-saw/examples/rust_data.rs b/heapster-saw/examples/rust_data.rs index 818dffe811..1077ba7993 100644 --- a/heapster-saw/examples/rust_data.rs +++ b/heapster-saw/examples/rust_data.rs @@ -231,6 +231,12 @@ impl MixedStruct { } } +impl fmt::Display for MixedStruct { + fn fmt<'a, 'b>(&'a self, f: &'b mut fmt::Formatter) -> fmt::Result { + write!(f, "s = {}, i1 = {}, i2 = {}", self.s, self.i1, self.i2) + } +} + /* A 'true' enum */ #[derive(Clone, Debug, PartialEq)] #[repr(u64)] From f7e53a9cba08084844a7b99f7ce9f5242ab19de6 Mon Sep 17 00:00:00 2001 From: Eddy Westbrook Date: Wed, 15 Sep 2021 13:47:08 -0700 Subject: [PATCH 35/98] RecurseFlag to Permissions.hs; added requireNamedPerm --- .../src/Verifier/SAW/Heapster/Implication.hs | 3 --- .../src/Verifier/SAW/Heapster/Permissions.hs | 16 +++++++++++++++- 2 files changed, 15 insertions(+), 4 deletions(-) diff --git a/heapster-saw/src/Verifier/SAW/Heapster/Implication.hs b/heapster-saw/src/Verifier/SAW/Heapster/Implication.hs index adb1169efd..2ac3bd4d30 100644 --- a/heapster-saw/src/Verifier/SAW/Heapster/Implication.hs +++ b/heapster-saw/src/Verifier/SAW/Heapster/Implication.hs @@ -2624,9 +2624,6 @@ instance SubstVar s m => Substable1 s (LocalImplRet ps) m where -- FIXME: instead of having a separate PPInfo and name type map, we should maybe -- combine all the local context into one type...? -data RecurseFlag = RecLeft | RecRight | RecNone - deriving (Eq, Show, Read) - data ImplState vars ps = ImplState { _implStatePerms :: PermSet ps, _implStateVars :: CruCtx vars, diff --git a/heapster-saw/src/Verifier/SAW/Heapster/Permissions.hs b/heapster-saw/src/Verifier/SAW/Heapster/Permissions.hs index ab52151345..fef7125da1 100644 --- a/heapster-saw/src/Verifier/SAW/Heapster/Permissions.hs +++ b/heapster-saw/src/Verifier/SAW/Heapster/Permissions.hs @@ -86,7 +86,7 @@ import Debug.Trace ---------------------------------------------------------------------- --- * Utility Functions +-- * Utility Functions and Definitions ---------------------------------------------------------------------- -- | Delete the nth element of a list @@ -132,6 +132,11 @@ foldr1WithDefault f def (a:as) = f a $ foldr1WithDefault f def as foldMapWithDefault :: (b -> b -> b) -> b -> (a -> b) -> [a] -> b foldMapWithDefault comb def f l = foldr1WithDefault comb def $ map f l +-- | A flag indicating whether an equality test has unfolded a +-- recursively-defined name on one side of the equation already +data RecurseFlag = RecLeft | RecRight | RecNone + deriving (Eq, Show, Read) + ---------------------------------------------------------------------- -- * Pretty-printing @@ -6504,6 +6509,15 @@ lookupNamedPerm env = helper (permEnvNamedPerms env) where = Just rp helper (_:rps) rpn = helper rps rpn +-- | Look up the 'NamedPerm' for a 'NamedPermName' in a 'PermEnv' or raise an +-- error if it does not exist +requireNamedPerm :: PermEnv -> NamedPermName ns args a -> NamedPerm ns args a +requireNamedPerm env npn + | Just np <- lookupNamedPerm env npn = np +requireNamedPerm _ npn = + error ("requireNamedPerm: named perm does not exist: " + ++ namedPermNameName npn) + -- | Look up an LLVM shape by name in a 'PermEnv' and cast it to a given width lookupNamedShape :: PermEnv -> String -> Maybe SomeNamedShape lookupNamedShape env nm = From 9823bc028a662cbf42b19d7a1bbcbafcdbb321b2 Mon Sep 17 00:00:00 2001 From: Eddy Westbrook Date: Wed, 15 Sep 2021 13:48:00 -0700 Subject: [PATCH 36/98] widening now unfolds defined and recursive permissions --- .../Verifier/SAW/Heapster/TypedCrucible.hs | 9 +-- .../src/Verifier/SAW/Heapster/Widening.hs | 55 ++++++++++++++++--- 2 files changed, 51 insertions(+), 13 deletions(-) diff --git a/heapster-saw/src/Verifier/SAW/Heapster/TypedCrucible.hs b/heapster-saw/src/Verifier/SAW/Heapster/TypedCrucible.hs index fdd44e7d78..d1b7d19c5b 100644 --- a/heapster-saw/src/Verifier/SAW/Heapster/TypedCrucible.hs +++ b/heapster-saw/src/Verifier/SAW/Heapster/TypedCrucible.hs @@ -4031,12 +4031,12 @@ visitCallSite (TypedEntry {..}) site@(TypedCallSite {..}) -- | Widen the permissions held by all callers of an entrypoint to compute new, -- weaker input permissions that can hopefully be satisfied by them -widenEntry :: PermCheckExtC ext => DebugLevel -> +widenEntry :: PermCheckExtC ext => DebugLevel -> PermEnv -> TypedEntry TCPhase ext blocks tops ret args ghosts -> Some (TypedEntry TCPhase ext blocks tops ret args) -widenEntry dlevel (TypedEntry {..}) = +widenEntry dlevel env (TypedEntry {..}) = debugTrace dlevel ("Widening entrypoint: " ++ show typedEntryID) $ - case foldl1' (widen dlevel typedEntryTops typedEntryArgs) $ + case foldl1' (widen dlevel env typedEntryTops typedEntryArgs) $ map (fmapF typedCallSiteArgVarPerms) typedEntryCallers of Some (ArgVarPerms ghosts perms_in) -> let callers = @@ -4070,6 +4070,7 @@ visitEntry _ _ _ entry -- Otherwise, visit the call sites, widen if needed, and type-check the body visitEntry names can_widen blk entry = (stDebugLevel <$> get) >>= \dlevel -> + (stPermEnv <$> get) >>= \env -> debugTracePretty dlevel (vsep [pretty ("visitEntry " ++ show (typedEntryID entry) ++ " with input perms:"), @@ -4079,7 +4080,7 @@ visitEntry names can_widen blk entry = mapM (traverseF $ visitCallSite entry) (typedEntryCallers entry) >>= \callers -> if can_widen && any (anyF typedCallSiteImplFails) callers then - case widenEntry dlevel entry of + case widenEntry dlevel env entry of Some entry' -> -- If we widen then we are throwing away the old body, so all of its -- callees are no longer needed and can be deleted diff --git a/heapster-saw/src/Verifier/SAW/Heapster/Widening.hs b/heapster-saw/src/Verifier/SAW/Heapster/Widening.hs index b52408a0e0..449e4d0d03 100644 --- a/heapster-saw/src/Verifier/SAW/Heapster/Widening.hs +++ b/heapster-saw/src/Verifier/SAW/Heapster/Widening.hs @@ -119,18 +119,21 @@ instance Monad (PolyContT r m) where data WidState = WidState { _wsNameMap :: WidNameMap, _wsPPInfo :: PPInfo, - _wsDebugLevel :: DebugLevel } + _wsPermEnv :: PermEnv, + _wsDebugLevel :: DebugLevel, + _wsRecFlag :: RecurseFlag } makeLenses ''WidState type WideningM = StateT WidState (PolyContT ExtVarPermsFun Identity) -runWideningM :: WideningM () -> DebugLevel -> WidNameMap -> RAssign Name args -> +runWideningM :: WideningM () -> DebugLevel -> PermEnv -> RAssign Name args -> ExtVarPerms args -runWideningM m dlevel wnmap = +runWideningM m dlevel env = applyExtVarPermsFun $ runIdentity $ - runPolyContT (runStateT m $ WidState wnmap emptyPPInfo dlevel) + runPolyContT (runStateT m $ + WidState NameMap.empty emptyPPInfo env dlevel RecNone) (Identity . wnMapExtWidFun . _wsNameMap . snd) openMb :: CruCtx ctx -> Mb ctx a -> WideningM (RAssign Name ctx, a) @@ -657,6 +660,40 @@ widenPerm' _ (ValPerm_Named npn1 args1 off1) (ValPerm_Named npn2 args2 off2) , offsetsEq off1 off2 = (\args -> ValPerm_Named npn1 args off1) <$> widenExprs (namedPermNameArgs npn1) args1 args2 +widenPerm' tp (ValPerm_Named npn1 args1 off1) p2 + | DefinedSortRepr _ <- namedPermNameSort npn1 = + do env <- use wsPermEnv + let np1 = requireNamedPerm env npn1 + widenPerm tp (unfoldPerm np1 args1 off1) p2 +widenPerm' tp p1 (ValPerm_Named npn2 args2 off2) + | DefinedSortRepr _ <- namedPermNameSort npn2 = + do env <- use wsPermEnv + let np2 = requireNamedPerm env npn2 + widenPerm tp p1 (unfoldPerm np2 args2 off2) +widenPerm' tp (ValPerm_Named npn1 args1 off1) p2 + | RecursiveSortRepr _ _ <- namedPermNameSort npn1 = + use wsRecFlag >>= \case + RecRight -> + -- If we have already unfolded on the right, don't unfold on the left + -- (for termination reasons); instead just give up and return true + return ValPerm_True + _ -> + do wsRecFlag .= RecLeft + env <- use wsPermEnv + let np1 = requireNamedPerm env npn1 + widenPerm tp (unfoldPerm np1 args1 off1) p2 +widenPerm' tp p1 (ValPerm_Named npn2 args2 off2) + | RecursiveSortRepr _ _ <- namedPermNameSort npn2 = + use wsRecFlag >>= \case + RecLeft -> + -- If we have already unfolded on the left, don't unfold on the right + -- (for termination reasons); instead just give up and return true + return ValPerm_True + _ -> + do wsRecFlag .= RecRight + env <- use wsPermEnv + let np2 = requireNamedPerm env npn2 + widenPerm tp p1 (unfoldPerm np2 args2 off2) widenPerm' _ (ValPerm_Var x1 off1) (ValPerm_Var x2 off2) | x1 == x2 && offsetsEq off1 off2 = return $ ValPerm_Var x1 off1 widenPerm' tp (ValPerm_Conj ps1) (ValPerm_Conj ps2) = @@ -879,13 +916,13 @@ simplifyGhostPerms _ some_avps = some_avps ---------------------------------------------------------------------- -- | Widen two lists of permissions-in-bindings -widen :: DebugLevel -> CruCtx tops -> CruCtx args -> +widen :: DebugLevel -> PermEnv -> CruCtx tops -> CruCtx args -> Some (ArgVarPerms (tops :++: args)) -> Some (ArgVarPerms (tops :++: args)) -> Some (ArgVarPerms (tops :++: args)) -widen dlevel tops args (Some (ArgVarPerms - vars1 mb_perms1)) (Some (ArgVarPerms - vars2 mb_perms2)) = +widen dlevel env tops args (Some (ArgVarPerms + vars1 mb_perms1)) (Some (ArgVarPerms + vars2 mb_perms2)) = let all_args = appendCruCtx tops args prxs1 = cruCtxProxies vars1 prxs2 = cruCtxProxies vars2 @@ -893,7 +930,7 @@ widen dlevel tops args (Some (ArgVarPerms simplifyGhostPerms (cruCtxProxies all_args) $ completeArgVarPerms $ flip nuMultiWithElim1 mb_mb_perms1 $ \args_ns1 mb_perms1' -> - (\m -> runWideningM m dlevel NameMap.empty args_ns1) $ + (\m -> runWideningM m dlevel env args_ns1) $ do (vars1_ns, ps1) <- openMb vars1 mb_perms1' (ns2, ps2) <- openMb (appendCruCtx all_args vars2) mb_perms2 let (args_ns2, vars2_ns) = RL.split all_args prxs2 ns2 From d91b753bea217f643370017e619a94e2d91d1dda Mon Sep 17 00:00:00 2001 From: Eddy Westbrook Date: Wed, 15 Sep 2021 14:38:45 -0700 Subject: [PATCH 37/98] whoops, forgot to insert a bindM into the translation of SImpl_LLVMArrayContents --- .../Verifier/SAW/Heapster/SAWTranslation.hs | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/heapster-saw/src/Verifier/SAW/Heapster/SAWTranslation.hs b/heapster-saw/src/Verifier/SAW/Heapster/SAWTranslation.hs index 7a45f64fd5..6aa65ebba9 100644 --- a/heapster-saw/src/Verifier/SAW/Heapster/SAWTranslation.hs +++ b/heapster-saw/src/Verifier/SAW/Heapster/SAWTranslation.hs @@ -2647,7 +2647,7 @@ translateSimplImpl (ps0 :: Proxy ps0) mb_simpl m = case mbMatch mb_simpl of m [nuMP| SImpl_LLVMArrayContents _ ap flds' impl |] -> - do pctx_out_trans <- translateSimplImplOutHead mb_simpl + do p_out_trans <- translateSimplImplOutHead mb_simpl (w_term, len_term, elem_tp, _) <- translateLLVMArrayPerm ap flds_in_trans <- fmap tupleTypeTrans $ translate $ @@ -2663,15 +2663,21 @@ translateSimplImpl (ps0 :: Proxy ps0) mb_simpl m = case mbMatch mb_simpl of (mbCombine RL.typeCtxProxies impl) MNil MNil (fmap ((MNil :>:) . extPermTrans) flds_in_trans) (MNil :>: Member_Base) (fmap ((MNil :>:) . extPermTrans) flds_out_trans) - let mk_arr_out_tm ptrans_arr = + -- Build the computation that maps impl_tm over the input array using the + -- mapBVVecM monadic combinator + ptrans_arr <- getTopPermM + let arr_out_comp_tm = applyOpenTermMulti (globalOpenTerm "Prelude.mapBVVecM") [elem_tp, typeTransType1 flds_out_trans, impl_tm, w_term, len_term, transTerm1 ptrans_arr] - withPermStackM id - (\(pctx :>: ptrans_arr) -> - pctx :>: typeTransF pctx_out_trans [mk_arr_out_tm ptrans_arr]) - m + -- Now use bindM to bind the result of arr_out_comp_tm in the remaining + -- computation + applyMultiTransM (return $ globalOpenTerm "Prelude.bindM") + [return (typeTransType1 p_out_trans), returnTypeM, + return arr_out_comp_tm, + lambdaTransM "mapped_array" p_out_trans $ \ptrans_arr' -> + withPermStackM id (\(pctx :>: _) -> pctx :>: ptrans_arr') m] [nuMP| SImpl_LLVMFieldIsPtr x _ |] -> withPermStackM (:>: translateVar x) From 899cf70c0532c3b861dd0aa3e1cd11efb6838736 Mon Sep 17 00:00:00 2001 From: Eddy Westbrook Date: Wed, 15 Sep 2021 14:46:45 -0700 Subject: [PATCH 38/98] removed the old gen_block_perms hints that are no longer used anyway from arrays.saw --- heapster-saw/examples/arrays.saw | 8 -------- 1 file changed, 8 deletions(-) diff --git a/heapster-saw/examples/arrays.saw b/heapster-saw/examples/arrays.saw index f943abc800..1a12837847 100644 --- a/heapster-saw/examples/arrays.saw +++ b/heapster-saw/examples/arrays.saw @@ -1,6 +1,5 @@ enable_experimental; env <- heapster_init_env_from_file "arrays.sawcore" "arrays.bc"; -heapster_set_debug_level env 1; heapster_define_perm env "int64" " " "llvmptr 64" "exists x:bv 64.eq(llvmword(x))"; heapster_define_perm env "int8" " " "llvmptr 8" "exists x:bv 8.eq(llvmword(x))"; @@ -15,22 +14,15 @@ heapster_typecheck_fun env "contains0_rec_" "(len:bv 64).arg0:eq(llvmword(len)), // heapster_block_entry_hint env "contains0" 9 "top0:bv 64, top1:llvmptr 64, top2:llvmptr 64" "frm:llvmframe 64, x0:llvmptr 64, x1:llvmptr 64" "top0:true, top1:array(0, int64<>]), top2:eq(llvmword(top0)), arg0:ptr((W,0) |-> true), arg1:ptr((W,0) |-> eq(x1)), arg2:ptr((W,0) |-> eq(x0)), arg3:ptr((W,0) |-> int64<>), frm:llvmframe [arg3:8, arg2:8, arg1:8, arg0:8], x0:eq(top2), x1:eq(top1)"; // heapster_typecheck_fun env "contains0" "(len:bv 64).arg0:array(0, int64<>]), arg1:eq(llvmword(len)) -o arg0:array(0, int64<>]), arg1:true, ret:int64<>"; -// the new way using a gen perms hint -heapster_gen_block_perms_hint env "contains0" []; // Note that we could give specific block numbers here (e.g. [9]), but giving nothing will just add a hint to every block, which works just fine for this function. heapster_typecheck_fun env "contains0" "(len:bv 64).arg0:int64array, arg1:eq(llvmword(len)) -o arg0:int64array, arg1:true, ret:int64<>"; -// the new way using a gen perms hint -heapster_gen_block_perms_hint env "zero_array" []; heapster_typecheck_fun env "zero_array" "(len:bv 64).arg0:int64array, arg1:eq(llvmword(len)) -o arg0:int64array, arg1:true, ret:true"; -heapster_gen_block_perms_hint env "zero_array_from" []; heapster_typecheck_fun env "zero_array_from" "(len:bv 64, off:bv 64).arg0:int64array, arg1:eq(llvmword(len)), arg2:eq(llvmword(off)) -o arg0:int64array, arg1:true, ret:true"; -heapster_gen_block_perms_hint env "filter_and_sum_pos" []; heapster_join_point_hint env "filter_and_sum_pos" []; heapster_typecheck_fun env "filter_and_sum_pos" "(len:bv 64).arg0:int64array, arg1:eq(llvmword(len)) -o arg0:int64array, arg1:true, ret:int64<>"; -heapster_gen_block_perms_hint env "sum_2d" []; heapster_typecheck_fun env "sum_2d" "(l1:bv 64,l2:bv 64).arg0:array(0, array(0, exists z:bv 64.eq(llvmword(z))])]), arg1:eq(llvmword(l1)), arg2:eq(llvmword(l2)) -o arg0:array(0, array(0, exists z:bv 64.eq(llvmword(z))])]), arg1:true, arg2:true, ret:int64<>"; heapster_export_coq env "arrays_gen.v"; From f213fbdd859715be65e7a6af8fdd6114bb4bacc7 Mon Sep 17 00:00:00 2001 From: Eddy Westbrook Date: Wed, 15 Sep 2021 16:57:05 -0700 Subject: [PATCH 39/98] changed tupleTypeTrans to no longer having the trailing unit type on tuples of 2 or more types; updated foldList and unfoldList in the SAW core Prelude to fit this new approach; regenerated the resulting Coq files --- .../examples/iter_linked_list.sawcore | 18 +++--- heapster-saw/examples/rust_data.saw | 2 +- .../Verifier/SAW/Heapster/SAWTranslation.hs | 62 +++++++++---------- .../generated/CryptolToCoq/SAWCorePrelude.v | 30 +++++++-- saw-core/prelude/Prelude.sawcore | 18 +++--- 5 files changed, 76 insertions(+), 54 deletions(-) diff --git a/heapster-saw/examples/iter_linked_list.sawcore b/heapster-saw/examples/iter_linked_list.sawcore index 9a473ccbf3..fbb59e816b 100644 --- a/heapster-saw/examples/iter_linked_list.sawcore +++ b/heapster-saw/examples/iter_linked_list.sawcore @@ -27,20 +27,20 @@ ListF__rec : (a b:sort 0) -> (P : ListF a b -> sort 0) -> (l:ListF a b) -> P l; ListF__rec a b P f1 f2 l = ListF#rec a b P f1 f2 l; -unfoldListF : (a b:sort 0) -> ListF a b -> Either b (a * ListF a b * #()); +unfoldListF : (a b:sort 0) -> ListF a b -> Either b (a * ListF a b); unfoldListF a b l = - ListF__rec a b (\ (_:ListF a b) -> Either b (a * ListF a b * #())) - (\ (x:b) -> Left b (a * ListF a b * #()) x) - (\ (x:a) (l:ListF a b) (_:Either b (a * ListF a b * #())) -> - Right b (a * ListF a b * #()) (x, l, ())) + ListF__rec a b (\ (_:ListF a b) -> Either b (a * ListF a b)) + (\ (x:b) -> Left b (a * ListF a b) x) + (\ (x:a) (l:ListF a b) (_:Either b (a * ListF a b)) -> + Right b (a * ListF a b) (x, l)) l; -foldListF : (a b:sort 0) -> Either b (a * ListF a b * #()) -> ListF a b; +foldListF : (a b:sort 0) -> Either b (a * ListF a b) -> ListF a b; foldListF a b = - either b (a * ListF a b * #()) (ListF a b) + either b (a * ListF a b) (ListF a b) (\ (x : b) -> NilF a b x) - (\ (tup : (a * ListF a b * #())) -> - ConsF a b tup.(1) tup.(2).(1)); + (\ (tup : (a * ListF a b)) -> + ConsF a b tup.(1) tup.(2)); getListF : (a b:sort 0) -> ListF a b -> b; getListF a b = diff --git a/heapster-saw/examples/rust_data.saw b/heapster-saw/examples/rust_data.saw index 198164c2b7..4102e3c057 100644 --- a/heapster-saw/examples/rust_data.saw +++ b/heapster-saw/examples/rust_data.saw @@ -120,7 +120,7 @@ exchange_malloc_sym <- heapster_find_symbol env "15exchange_malloc"; heapster_assume_fun_rename env exchange_malloc_sym "exchange_malloc" "(len:bv 64).arg0:eq(llvmword(len)),arg1:true -o ret:memblock(W,0,len,emptysh)" "\\ (len:Vec 64 Bool) -> returnM #() ()"; // memcpy -heapster_assume_fun env "llvm.memcpy.p0i8.p0i8.i64" "(rw:rwmodality, l1:lifetime, l2:lifetime, sh:llvmshape 64, b:llvmblock 64, len:bv 64).arg0:[l1]memblock(W,0,len,sh), arg1:[l2]memblock(rw,0,len,eqsh(b)), arg2:eq(llvmword(len)) -o arg0:[l1]memblock(W,0,len,eqsh(b)), arg1:[l2]memblock(rw,0,len,eqsh(b))" "\\ (X:sort 0) (len:Vec 64 Bool) (x:X) (_:#()) -> returnM (#() * #() * #()) ((),(),())"; +heapster_assume_fun env "llvm.memcpy.p0i8.p0i8.i64" "(rw:rwmodality, l1:lifetime, l2:lifetime, sh:llvmshape 64, b:llvmblock 64, len:bv 64).arg0:[l1]memblock(W,0,len,sh), arg1:[l2]memblock(rw,0,len,eqsh(b)), arg2:eq(llvmword(len)) -o arg0:[l1]memblock(W,0,len,eqsh(b)), arg1:[l2]memblock(rw,0,len,eqsh(b))" "\\ (X:sort 0) (len:Vec 64 Bool) (x:X) (_:#()) -> returnM (#() * #()) ((),())"; // ::to_string to_string_str <- heapster_find_symbol env "$LT$str$u20$as$u20$alloc..string..ToString$GT$9to_string"; diff --git a/heapster-saw/src/Verifier/SAW/Heapster/SAWTranslation.hs b/heapster-saw/src/Verifier/SAW/Heapster/SAWTranslation.hs index 6aa65ebba9..3d1494f4b6 100644 --- a/heapster-saw/src/Verifier/SAW/Heapster/SAWTranslation.hs +++ b/heapster-saw/src/Verifier/SAW/Heapster/SAWTranslation.hs @@ -132,12 +132,32 @@ typeTransType1 (TypeTrans [] _) = unitTypeOpenTerm typeTransType1 (TypeTrans [tp] _) = tp typeTransType1 _ = error ("typeTransType1" ++ nlPrettyCallStack callStack) --- | Build the tuple of @N@ types, with the special case that a single type is --- just converted to itself +-- | Build the tuple type @T1 * (T2 * ... * (Tn-1 * Tn))@ of @n@ types, with the +-- special case that 0 types maps to the unit type @#()@ (and 1 type just maps +-- to itself). Note that this is different from 'tupleTypeOpenTerm', which +-- always ends with unit, i.e., which returns @T1*(T2*...*(Tn-1*(Tn*#())))@. tupleOfTypes :: [OpenTerm] -> OpenTerm tupleOfTypes [] = unitTypeOpenTerm tupleOfTypes [tp] = tp -tupleOfTypes tps = tupleTypeOpenTerm tps +tupleOfTypes (tp:tps) = pairTypeOpenTerm tp $ tupleOfTypes tps + +-- | Build the tuple @(t1,(t2,(...,(tn-1,tn))))@ of @n@ terms, with the +-- special case that 0 types maps to the unit value @()@ (and 1 value just maps +-- to itself). Note that this is different from 'tupleOpenTerm', which +-- always ends with unit, i.e., which returns @t1*(t2*...*(tn-1*(tn*())))@. +tupleOfTerms :: [OpenTerm] -> OpenTerm +tupleOfTerms [] = unitOpenTerm +tupleOfTerms [t] = t +tupleOfTerms (t:ts) = pairOpenTerm t $ tupleOfTerms ts + +-- | Project the @i@th element from a term of type @'tupleOfTypes' tps@. Note +-- that this requires knowing the length of @tps@. +projTupleOfTypes :: [OpenTerm] -> Integer -> OpenTerm -> OpenTerm +projTupleOfTypes [] _ _ = error "projTupleOfTypes: projection of empty tuple!" +projTupleOfTypes [_] 0 tup = tup +projTupleOfTypes (_:_) 0 tup = pairLeftOpenTerm tup +projTupleOfTypes (_:tps) i tup = + projTupleOfTypes tps (i-1) $ pairRightOpenTerm tup -- | Map the 'typeTransTypes' field of a 'TypeTrans' to a single type, where a -- single type is mapped to itself, an empty list of types is mapped to @unit@, @@ -145,14 +165,13 @@ tupleOfTypes tps = tupleTypeOpenTerm tps typeTransTupleType :: TypeTrans tr -> OpenTerm typeTransTupleType = tupleOfTypes . typeTransTypes --- | Convert a 'TypeTrans' over 0 or more types to one over 1 type, where 2 --- or more types are converted to a single tuple type +-- | Convert a 'TypeTrans' over 0 or more types to one over the one type +-- returned by 'tupleOfTypes' tupleTypeTrans :: TypeTrans tr -> TypeTrans tr --- tupleTypeTrans ttrans@(TypeTrans [] _) = ttrans -tupleTypeTrans ttrans@(TypeTrans [_] _) = ttrans tupleTypeTrans ttrans = - TypeTrans [tupleTypeOpenTerm $ typeTransTypes ttrans] - (\[t] -> typeTransF ttrans $ map (\i -> projTupleOpenTerm i t) $ + let tps = typeTransTypes ttrans in + TypeTrans [tupleOfTypes tps] + (\[t] -> typeTransF ttrans $ map (\i -> projTupleOfTypes tps i t) $ take (length $ typeTransTypes ttrans) [0..]) -- | Convert a 'TypeTrans' over 0 or more types to one over 1 type of the form @@ -219,7 +238,7 @@ class IsTermTrans tr where -- function returns an element of the type @'tupleTypeTrans' ttrans@. transTupleTerm :: IsTermTrans tr => tr -> OpenTerm transTupleTerm (transTerms -> [t]) = t -transTupleTerm tr = tupleOpenTerm $ transTerms tr +transTupleTerm tr = tupleOfTerms $ transTerms tr -- | Build a tuple of the terms contained in a translation. This is "strict" in -- that it always makes a tuple, even for a single type, unlike @@ -1520,9 +1539,8 @@ setLLVMArrayTransSlice arr_trans sub_arr_trans off_tm = [natOpenTerm w, len_tm, elem_tp, arr_tm, off_tm, len'_tm, sub_arr_tm] } -- | Weaken a monadic function of type @(T1*...*Tn) -> CompM(U1*...*Um)@ to one --- of type @(V*T1*...*Tn) -> CompM(V*U1*...*Um)@, where tuples of 2 or more --- types are right-nested and and in a unit type, i.e., have the form --- @(T1*(T2*(...*(Tn*#()))))@. +-- of type @(V*T1*...*Tn) -> CompM(V*U1*...*Um)@, @n@-ary tuple types are built +-- using 'tupleOfTypes' weakenMonadicFun1 :: OpenTerm -> [OpenTerm] -> [OpenTerm] -> OpenTerm -> OpenTerm weakenMonadicFun1 v ts us f = @@ -1539,13 +1557,6 @@ weakenMonadicFun1 v ts us f = [] -> lambdaOpenTerm "x" v $ \x -> applyOpenTerm f1 (pairOpenTerm x unitOpenTerm) - -- If ts = [t], form the term \ (x:V*(T*#())) -> f1 (x.(1),x.(2).(1)) to - -- coerce f1 from V*T -> CompM(V*Us) to type V*(T*#()) -> CompM(V*Us) - [t] -> - lambdaOpenTerm "x" (tupleTypeOpenTerm [v,t]) $ \x -> - applyOpenTerm f1 (pairOpenTerm - (pairLeftOpenTerm x) - (pairLeftOpenTerm $ pairRightOpenTerm x)) -- Otherwise, leave f1 unchanged _ -> f1 in @@ -1558,17 +1569,6 @@ weakenMonadicFun1 v ts us f = lambdaOpenTerm "x" (pairTypeOpenTerm v unitTypeOpenTerm) (\x -> applyOpenTermMulti (globalOpenTerm "Prelude.returnM") [v, pairLeftOpenTerm x])] - [u] -> - -- If us = [u], compose f2 with the term - -- \ (x:V*U) -> returnM (V*(U*#())) (x.(1), (x.(2),())) to coerce - -- from V*Us -> CompM (V*U) to V*Us -> CompM (V*(U*#())) - applyOpenTermMulti (globalOpenTerm "Prelude.composeM") - [tupleOfTypes (v:ts), pairTypeOpenTerm v u, tupleOfTypes [v,u], f2, - lambdaOpenTerm "x" (pairTypeOpenTerm v u) - (\x -> applyOpenTermMulti (globalOpenTerm "Prelude.returnM") - [tupleOfTypes [v,u], - pairOpenTerm (pairLeftOpenTerm x) - (pairOpenTerm (pairRightOpenTerm x) unitOpenTerm)])] -- Otherwise, leave f2 unchanged _ -> f2 diff --git a/saw-core-coq/coq/generated/CryptolToCoq/SAWCorePrelude.v b/saw-core-coq/coq/generated/CryptolToCoq/SAWCorePrelude.v index 8237878d58..cfcecfaac1 100644 --- a/saw-core-coq/coq/generated/CryptolToCoq/SAWCorePrelude.v +++ b/saw-core-coq/coq/generated/CryptolToCoq/SAWCorePrelude.v @@ -459,6 +459,10 @@ Axiom expByNat : forall (a : Type), a -> (a -> a -> a) -> a -> @SAWCoreScaffoldi (* Prelude.gen was skipped *) +Axiom head : forall (n : @SAWCoreScaffolding.Nat), forall (a : Type), @SAWCoreVectorsAsCoqVectors.Vec (@SAWCoreScaffolding.Succ n) a -> a . + +Axiom tail : forall (n : @SAWCoreScaffolding.Nat), forall (a : Type), @SAWCoreVectorsAsCoqVectors.Vec (@SAWCoreScaffolding.Succ n) a -> @SAWCoreVectorsAsCoqVectors.Vec n a . + (* Prelude.atWithDefault was skipped *) Definition sawAt : forall (n : @SAWCoreScaffolding.Nat), forall (a : Type), @SAWCoreVectorsAsCoqVectors.Vec n a -> @SAWCoreScaffolding.Nat -> a := @@ -830,11 +834,11 @@ Definition uncurrySigma : forall (a : Type), forall (b : a -> Type), forall (c : (* Prelude.List__rec was skipped *) -Definition unfoldList : forall (a : Type), @Datatypes.list a -> @Either unit (prod a (prod (@Datatypes.list a) unit)) := - fun (a : Type) (l : @Datatypes.list a) => @Datatypes.list_rect a (fun (_1 : @Datatypes.list a) => @Either unit (prod a (prod (@Datatypes.list a) unit))) (@Left unit (prod a (prod (@Datatypes.list a) unit)) tt) (fun (x : a) (l1 : @Datatypes.list a) (_1 : @Either unit (prod a (prod (@Datatypes.list a) unit))) => @Right unit (prod a (prod (@Datatypes.list a) unit)) (pair x (pair l1 tt))) l. +Definition unfoldList : forall (a : Type), @Datatypes.list a -> @Either unit (prod a (@Datatypes.list a)) := + fun (a : Type) (l : @Datatypes.list a) => @Datatypes.list_rect a (fun (_1 : @Datatypes.list a) => @Either unit (prod a (@Datatypes.list a))) (@Left unit (prod a (@Datatypes.list a)) tt) (fun (x : a) (l1 : @Datatypes.list a) (_1 : @Either unit (prod a (@Datatypes.list a))) => @Right unit (prod a (@Datatypes.list a)) (pair x l1)) l. -Definition foldList : forall (a : Type), @Either unit (prod a (prod (@Datatypes.list a) unit)) -> @Datatypes.list a := - fun (a : Type) => @either unit (prod a (prod (@Datatypes.list a) unit)) (@Datatypes.list a) (fun (_1 : unit) => @Datatypes.nil a) (fun (tup : prod a (prod (@Datatypes.list a) unit)) => @Datatypes.cons a (SAWCoreScaffolding.fst tup) (SAWCoreScaffolding.fst (SAWCoreScaffolding.snd tup))). +Definition foldList : forall (a : Type), @Either unit (prod a (@Datatypes.list a)) -> @Datatypes.list a := + fun (a : Type) => @either unit (prod a (@Datatypes.list a)) (@Datatypes.list a) (fun (_1 : unit) => @Datatypes.nil a) (fun (tup : prod a (@Datatypes.list a)) => @Datatypes.cons a (SAWCoreScaffolding.fst tup) (SAWCoreScaffolding.snd tup)). Inductive ListSort : Type := | LS_Nil : @ListSort @@ -1011,6 +1015,18 @@ Definition foldIRT : forall (As : @ListSort), forall (Ds : @IRTSubsts As), foral (* Prelude.bindM was skipped *) +Definition fmapM : forall (a : Type), forall (b : Type), (a -> b) -> CompM a -> CompM b := + fun (a : Type) (b : Type) (f : a -> b) (m : CompM a) => @bindM CompM _ a b m (fun (x : a) => @returnM CompM _ b (f x)). + +Definition applyM : forall (a : Type), forall (b : Type), CompM (a -> b) -> CompM a -> CompM b := + fun (a : Type) (b : Type) (f : CompM (a -> b)) (m : CompM a) => @bindM CompM _ (a -> b) b f (fun (f1 : a -> b) => @bindM CompM _ a b m (fun (x : a) => @returnM CompM _ b (f1 x))). + +Definition fmapM2 : forall (a : Type), forall (b : Type), forall (c : Type), (a -> b -> c) -> CompM a -> CompM b -> CompM c := + fun (a : Type) (b : Type) (c : Type) (f : a -> b -> c) (m1 : CompM a) (m2 : CompM b) => @applyM b c (@fmapM a (b -> c) f m1) m2. + +Definition fmapM3 : forall (a : Type), forall (b : Type), forall (c : Type), forall (d : Type), (a -> b -> c -> d) -> CompM a -> CompM b -> CompM c -> CompM d := + fun (a : Type) (b : Type) (c : Type) (d : Type) (f : a -> b -> c -> d) (m1 : CompM a) (m2 : CompM b) (m3 : CompM c) => @applyM c d (@fmapM2 a b (c -> d) f m1 m2) m3. + Definition composeM : forall (a : Type), forall (b : Type), forall (c : Type), (a -> CompM b) -> (b -> CompM c) -> a -> CompM c := fun (a : Type) (b : Type) (c : Type) (f : a -> CompM b) (g : b -> CompM c) (x : a) => @bindM CompM _ b c (f x) g. @@ -1020,6 +1036,12 @@ Definition tupleCompMFunBoth : forall (a : Type), forall (b : Type), forall (c : Definition tupleCompMFunOut : forall (a : Type), forall (b : Type), forall (c : Type), c -> (a -> CompM b) -> a -> CompM (prod c b) := fun (a : Type) (b : Type) (c : Type) (x : c) (f : a -> CompM b) (y : a) => @bindM CompM _ b (prod c b) (f y) (fun (z : b) => @returnM CompM _ (prod c b) (pair x z)). +Definition mapM : forall (a : Type), forall (b : Type), (a -> CompM b) -> forall (n : @SAWCoreScaffolding.Nat), @SAWCoreVectorsAsCoqVectors.Vec n a -> CompM (@SAWCoreVectorsAsCoqVectors.Vec n b) := + fun (a : Type) (b : Type) (f : a -> CompM b) => @Nat__rec (fun (n : @SAWCoreScaffolding.Nat) => @SAWCoreVectorsAsCoqVectors.Vec n a -> CompM (@SAWCoreVectorsAsCoqVectors.Vec n b)) (fun (_1 : @SAWCoreVectorsAsCoqVectors.Vec 0 a) => @returnM CompM _ (@SAWCoreVectorsAsCoqVectors.Vec 0 b) (@SAWCoreVectorsAsCoqVectors.EmptyVec b)) (fun (n : @SAWCoreScaffolding.Nat) (rec_f : @SAWCoreVectorsAsCoqVectors.Vec n a -> CompM (@SAWCoreVectorsAsCoqVectors.Vec n b)) (v : @SAWCoreVectorsAsCoqVectors.Vec (@SAWCoreScaffolding.Succ n) a) => @fmapM2 b (@SAWCoreVectorsAsCoqVectors.Vec n b) (@SAWCoreVectorsAsCoqVectors.Vec (@SAWCoreScaffolding.Succ n) b) (fun (hd : b) (tl : @SAWCoreVectorsAsCoqVectors.Vec n b) => @ConsVec b hd n tl) (f (@head n a v)) (rec_f (@tail n a v))). + +Definition mapBVVecM : forall (a : Type), forall (b : Type), (a -> CompM b) -> forall (n : @SAWCoreScaffolding.Nat), forall (len : @SAWCoreVectorsAsCoqVectors.Vec n (@SAWCoreScaffolding.Bool)), @BVVec n len a -> CompM (@BVVec n len b) := + fun (a : Type) (b : Type) (f : a -> CompM b) (n : @SAWCoreScaffolding.Nat) (len : @SAWCoreVectorsAsCoqVectors.Vec n (@SAWCoreScaffolding.Bool)) => @mapM a b f (@SAWCoreVectorsAsCoqVectors.bvToNat n len). + (* Prelude.errorM was skipped *) (* Prelude.fixM was skipped *) diff --git a/saw-core/prelude/Prelude.sawcore b/saw-core/prelude/Prelude.sawcore index 773c2693c0..ed8827b56a 100644 --- a/saw-core/prelude/Prelude.sawcore +++ b/saw-core/prelude/Prelude.sawcore @@ -1451,20 +1451,20 @@ List__rec : (l : List a) -> P l; List__rec a P f1 f2 l = List#rec a P f1 f2 l; -unfoldList : (a:sort 0) -> List a -> Either #() (a * List a * #()); +unfoldList : (a:sort 0) -> List a -> Either #() (a * List a); unfoldList a l = - List__rec a (\ (_:List a) -> Either #() (a * List a * #())) - (Left #() (a * List a * #()) ()) - (\ (x:a) (l:List a) (_:Either #() (a * List a * #())) -> - Right #() (a * List a * #()) (x, l, ())) + List__rec a (\ (_:List a) -> Either #() (a * List a)) + (Left #() (a * List a) ()) + (\ (x:a) (l:List a) (_:Either #() (a * List a)) -> + Right #() (a * List a) (x, l)) l; -foldList : (a:sort 0) -> Either #() (a * List a * #()) -> List a; +foldList : (a:sort 0) -> Either #() (a * List a) -> List a; foldList a = - either #() (a * List a * #()) (List a) + either #() (a * List a) (List a) (\ (_ : #()) -> Nil a) - (\ (tup : (a * List a * #())) -> - Cons a tup.(1) tup.(2).(1)); + (\ (tup : (a * List a)) -> + Cons a tup.(1) tup.(2)); -- A list of types, i.e. `List (sort 0)` if `List` was universe polymorphic data ListSort : sort 1 From fe25d919bc500af3e75787c806e4655eca6f1042 Mon Sep 17 00:00:00 2001 From: Eddy Westbrook Date: Wed, 15 Sep 2021 17:28:58 -0700 Subject: [PATCH 40/98] small tweak to the expression type-checker to type-check the bodies of existential shapes as arbitrary expressions --- heapster-saw/src/Verifier/SAW/Heapster/TypeChecker.hs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/heapster-saw/src/Verifier/SAW/Heapster/TypeChecker.hs b/heapster-saw/src/Verifier/SAW/Heapster/TypeChecker.hs index b0cb527e98..872509124f 100644 --- a/heapster-saw/src/Verifier/SAW/Heapster/TypeChecker.hs +++ b/heapster-saw/src/Verifier/SAW/Heapster/TypeChecker.hs @@ -421,7 +421,7 @@ tcLLVMShape (ExOrSh _ x y) = PExpr_OrShape <$> tcKExpr x <*> tcKExpr y tcLLVMShape (ExExSh _ var vartype sh) = do Some ktp'@KnownReprObj <- tcTypeKnown vartype fmap PExpr_ExShape $ mbM $ nu \z -> - withExprVar var (unKnownReprObj ktp') z (tcLLVMShape sh) + withExprVar var (unKnownReprObj ktp') z (tcKExpr sh) tcLLVMShape (ExSeqSh _ x y) = PExpr_SeqShape <$> tcKExpr x <*> tcKExpr y tcLLVMShape ExEmptySh{} = pure PExpr_EmptyShape tcLLVMShape (ExEqSh _ v) = PExpr_EqShape <$> tcKExpr v From eef2cbfe25bf29d67766e8da59e3bfac6d2b5e4f Mon Sep 17 00:00:00 2001 From: Eddy Westbrook Date: Thu, 16 Sep 2021 07:06:51 -0700 Subject: [PATCH 41/98] expanded the translation of Rust slices to allow multiple fields --- .../src/Verifier/SAW/Heapster/Permissions.hs | 17 ++++++- .../src/Verifier/SAW/Heapster/RustTypes.hs | 46 +++++++++++++------ 2 files changed, 46 insertions(+), 17 deletions(-) diff --git a/heapster-saw/src/Verifier/SAW/Heapster/Permissions.hs b/heapster-saw/src/Verifier/SAW/Heapster/Permissions.hs index fef7125da1..32717d5f28 100644 --- a/heapster-saw/src/Verifier/SAW/Heapster/Permissions.hs +++ b/heapster-saw/src/Verifier/SAW/Heapster/Permissions.hs @@ -3280,6 +3280,10 @@ llvmBlockEndOffset :: (1 <= w, KnownNat w) => LLVMBlockPerm w -> PermExpr (BVType w) llvmBlockEndOffset = bvRangeEnd . llvmBlockRange +-- | Return the length in bytes of an 'LLVMFieldShape' +llvmFieldShapeLength :: LLVMFieldShape w -> Integer +llvmFieldShapeLength (LLVMFieldShape p) = exprLLVMTypeBytes p + -- | Return the expression for the length of a shape if there is one llvmShapeLength :: (1 <= w, KnownNat w) => PermExpr (LLVMShapeType w) -> Maybe (PermExpr (BVType w)) @@ -3300,8 +3304,8 @@ llvmShapeLength (PExpr_EqShape _) = Nothing llvmShapeLength (PExpr_PtrShape _ _ sh) | LLVMShapeRepr w <- exprType sh = Just $ bvInt (intValue w `div` 8) | otherwise = Nothing -llvmShapeLength (PExpr_FieldShape (LLVMFieldShape p)) = - Just $ exprLLVMTypeBytesExpr p +llvmShapeLength (PExpr_FieldShape fsh) = + Just $ bvInt $ llvmFieldShapeLength fsh llvmShapeLength (PExpr_ArrayShape len _ _) = Just len llvmShapeLength (PExpr_SeqShape sh1 sh2) = liftA2 bvAdd (llvmShapeLength sh1) (llvmShapeLength sh2) @@ -3407,6 +3411,15 @@ llvmReadBlockOfShape sh llvmReadBlockOfShape _ = error "llvmReadBlockOfShape: shape without known length" +-- | Test if an LLVM shape is a sequence of field shapes, and if so, return that +-- sequence +matchLLVMFieldShapeSeq :: (1 <= w, KnownNat w) => PermExpr (LLVMShapeType w) -> + Maybe [LLVMFieldShape w] +matchLLVMFieldShapeSeq (PExpr_FieldShape fsh) = Just [fsh] +matchLLVMFieldShapeSeq (PExpr_SeqShape sh1 sh2) = + (++) <$> matchLLVMFieldShapeSeq sh1 <*> matchLLVMFieldShapeSeq sh2 +matchLLVMFieldShapeSeq _ = Nothing + -- | Add the given read/write and lifetime modalities to all top-level pointer -- shapes in a shape. Top-level here means we do not recurse inside pointer -- shapes, as pointer shape modalities also apply recursively to the contained diff --git a/heapster-saw/src/Verifier/SAW/Heapster/RustTypes.hs b/heapster-saw/src/Verifier/SAW/Heapster/RustTypes.hs index 267d4094bd..05910c3aae 100644 --- a/heapster-saw/src/Verifier/SAW/Heapster/RustTypes.hs +++ b/heapster-saw/src/Verifier/SAW/Heapster/RustTypes.hs @@ -54,6 +54,7 @@ import qualified Data.Binding.Hobbits.NameSet as NameSet import Language.Rust.Syntax import Language.Rust.Parser +import qualified Language.Rust.Pretty as RustPP import Language.Rust.Data.Ident (Ident(..), name) import Prettyprinter as PP @@ -125,6 +126,12 @@ lookupName :: String -> TypeRepr a -> RustConvM (Name a) lookupName str tp = lookupTypedName str >>= \n -> castTypedM "variable" tp n +-- | Build a 'PPInfo' structure for the names currently in scope +rsPPInfo :: RustConvM PPInfo +rsPPInfo = + foldr (\(str, Some (Typed _ n)) -> ppInfoAddExprName str n) emptyPPInfo <$> + rciCtx <$> ask + -- | The conversion of a context of Rust type and lifetime variables type RustCtx = RAssign (Product (Constant String) TypeRepr) @@ -372,13 +379,17 @@ instance RsConvert w [PathParameters Span] (Some TypedPermExprs) where instance RsConvert w (Ty Span) (PermExpr (LLVMShapeType w)) where rsConvert w (Slice tp _) = do sh <- rsConvert w tp - case sh of - PExpr_FieldShape fsh@(LLVMFieldShape p) -> + case matchLLVMFieldShapeSeq sh of + Just fshs -> return (PExpr_ExShape $ nu $ \n -> PExpr_ArrayShape (PExpr_Var n) - (fromIntegral $ exprLLVMTypeBytes p) - [fsh]) - _ -> fail "rsConvert: slices of compound types not yet supported" + (fromIntegral $ sum $ map llvmFieldShapeLength fshs) + fshs) + _ -> + rsPPInfo >>= \ppInfo -> + fail ("rsConvert: slices not yet supported of type: " + ++ show (RustPP.pretty tp) ++ " with translation:\n" + ++ renderDoc (permPretty ppInfo sh)) rsConvert _ (Rptr Nothing _ _ _) = fail "rsConvert: lifetimes must be supplied for reference types" rsConvert w (Rptr (Just rust_l) mut tp' _) = @@ -715,16 +726,17 @@ un3SomeFunPerm args ret (Some3FunPerm fun_perm) , Just Refl <- testEquality ret (funPermRet fun_perm) = return $ SomeFunPerm fun_perm un3SomeFunPerm args ret (Some3FunPerm fun_perm) = + rsPPInfo >>= \ppInfo -> fail $ renderDoc $ vsep [ pretty "Unexpected LLVM type for function permission:" - , permPretty emptyPPInfo fun_perm + , permPretty ppInfo fun_perm , pretty "Actual LLVM type of function:" - <+> PP.group (permPretty emptyPPInfo args) <+> pretty "=>" - <+> PP.group (permPretty emptyPPInfo ret) + <+> PP.group (permPretty ppInfo args) <+> pretty "=>" + <+> PP.group (permPretty ppInfo ret) , pretty "Expected LLVM type of function:" - <+> PP.group (permPretty emptyPPInfo (funPermArgs fun_perm)) + <+> PP.group (permPretty ppInfo (funPermArgs fun_perm)) <+> pretty "=>" - <+> PP.group (permPretty emptyPPInfo (funPermRet fun_perm)) ] + <+> PP.group (permPretty ppInfo (funPermRet fun_perm)) ] -- | This is the more general form of 'funPerm3FromArgLayout, where there can be -- ghost variables in the 'ArgLayout' @@ -919,9 +931,10 @@ layoutArgShapeByVal Rust (PExpr_PtrShape maybe_rw maybe_l sh) -- If we don't know the length of our pointer, we can't lay it out at all layoutArgShapeByVal Rust (PExpr_PtrShape _ _ sh) = + lift rsPPInfo >>= \ppInfo -> lift $ fail $ renderDoc $ fillSep [pretty "layoutArgShapeByVal: Shape with unknown length:", - permPretty emptyPPInfo sh] + permPretty ppInfo sh] -- A field shape --> the contents of the field layoutArgShapeByVal Rust (PExpr_FieldShape (LLVMFieldShape p)) = @@ -958,8 +971,9 @@ layoutArgShapeByVal Rust (PExpr_ExShape mb_sh) = existsArgLayout <$> mbM (fmap (layoutArgShapeByVal Rust) mb_sh) layoutArgShapeByVal Rust sh = + lift rsPPInfo >>= \ppInfo -> lift $ fail $ renderDoc $ fillSep - [pretty "layoutArgShapeByVal: Unsupported shape:", permPretty emptyPPInfo sh] + [pretty "layoutArgShapeByVal: Unsupported shape:", permPretty ppInfo sh] layoutArgShapeByVal abi _ = lift $ fail ("layoutArgShapeByVal: Unsupported ABI: " ++ show abi) @@ -975,9 +989,10 @@ layoutArgShapeOrBlock abi sh = Just layout -> return $ Right layout Nothing | Just bp <- shapeToBlock sh -> return $ Left bp _ -> + rsPPInfo >>= \ppInfo -> fail $ renderDoc $ fillSep [pretty "layoutArgShapeOrBlock: Could not layout shape with unknown size:", - permPretty emptyPPInfo sh] + permPretty ppInfo sh] -- | Compute the layout of an argument with the given shape as 1 or more -- register arguments of a function @@ -1087,10 +1102,11 @@ lownedPermsForLifetime l (perms :>: VarAndPerm x p) , not (NameSet.member l $ freeVars p) = lownedPermsForLifetime l perms lownedPermsForLifetime l (_ :>: vap) = + rsPPInfo >>= \ppInfo -> fail $ renderDoc $ fillSep [pretty "lownedPermsForLifetime: could not compute lowned permissions for " - <+> permPretty emptyPPInfo l <+> pretty "in:", - permPretty emptyPPInfo vap] + <+> permPretty ppInfo l <+> pretty "in:", + permPretty ppInfo vap] -- | Get the 'String' name defined by a 'LifetimeDef' lifetimeDefName :: LifetimeDef a -> String From 60bad84d4e91e21846e69e7b53903b676851dfd8 Mon Sep 17 00:00:00 2001 From: Eddy Westbrook Date: Thu, 16 Sep 2021 10:21:32 -0700 Subject: [PATCH 42/98] updated mbox proof script to work with the recent changes, though not all the mbox proofs work... --- heapster-saw/examples/mbox.saw | 2 +- heapster-saw/examples/mbox.sawcore | 18 +++++++++--------- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/heapster-saw/examples/mbox.saw b/heapster-saw/examples/mbox.saw index c92785b703..19844ce74b 100644 --- a/heapster-saw/examples/mbox.saw +++ b/heapster-saw/examples/mbox.saw @@ -43,7 +43,7 @@ heapster_define_perm env "boolean" " " "llvmptr 1" "exists x:bv 1.eq(llvmword(x) heapster_assume_fun env "llvm.objectsize.i64.p0i8" "().empty -o empty" "returnM #() ()"; -heapster_assume_fun env "__memcpy_chk" "(len:bv 64).arg0:byte_array,arg1:byte_array,arg2:eq(llvmword (len)) -o arg0:byte_array,arg1:byte_array" "\\ (len:Vec 64 Bool) (_ src : BVVec 64 len (Vec 8 Bool)) -> returnM (BVVec 64 len (Vec 8 Bool) * BVVec 64 len (Vec 8 Bool) * #()) (src, src, ())"; +heapster_assume_fun env "__memcpy_chk" "(len:bv 64).arg0:byte_array,arg1:byte_array,arg2:eq(llvmword (len)) -o arg0:byte_array,arg1:byte_array" "\\ (len:Vec 64 Bool) (_ src : BVVec 64 len (Vec 8 Bool)) -> returnM (BVVec 64 len (Vec 8 Bool) * BVVec 64 len (Vec 8 Bool)) (src, src)"; //------------------------------------------------------------------------------ diff --git a/heapster-saw/examples/mbox.sawcore b/heapster-saw/examples/mbox.sawcore index 1e260e6bd8..28b4106695 100644 --- a/heapster-saw/examples/mbox.sawcore +++ b/heapster-saw/examples/mbox.sawcore @@ -31,20 +31,20 @@ Mbox__rec : (P : Mbox -> sort 0) -> (m:Mbox) -> P m; Mbox__rec P f1 f2 m = Mbox#rec P f1 f2 m; -unfoldMbox : Mbox -> Either #() (Vec 64 Bool * Vec 64 Bool * Mbox * BVVec 64 bv64_128 (Vec 8 Bool) * #()); +unfoldMbox : Mbox -> Either #() (Vec 64 Bool * Vec 64 Bool * Mbox * BVVec 64 bv64_128 (Vec 8 Bool)); unfoldMbox m = - Mbox__rec (\ (_:Mbox) -> Either #() (Vec 64 Bool * Vec 64 Bool * Mbox * BVVec 64 bv64_128 (Vec 8 Bool) * #())) - (Left #() (Vec 64 Bool * Vec 64 Bool * Mbox * BVVec 64 bv64_128 (Vec 8 Bool) * #()) ()) - (\ (strt:Vec 64 Bool) (len:Vec 64 Bool) (m:Mbox) (_:Either #() (Vec 64 Bool * Vec 64 Bool * Mbox * BVVec 64 bv64_128 (Vec 8 Bool) * #())) (d:BVVec 64 bv64_128 (Vec 8 Bool)) -> - Right #() (Vec 64 Bool * Vec 64 Bool * Mbox * BVVec 64 bv64_128 (Vec 8 Bool) * #()) (strt, len, m, d, ())) + Mbox__rec (\ (_:Mbox) -> Either #() (Vec 64 Bool * Vec 64 Bool * Mbox * BVVec 64 bv64_128 (Vec 8 Bool))) + (Left #() (Vec 64 Bool * Vec 64 Bool * Mbox * BVVec 64 bv64_128 (Vec 8 Bool)) ()) + (\ (strt:Vec 64 Bool) (len:Vec 64 Bool) (m:Mbox) (_:Either #() (Vec 64 Bool * Vec 64 Bool * Mbox * BVVec 64 bv64_128 (Vec 8 Bool))) (d:BVVec 64 bv64_128 (Vec 8 Bool)) -> + Right #() (Vec 64 Bool * Vec 64 Bool * Mbox * BVVec 64 bv64_128 (Vec 8 Bool)) (strt, len, m, d)) m; -foldMbox : Either #() (Vec 64 Bool * Vec 64 Bool * Mbox * (BVVec 64 bv64_128 (Vec 8 Bool)) * #()) -> Mbox; +foldMbox : Either #() (Vec 64 Bool * Vec 64 Bool * Mbox * BVVec 64 bv64_128 (Vec 8 Bool)) -> Mbox; foldMbox = - either #() (Vec 64 Bool * Vec 64 Bool * Mbox * (BVVec 64 bv64_128 (Vec 8 Bool)) * #()) Mbox + either #() (Vec 64 Bool * Vec 64 Bool * Mbox * BVVec 64 bv64_128 (Vec 8 Bool)) Mbox (\ (_:#()) -> Mbox_nil) - (\ (tup : (Vec 64 Bool * Vec 64 Bool * Mbox * (BVVec 64 bv64_128 (Vec 8 Bool)) * #())) -> - Mbox_cons tup.1 tup.2 tup.3 tup.4); + (\ (tup : (Vec 64 Bool * Vec 64 Bool * Mbox * BVVec 64 bv64_128 (Vec 8 Bool))) -> + Mbox_cons tup.1 tup.2 tup.3 tup.(2).(2).(2)); {- getMbox : (a : sort 0) -> Mbox a -> a; From 13e6b2147957ecb7c8fc5ae5caf210b6bbe13981 Mon Sep 17 00:00:00 2001 From: Eddy Westbrook Date: Thu, 16 Sep 2021 10:21:50 -0700 Subject: [PATCH 43/98] started updating the mbox proofs, but I got stuck... --- heapster-saw/examples/mbox_proofs.v | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/heapster-saw/examples/mbox_proofs.v b/heapster-saw/examples/mbox_proofs.v index 9c6fa1f849..91585f930e 100644 --- a/heapster-saw/examples/mbox_proofs.v +++ b/heapster-saw/examples/mbox_proofs.v @@ -26,7 +26,7 @@ Definition unfoldMbox_nil : unfoldMbox Mbox_nil = Left _ _ tt := reflexivity _. Definition unfoldMbox_cons strt len m d : - unfoldMbox (Mbox_cons strt len m d) = Right _ _ (strt, (len, (m, (d, tt)))) := + unfoldMbox (Mbox_cons strt len m d) = Right _ _ (strt, (len, (m, d))) := reflexivity _. Ltac Mbox_destruct m m' := destruct m as [| ?strt ?len m' ?d]. @@ -40,7 +40,7 @@ Lemma refinesM_either_unfoldMbox_nil_l {C} f g (P : CompM C) : Proof. eauto. Qed. Lemma refinesM_either_unfoldMbox_cons_l {C} strt len m d f g (P : CompM C) : - g (strt, (len, (m, (d, tt)))) |= P -> + g (strt, (len, (m, d))) |= P -> SAWCorePrelude.either _ _ _ f g (unfoldMbox (Mbox_cons strt len m d)) |= P. Proof. eauto. Qed. @@ -196,9 +196,9 @@ Proof. (* Show Ltac Profile. Reset Ltac Profile. *) Time Qed. -Definition mbox_detach_spec : Mbox -> Mbox * (Mbox * unit) := - Mbox__rec _ (Mbox_nil, (Mbox_nil, tt)) - (fun strt len next _ d => (next, (Mbox_cons strt len Mbox_nil d, tt))). +Definition mbox_detach_spec : Mbox -> Mbox * Mbox := + Mbox__rec _ (Mbox_nil, Mbox_nil) + (fun strt len next _ d => (next, (Mbox_cons strt len Mbox_nil d))). Lemma mbox_detach_spec_ref : refinesFun mbox_detach (fun x => returnM (mbox_detach_spec x)). @@ -234,11 +234,11 @@ Definition mbox_len_spec : Mbox -> bitvector 64 := (fun strt len m rec d => bvAdd 64 rec len). Lemma mbox_len_spec_ref - : refinesFun mbox_len (fun m => returnM (m, (mbox_len_spec m, tt))). + : refinesFun mbox_len (fun m => returnM (m, mbox_len_spec m)). Proof. unfold mbox_len, mbox_len__tuple_fun. prove_refinement_match_letRecM_l. - - exact (fun m1 rec m2 => returnM (transMbox m1 m2, (bvAdd 64 rec (mbox_len_spec m2), tt))). + - exact (fun m1 rec m2 => returnM (transMbox m1 m2, bvAdd 64 rec (mbox_len_spec m2))). unfold mbox_len_spec. (* Set Ltac Profiling. *) time "mbox_len_spec_ref" prove_refinement. From e327986887a23d35bcb3f9111da1eee78e3e8c09 Mon Sep 17 00:00:00 2001 From: Eddy Westbrook Date: Thu, 16 Sep 2021 10:22:31 -0700 Subject: [PATCH 44/98] moved formatting-related types in the rust_data example to their own section --- heapster-saw/examples/rust_data.saw | 67 +++++++++++++++++++---------- 1 file changed, 45 insertions(+), 22 deletions(-) diff --git a/heapster-saw/examples/rust_data.saw b/heapster-saw/examples/rust_data.saw index 4102e3c057..e23b31b6b9 100644 --- a/heapster-saw/examples/rust_data.saw +++ b/heapster-saw/examples/rust_data.saw @@ -15,6 +15,9 @@ heapster_define_llvmshape env "u64" 64 "" "fieldsh(int64<>)"; heapster_define_llvmshape env "u32" 64 "" "fieldsh(32,int32<>)"; heapster_define_llvmshape env "u8" 64 "" "fieldsh(8,int8<>)"; +heapster_define_llvmshape env "usize" 64 "" "fieldsh(int64<>)"; +heapster_define_llvmshape env "char" 64 "" "fieldsh(32,int32<>)"; + // bool type heapster_define_llvmshape env "bool" 64 "" "fieldsh(1,int1<>)"; @@ -45,31 +48,14 @@ heapster_define_llvmshape env "String" 64 "" "exsh cap:bv 64. ptrsh(arraysh(cap, //heapster_define_recursive_perm env "ListPerm" "X:llvmshape 64, Xlen:bv 64, rw:rwmodality, l:lifetime" "llvmptr 64" ["[l]memblock(rw,0,Xlen + 16,List,X>)"] "\\ (X:sort 0) (_:Vec 64 Bool) -> List X" "\\ (X:sort 0) (_:Vec 64 Bool) -> foldListPermH X" "\\ (X:sort 0) (_:Vec 64 Bool) -> unfoldListPermH X"; heapster_define_rust_type env "pub enum List { Nil, Cons (X,Box>) }"; -// Void type; note that Heapster does not (yet?) support empty types, so instead -// we make this type opaque. Also, note that the ArgumentV1 structure contains -// referens to Void, so presumably they are just casts of other types...? +// The Rust Void type is really a general existential type; this is not directly +// representable in the Rust type system, but it is in Heapster! +//heapster_define_llvmshape env "Void" 64 "" "exsh T:llvmshape 64.T"; // -//heapster_define_rust_type env "pub enum Void {}"; +// Doh! Except the above looks like a dynamically-sized type to Heapster! So we +// instead just make Void an opaque type heapster_define_opaque_llvmshape env "Void" 64 "" "64" "#()"; -// fmt::Error type -heapster_define_rust_type_qual env "fmt" "pub struct Error { }"; - -// fmt::Result type -// FIXME: there seems to be some optimization in Rust that lays out fmt::Result as a 1-bit value -heapster_define_llvmshape env "fmt::Result" 64 "" "fieldsh(1,eq(llvmword(0))) orsh fieldsh(1,eq(llvmword(1)))"; -//heapster_define_rust_type_qual env "fmt" "pub enum Result { Ok (), Err (fmt::Error) }"; - -// fmt::Formatter type -heapster_define_opaque_llvmshape env "fmt::Formatter" 64 "" "64" "#()"; - -// fmt::ArgumentV1 type -//heapster_define_rust_type_qual env "fmt" "pub struct ArgumentV1<'a> { value: &'a Void, formatter: for <'b> fn(&'b Void, &'b mut fmt::Formatter) -> fmt::Result, }"; - -// fmt::Arguments type -//heapster_define_rust_type_qual env "fmt" "pub struct Arguments<'a> { pieces: &'a [&'a str], fmt: Option<&'a [fmt::Argument]>, args: &'a [fmt::ArgumentV1<'a>], }"; - - // List64 type heapster_define_rust_type env "pub enum List64 { Nil64, Cons64 (u64,Box) }"; @@ -110,6 +96,43 @@ heapster_define_rust_type env "pub enum List10 { List10_Head(X,Box> heapster_define_rust_type env "pub enum List20 { List20_Head(X,Box>), List20_0(X,Box>), List20_1(X,Box>), List20_2(X,Box>), List20_3(X,Box>), List20_4(X,Box>), List20_5(X,Box>), List20_6(X,Box>), List20_7(X,Box>), List20_8(X,Box>), List20_9(X,Box>), List20_10(X,Box>), List20_11(X,Box>), List20_12(X,Box>), List20_13(X,Box>), List20_14(X,Box>), List20_15(X,Box>), List20_16(X,Box>), List20_17(X,Box>), List20_18(X,Box>), List20_19(X,Box>), }"; +/*** + *** Rust Formatting Types + ***/ + +// fmt::Error type +heapster_define_rust_type_qual env "fmt" "pub struct Error { }"; + +// fmt::Result type +// FIXME: there seems to be some optimization in Rust that lays out fmt::Result as a 1-bit value +heapster_define_llvmshape env "fmt::Result" 64 "" "fieldsh(1,eq(llvmword(0))) orsh fieldsh(1,eq(llvmword(1)))"; +//heapster_define_rust_type_qual env "fmt" "pub enum Result { Ok (), Err (fmt::Error) }"; + +// fmt::Formatter type +heapster_define_opaque_llvmshape env "fmt::Formatter" 64 "" "64" "#()"; + +// fmt::Alignment type +heapster_define_rust_type_qual env "fmt" "pub enum Alignment { Left, Right, Center, Unknown,}"; + +// fmt::Count type +heapster_define_rust_type_qual env "fmt" "pub enum Count { Is(usize), Param(usize), NextParam, Implied,}"; + +// fmt::FormatSpec +heapster_define_rust_type_qual env "fmt" "pub struct FormatSpec { pub fill: char, pub align: fmt::Alignment, pub flags: u32, pub precision: fmt::Count, pub width: fmt::Count, }"; + +// fmt::Position +heapster_define_rust_type_qual env "fmt" "pub enum Position { Next, At(usize),}"; + +// fmt::Argument type +heapster_define_rust_type_qual env "fmt" "pub struct Argument { pub position: fmt::Position, pub format: fmt::FormatSpec,}"; + +// fmt::ArgumentV1 type +heapster_define_rust_type_qual env "fmt" "pub struct ArgumentV1<'a> { value: &'a Void, formatter: for <'b> fn(&'b Void, &'b mut fmt::Formatter) -> fmt::Result, }"; + +// fmt::Arguments type +//heapster_define_rust_type_qual env "fmt" "pub struct Arguments<'a> { pieces: &'a [&'a str], fmt: Option<&'a [fmt::Argument]>, args: &'a [fmt::ArgumentV1<'a>], }"; + + /*** *** Assumed Functions ***/ From 0eef2f02dcd845f1336ddc1ace5e701606c827a3 Mon Sep 17 00:00:00 2001 From: Eddy Westbrook Date: Thu, 16 Sep 2021 10:30:13 -0700 Subject: [PATCH 45/98] finished updating mbox proofs --- heapster-saw/examples/mbox_proofs.v | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/heapster-saw/examples/mbox_proofs.v b/heapster-saw/examples/mbox_proofs.v index 91585f930e..260d132663 100644 --- a/heapster-saw/examples/mbox_proofs.v +++ b/heapster-saw/examples/mbox_proofs.v @@ -246,7 +246,7 @@ Proof. (* Most of the remaining cases are taken care of with just bvAdd_id_l and bvAdd_id_r *) all: try rewrite bvAdd_id_r; try rewrite bvAdd_id_l; try reflexivity. (* The remaining case just needs a few more rewrites *) - - do 2 f_equal. + - f_equal. rewrite bvAdd_assoc; f_equal. rewrite bvAdd_comm; reflexivity. - cbn; rewrite transMbox_Mbox_nil_r; reflexivity. @@ -300,17 +300,17 @@ Definition conjSliceBVVec (strt len : bitvector 64) pf0 pf1 d0 d1 : BVVec 64 bv6 (* Given a `start`, `len`, and `dat` of a single Mbox, return an mbox chain consisting of a single mbox with `id` 0, the given `start` and `len`, and the given `dat` with the range 0 to `start` zeroed out. *) -Definition mbox_copy_spec_cons strt len m d : CompM (Mbox * (Mbox * unit)) := +Definition mbox_copy_spec_cons strt len m d : CompM (Mbox * Mbox) := assumingM (isBvslt 64 (intToBv 64 0) strt) (forallM (fun pf0 : isBvule 64 strt (intToBv 64 128) => (forallM (fun pf1 : isBvule 64 len (bvSub 64 (intToBv 64 128) strt) => returnM (Mbox_cons strt len m (conjSliceBVVec strt len pf0 pf1 d d), (Mbox_cons strt len Mbox_nil - (conjSliceBVVec strt len pf0 pf1 empty_mbox_d d), tt)))))). + (conjSliceBVVec strt len pf0 pf1 empty_mbox_d d))))))). -Definition mbox_copy_spec : Mbox -> CompM (Mbox * (Mbox * unit)) := - Mbox__rec (fun _ => CompM (Mbox * (Mbox * unit))) (returnM (Mbox_nil, (Mbox_nil, tt))) +Definition mbox_copy_spec : Mbox -> CompM (Mbox * Mbox) := + Mbox__rec (fun _ => CompM (Mbox * Mbox)) (returnM (Mbox_nil, Mbox_nil)) (fun strt len m _ d => mbox_copy_spec_cons strt len m d). Lemma mbox_copy_spec_ref : refinesFun mbox_copy mbox_copy_spec. From f01c8d80487b8134011c9ccc42a3d8c65004b491 Mon Sep 17 00:00:00 2001 From: Eddy Westbrook Date: Thu, 16 Sep 2021 15:51:08 -0700 Subject: [PATCH 46/98] generalized array permissions and array shapes to use shapes for their cells instead of lists of fields --- .../src/Verifier/SAW/Heapster/Permissions.hs | 523 ++++++------------ 1 file changed, 172 insertions(+), 351 deletions(-) diff --git a/heapster-saw/src/Verifier/SAW/Heapster/Permissions.hs b/heapster-saw/src/Verifier/SAW/Heapster/Permissions.hs index 32717d5f28..e33d4767e3 100644 --- a/heapster-saw/src/Verifier/SAW/Heapster/Permissions.hs +++ b/heapster-saw/src/Verifier/SAW/Heapster/Permissions.hs @@ -550,10 +550,13 @@ data PermExpr (a :: CrucibleType) where PExpr_FieldShape :: (1 <= w, KnownNat w) => LLVMFieldShape w -> PermExpr (LLVMShapeType w) - -- | A shape for an array with the given stride, length (in number of - -- elements = total length / stride), and fields + -- | A shape for an array of @len@ individual regions of memory, called "array + -- cells"; the size of each cell in bytes is given by the array stride, which + -- must be known statically, and each cell has shape given by the supplied + -- LLVM shape, also called the cell shape PExpr_ArrayShape :: (1 <= w, KnownNat w) => - PermExpr (BVType w) -> Bytes -> [LLVMFieldShape w] -> + PermExpr (BVType w) -> Bytes -> + PermExpr (LLVMShapeType w) -> PermExpr (LLVMShapeType w) -- | A sequence of two shapes @@ -812,8 +815,8 @@ instance Eq (PermExpr a) where (PExpr_FieldShape p1) == (PExpr_FieldShape p2) = p1 == p2 (PExpr_FieldShape _) == _ = False - (PExpr_ArrayShape len1 s1 flds1) == (PExpr_ArrayShape len2 s2 flds2) = - len1 == len2 && s1 == s2 && flds1 == flds2 + (PExpr_ArrayShape len1 s1 sh1) == (PExpr_ArrayShape len2 s2 sh2) = + len1 == len2 && s1 == s2 && sh1 == sh2 (PExpr_ArrayShape _ _ _) == _ = False (PExpr_SeqShape sh1 sh1') == (PExpr_SeqShape sh2 sh2') = @@ -880,12 +883,11 @@ instance PermPretty (PermExpr a) where return (l_pp <> pretty "ptrsh" <> parens (rw_pp <> sh_pp)) permPrettyM (PExpr_FieldShape fld) = (pretty "fieldsh" <>) <$> permPrettyM fld - permPrettyM (PExpr_ArrayShape len stride flds) = + permPrettyM (PExpr_ArrayShape len stride sh) = do len_pp <- permPrettyM len - flds_pp <- mapM permPrettyM flds + sh_pp <- permPrettyM sh let stride_pp = pretty (toInteger stride) - return (pretty "arraysh" <> tupled [len_pp, stride_pp, - ppEncList False flds_pp]) + return (pretty "arraysh" <> tupled [len_pp, stride_pp, sh_pp]) permPrettyM (PExpr_SeqShape sh1 sh2) = do pp1 <- permPrettyM sh1 pp2 <- permPrettyM sh2 @@ -1088,7 +1090,7 @@ bvCouldEqual _ _ = True -- when the right-hand side is 0 and 'True' in all other cases except constant -- expressions @k1 >= k2@. bvCouldBeLt :: PermExpr (BVType w) -> PermExpr (BVType w) -> Bool -bvCouldBeLt _ (PExpr_BV [] (BV.BV 0)) = False +bvCouldBeLt _ (PExpr_BV [] (BV.BV 0)) = False bvCouldBeLt e1 e2 | bvEq e1 e2 = False bvCouldBeLt (PExpr_BV [] (BV.BV k1)) (PExpr_BV [] (BV.BV k2)) = k1 < k2 bvCouldBeLt _ _ = True @@ -1612,7 +1614,7 @@ data LLVMFieldPerm w sz = LLVMFieldPerm { llvmFieldRW :: PermExpr RWModalityType, -- ^ Whether this is a read or write permission llvmFieldLifetime :: PermExpr LifetimeType, - -- ^ The lifetime during with this field permission is active + -- ^ The lifetime during which this field permission is active llvmFieldOffset :: PermExpr (BVType w), -- ^ The offset from the pointer in bytes of this field llvmFieldContents :: ValuePerm (LLVMPointerType sz) @@ -1626,58 +1628,36 @@ llvmFieldSize _ = knownNat -- | Helper type to represent byte offsets -- --- > 'machineWordBytes' * (stride * ix + fld_num) +-- > stride * ix + off -- --- from the beginning of an array permission. Such an expression refers to the --- array field @fld_num@, which must be a statically-known constant, in array --- cell @ix@. +-- from the beginning of an array permission. Such an expression refers to +-- offset @off@, which must be a statically-known constant, in array cell @ix@. data LLVMArrayIndex w = LLVMArrayIndex { llvmArrayIndexCell :: PermExpr (BVType w), - llvmArrayIndexFieldNum :: Int } + llvmArrayIndexOffset :: BV w } -- NOTE: we need a custom instance of Eq so we can use bvEq on the cell instance Eq (LLVMArrayIndex w) where LLVMArrayIndex e1 i1 == LLVMArrayIndex e2 i2 = bvEq e1 e2 && i1 == i2 --- | A single field in an array permission -data LLVMArrayField w = - forall sz. (1 <= sz, KnownNat sz) => LLVMArrayField (LLVMFieldPerm w sz) - -instance Eq (LLVMArrayField w) where - (LLVMArrayField fp1) == (LLVMArrayField fp2) - | Just Refl <- testEquality (llvmFieldSize fp1) (llvmFieldSize fp2) = - fp1 == fp2 - _ == _ = False - --- | Extract the offset from the field permission in an 'LLVMArrayField' -llvmArrayFieldOffset :: LLVMArrayField w -> PermExpr (BVType w) -llvmArrayFieldOffset (LLVMArrayField fp) = llvmFieldOffset fp - --- | Convert an 'LLVMArrayField' to an atomic permission -llvmArrayFieldToAtomicPerm :: (1 <= w, KnownNat w) => LLVMArrayField w -> - AtomicPerm (LLVMPointerType w) -llvmArrayFieldToAtomicPerm (LLVMArrayField fp) = Perm_LLVMField fp - --- | Get the length in bytes of an array field -llvmArrayFieldLen :: LLVMArrayField w -> Integer -llvmArrayFieldLen (LLVMArrayField fp) = intValue $ llvmFieldSize fp - --- | A permission to an array of repeated field permissions. An array permission --- is structured as zero or more cells, each of which are composed of one or --- more individual fields. The number of cells can be a dynamic expression, but --- the size in memory of each cell, called the /stride/ of the array, must be --- statically known and no less than the total size of the fields +-- | A permission to an array of @len@ individual regions of memory, called +-- "array cells". The size of each cell in bytes is given by the array /stride/, +-- which must be known statically, and each cell has shape given by the supplied +-- LLVM shape, also called the cell shape. data LLVMArrayPerm w = - LLVMArrayPerm { llvmArrayOffset :: PermExpr (BVType w), + LLVMArrayPerm { llvmArrayRW :: PermExpr RWModalityType, + -- ^ Whether this array gives read or write access + llvmArrayLifetime :: PermExpr LifetimeType, + -- ^ The lifetime during which this array permission is valid + llvmArrayOffset :: PermExpr (BVType w), -- ^ The offset from the pointer in bytes of this array llvmArrayLen :: PermExpr (BVType w), -- ^ The number of array blocks llvmArrayStride :: Bytes, -- ^ The array stride in bytes - llvmArrayFields :: [LLVMArrayField w], - -- ^ The fields in each element of this array; should have - -- length <= the stride + llvmArrayCellShape :: PermExpr (LLVMShapeType w), + -- ^ The shape of each cell in the array llvmArrayBorrows :: [LLVMArrayBorrow w] -- ^ Indices or index ranges that are missing from this array } @@ -1691,8 +1671,8 @@ llvmArrayStrideBits = toInteger . bytesToBits . llvmArrayStride -- -- FIXME: think about calling the just @LLVMArrayIndexSet@ data LLVMArrayBorrow w - = FieldBorrow (LLVMArrayIndex w) - -- ^ Borrow a specific field in a specific cell of an array permission + = FieldBorrow (PermExpr (BVType w)) + -- ^ Borrow a specific cell of an array permission | RangeBorrow (BVRange w) -- ^ Borrow a range of array cells, where each cell is 'llvmArrayStride' -- machine words long @@ -2648,20 +2628,19 @@ instance (1 <= w, KnownNat w, 1 <= sz, KnownNat sz) => PermPretty (LLVMFieldPerm w sz) where permPrettyM = permPrettyLLVMField False -instance KnownNat w => PermPretty (LLVMArrayField w) where - permPrettyM (LLVMArrayField fp) = permPrettyLLVMField True fp - instance (1 <= w, KnownNat w) => PermPretty (LLVMArrayPerm w) where permPrettyM (LLVMArrayPerm {..}) = - do pp_off <- permPrettyM llvmArrayOffset + do pp_l <- permPrettyLifetimePrefix llvmArrayLifetime + pp_rw <- permPrettyM llvmArrayRW + pp_off <- permPrettyM llvmArrayOffset pp_len <- permPrettyM llvmArrayLen let pp_stride = pretty (show llvmArrayStride) - pp_flds <- mapM permPrettyM llvmArrayFields + pp_sh <- permPrettyM llvmArrayCellShape pp_bs <- mapM permPrettyM llvmArrayBorrows - return $ PP.group (pretty "array" <> - ppEncList True [pp_off, pretty "<" <> pp_len, + return $ PP.group (pp_l <> pretty "array" <> + ppEncList True [pp_rw, pp_off, pretty "<" <> pp_len, pretty "*" <> pp_stride, - ppEncList False pp_flds, + pp_sh, ppEncList False pp_bs]) instance (1 <= w, KnownNat w) => PermPretty (LLVMBlockPerm w) where @@ -2757,10 +2736,7 @@ instance PermPretty (BVProp w) where <$> permPrettyM e1 <*> permPrettyM e2 <*> permPrettyM e3 instance PermPretty (LLVMArrayBorrow w) where - permPrettyM (FieldBorrow (LLVMArrayIndex ix fld_num)) = - do pp_ix <- permPrettyM ix - let pp_fld_num = pretty (show fld_num) - return (parens pp_ix <> pretty "." <> pp_fld_num) + permPrettyM (FieldBorrow ix) = permPrettyM ix permPrettyM (RangeBorrow rng) = permPrettyM rng instance PermPretty (VarAndPerm a) where @@ -2812,7 +2788,6 @@ $(mkNuMatching [t| forall w . LLVMArrayPerm w |]) $(mkNuMatching [t| forall w . LLVMBlockPerm w |]) $(mkNuMatching [t| RWModality |]) $(mkNuMatching [t| forall w . LLVMArrayIndex w |]) -$(mkNuMatching [t| forall w . LLVMArrayField w |]) $(mkNuMatching [t| forall w . LLVMArrayBorrow w |]) $(mkNuMatching [t| forall w . LLVMFieldShape w |]) $(mkNuMatching [t| forall w . LOwnedPerm w |]) @@ -3214,22 +3189,14 @@ llvmAtomicPermToBlock :: AtomicPerm (LLVMPointerType w) -> llvmAtomicPermToBlock (Perm_LLVMField fp) = Just $ llvmFieldPermToBlock fp llvmAtomicPermToBlock (Perm_LLVMArray ap) | [] <- llvmArrayBorrows ap - , LLVMArrayField fp : _ <- llvmArrayFields ap - , Just shs <- - mapM (\case - LLVMArrayField fp' - | llvmFieldRW fp == llvmFieldRW fp' - , llvmFieldLifetime fp == llvmFieldLifetime fp' -> - Just $ LLVMFieldShape (llvmFieldContents fp') - _ -> Nothing) - (llvmArrayFields ap) = Just $ LLVMBlockPerm - { llvmBlockRW = llvmFieldRW fp, - llvmBlockLifetime = llvmFieldLifetime fp, + { llvmBlockRW = llvmArrayRW ap, + llvmBlockLifetime = llvmArrayLifetime ap, llvmBlockOffset = llvmArrayOffset ap, - llvmBlockLen = llvmArrayLen ap, + llvmBlockLen = bvMult (llvmArrayStride ap) (llvmArrayLen ap), llvmBlockShape = - PExpr_ArrayShape (llvmArrayLen ap) (llvmArrayStride ap) shs } + PExpr_ArrayShape (llvmArrayLen ap) (llvmArrayStride ap) + (llvmArrayCellShape ap) } llvmAtomicPermToBlock (Perm_LLVMBlock bp) = Just bp llvmAtomicPermToBlock _ = Nothing @@ -3306,7 +3273,7 @@ llvmShapeLength (PExpr_PtrShape _ _ sh) | otherwise = Nothing llvmShapeLength (PExpr_FieldShape fsh) = Just $ bvInt $ llvmFieldShapeLength fsh -llvmShapeLength (PExpr_ArrayShape len _ _) = Just len +llvmShapeLength (PExpr_ArrayShape len stride _) = Just $ bvMult stride len llvmShapeLength (PExpr_SeqShape sh1 sh2) = liftA2 bvAdd (llvmShapeLength sh1) (llvmShapeLength sh2) llvmShapeLength (PExpr_OrShape sh1 sh2) = @@ -3325,34 +3292,19 @@ llvmShapeLength (PExpr_ExShape mb_sh) = partialSubst (emptyPSubst $ singletonCruCtx $ knownRepr) mb_len _ -> Nothing --- | Convert an 'LLVMFieldShape' inside (i.e., with all the other components of) --- a @memblock@ permission to an 'LLVMArrayField' and its length -llvmFieldShapePermToArrayField :: (1 <= w, KnownNat w) => PermExpr RWModalityType -> - PermExpr LifetimeType -> PermExpr (BVType w) -> - LLVMFieldShape w -> - (LLVMArrayField w, PermExpr (BVType w)) -llvmFieldShapePermToArrayField rw l off (LLVMFieldShape p) = - (LLVMArrayField (LLVMFieldPerm rw l off p), exprLLVMTypeBytesExpr p) - -- | Convert a @memblock@ permission with array shape to an array permission llvmArrayBlockToArrayPerm :: (1 <= w, KnownNat w) => LLVMBlockPerm w -> LLVMArrayPerm w llvmArrayBlockToArrayPerm bp - | PExpr_ArrayShape len stride fshs <- llvmBlockShape bp - , rw <- llvmBlockRW bp - , l <- llvmBlockLifetime bp = + | PExpr_ArrayShape len stride sh <- llvmBlockShape bp = LLVMArrayPerm - { llvmArrayOffset = llvmBlockOffset bp, + { llvmArrayRW = llvmBlockRW bp, + llvmArrayLifetime = llvmBlockLifetime bp, + llvmArrayOffset = llvmBlockOffset bp, llvmArrayLen = bvMult (toInteger stride) len, llvmArrayStride = stride, llvmArrayBorrows = [], - llvmArrayFields = - snd $ - foldl (\(off,flds) sh -> - let (fld, sz) = llvmFieldShapePermToArrayField rw l off sh in - (bvAdd off sz, flds ++ [fld])) - (bvInt 0, []) - fshs } + llvmArrayCellShape = sh } llvmArrayBlockToArrayPerm _ = error "llvmArrayBlockToArrayPerm: block perm not of array shape" @@ -3516,16 +3468,16 @@ splitLLVMBlockPerm _ (llvmBlockShape -> PExpr_NamedShape _ _ _ _) = Nothing splitLLVMBlockPerm _ (llvmBlockShape -> PExpr_EqShape _) = Nothing splitLLVMBlockPerm _ (llvmBlockShape -> PExpr_PtrShape _ _ _) = Nothing splitLLVMBlockPerm _ (llvmBlockShape -> PExpr_FieldShape _) = Nothing -splitLLVMBlockPerm off bp@(llvmBlockShape -> PExpr_ArrayShape len stride flds) +splitLLVMBlockPerm off bp@(llvmBlockShape -> PExpr_ArrayShape len stride sh) | Just (ix, BV.BV 0) <- bvMatchFactorPlusConst (bytesToInteger stride) (bvSub off $ llvmBlockOffset bp) , off_diff <- bvSub off (llvmBlockOffset bp) = Just (bp { llvmBlockLen = off_diff, - llvmBlockShape = PExpr_ArrayShape ix stride flds }, + llvmBlockShape = PExpr_ArrayShape ix stride sh }, bp { llvmBlockOffset = off, llvmBlockLen = bvSub (llvmBlockLen bp) off_diff, - llvmBlockShape = PExpr_ArrayShape (bvSub len ix) stride flds }) + llvmBlockShape = PExpr_ArrayShape (bvSub len ix) stride sh }) splitLLVMBlockPerm off bp@(llvmBlockShape -> PExpr_SeqShape sh1 sh2) | Just sh1_len <- llvmShapeLength sh1 , off_diff <- bvSub off (llvmBlockOffset bp) @@ -3672,12 +3624,20 @@ findTaggedUnionIndexForPerms off ps tag_un = -- | Convert an array cell number @cell@ to the byte offset for that cell, given --- by @stride * cell + field_num@ +-- by @stride * cell@ llvmArrayCellToOffset :: (1 <= w, KnownNat w) => LLVMArrayPerm w -> PermExpr (BVType w) -> PermExpr (BVType w) llvmArrayCellToOffset ap cell = bvMult (bytesToInteger $ llvmArrayStride ap) cell +-- | Convert an array cell number @cell@ to the "absolute" byte offset for that +-- cell, given by @off + stride * cell@, where @off@ is the offset of the +-- supplied array permission +llvmArrayCellToAbsOffset :: (1 <= w, KnownNat w) => LLVMArrayPerm w -> + PermExpr (BVType w) -> PermExpr (BVType w) +llvmArrayCellToAbsOffset ap cell = + bvAdd (llvmArrayOffset ap) (llvmArrayCellToOffset ap cell) + -- | Convert a range of cell numbers to a range of byte offsets from the -- beginning of the array permission llvmArrayCellsToOffsets :: (1 <= w, KnownNat w) => LLVMArrayPerm w -> @@ -3710,13 +3670,25 @@ bytesToMachineWords w n = (n + machineWordBytes w - 1) `div` machineWordBytes w prevMachineWord :: KnownNat w => f w -> Integer -> Integer prevMachineWord w n = (bytesToMachineWords w n - 1) * machineWordBytes w +-- | Build the @memblock@ permission that corresponds to a single cell of an +-- array permission +blockForLLVMArrayIndex :: (1 <= w, KnownNat w) => LLVMArrayPerm w -> + PermExpr (BVType w) -> LLVMBlockPerm w +blockForLLVMArrayIndex ap ix = + LLVMBlockPerm + { llvmBlockRW = llvmArrayRW ap, + llvmBlockLifetime = llvmArrayLifetime ap, + llvmBlockOffset = llvmArrayCellToAbsOffset ap ix, + llvmBlockLen = bvInt (toInteger $ llvmArrayStride ap), + llvmBlockShape = llvmArrayCellShape ap } + -- | Build the permission that corresponds to a borrow from an array, i.e., that -- would need to be returned in order to remove this borrow. For 'RangeBorrow's, -- that is the sub-array permission with no borrows of its own. permForLLVMArrayBorrow :: (1 <= w, KnownNat w) => LLVMArrayPerm w -> LLVMArrayBorrow w -> ValuePerm (LLVMPointerType w) permForLLVMArrayBorrow ap (FieldBorrow ix) = - ValPerm_Conj1 $ llvmArrayFieldToAtomicPerm $ llvmArrayFieldWithOffset ap ix + ValPerm_LLVMBlock $ blockForLLVMArrayIndex ap ix permForLLVMArrayBorrow ap (RangeBorrow (BVRange off len)) = ValPerm_Conj1 $ Perm_LLVMArray $ ap { llvmArrayOffset = llvmArrayCellToOffset ap off, @@ -3782,48 +3754,26 @@ llvmArrayBorrowsPermuteTo ap bs = -- be relative to an array with that many more cells added to the front cellOffsetLLVMArrayBorrow :: (1 <= w, KnownNat w) => PermExpr (BVType w) -> LLVMArrayBorrow w -> LLVMArrayBorrow w -cellOffsetLLVMArrayBorrow off (FieldBorrow (LLVMArrayIndex ix fld_num)) = - FieldBorrow (LLVMArrayIndex (bvAdd ix off) fld_num) +cellOffsetLLVMArrayBorrow off (FieldBorrow ix) = + FieldBorrow (bvAdd ix off) cellOffsetLLVMArrayBorrow off (RangeBorrow rng) = RangeBorrow $ offsetBVRange off rng --- | Convert an array permission into a field permission of the same size with a --- @true@ permission, if possible -llvmArrayToField :: (1 <= w, KnownNat w, 1 <= sz, KnownNat sz) => - NatRepr sz -> LLVMArrayPerm w -> Maybe (LLVMFieldPerm w sz) -llvmArrayToField sz ap - | LLVMArrayField fp : _ <- llvmArrayFields ap - , (rw,l) <- (llvmFieldRW fp, llvmFieldLifetime fp) - , all (\(LLVMArrayField fp') -> rw == llvmFieldRW fp' && - l == llvmFieldLifetime fp') - (llvmArrayFields ap) - , [] <- llvmArrayBorrows ap - , bvEq (bvMult (bytesToBits $ - llvmArrayStride ap) (llvmArrayLen ap)) (bvInt $ intValue sz) = - Just $ LLVMFieldPerm { llvmFieldRW = rw, llvmFieldLifetime = l, - llvmFieldOffset = llvmArrayOffset ap, - llvmFieldContents = ValPerm_True } -llvmArrayToField _ _ = Nothing - --- | Test if a byte offset @o@ statically aligns with a field in an array, i.e., --- whether +-- | Test if a byte offset @o@ statically aligns with a statically-known offset +-- into some array cell, i.e., whether -- --- > o - off = stride*ix + 'llvmFieldOffset' (fields !! fld_num) +-- > o - off = stride*ix + cell_off -- --- for some @ix@ and @fld_num@, where @off@ is the array offset, @stride@ is the --- array stride, and @fields@ is the array fields. Return @ix@ and @fld_num@ on +-- for some @ix@ and @cell_off@, where @off@ is the array offset and @stride@ is +-- the array stride. Return @ix@ and @cell_off@ as an 'LLVMArrayIndex' on -- success. -matchLLVMArrayField :: (1 <= w, KnownNat w) => LLVMArrayPerm w -> +matchLLVMArrayIndex :: (1 <= w, KnownNat w) => LLVMArrayPerm w -> PermExpr (BVType w) -> Maybe (LLVMArrayIndex w) -matchLLVMArrayField ap o - | rel_off <- bvSub o (llvmArrayOffset ap) = - do (ix, fld_off) <- +matchLLVMArrayIndex ap o = + do let rel_off = bvSub o (llvmArrayOffset ap) + (ix, cell_off) <- bvMatchFactorPlusConst (bytesToInteger $ llvmArrayStride ap) rel_off - fld_num <- - findIndex (\case LLVMArrayField fp -> - bvEq (llvmFieldOffset fp) (bvBV fld_off)) - (llvmArrayFields ap) - return $ LLVMArrayIndex ix fld_num + return $ LLVMArrayIndex ix cell_off -- | Return a list 'BVProp' stating that the field(s) represented by an array -- borrow are in the "base" set of fields in an array, before the borrows are @@ -3833,11 +3783,8 @@ matchLLVMArrayField ap o llvmArrayBorrowInArrayBase :: (1 <= w, KnownNat w) => LLVMArrayPerm w -> LLVMArrayBorrow w -> [BVProp w] -llvmArrayBorrowInArrayBase ap (FieldBorrow ix) - | llvmArrayIndexFieldNum ix >= length (llvmArrayFields ap) = - error "llvmArrayBorrowInArrayBase: invalid index" llvmArrayBorrowInArrayBase ap (FieldBorrow ix) = - [bvPropInRange (llvmArrayIndexCell ix) (llvmArrayCells ap)] + [bvPropInRange ix (llvmArrayCells ap)] llvmArrayBorrowInArrayBase ap (RangeBorrow rng) = bvPropRangeSubset rng (llvmArrayCells ap) @@ -3846,14 +3793,12 @@ llvmArrayBorrowInArrayBase ap (RangeBorrow rng) = -- statically distinct field numbers. llvmArrayBorrowsDisjoint :: (1 <= w, KnownNat w) => LLVMArrayBorrow w -> LLVMArrayBorrow w -> [BVProp w] -llvmArrayBorrowsDisjoint (FieldBorrow ix1) (FieldBorrow ix2) - | llvmArrayIndexFieldNum ix1 == llvmArrayIndexFieldNum ix2 - = [BVProp_Neq (llvmArrayIndexCell ix1) (llvmArrayIndexCell ix2)] -llvmArrayBorrowsDisjoint (FieldBorrow _) (FieldBorrow _) = [] +llvmArrayBorrowsDisjoint (FieldBorrow ix1) (FieldBorrow ix2) = + [BVProp_Neq ix1 ix2] llvmArrayBorrowsDisjoint (FieldBorrow ix) (RangeBorrow rng) = - [bvPropNotInRange (llvmArrayIndexCell ix) rng] + [bvPropNotInRange ix rng] llvmArrayBorrowsDisjoint (RangeBorrow rng) (FieldBorrow ix) = - [bvPropNotInRange (llvmArrayIndexCell ix) rng] + [bvPropNotInRange ix rng] llvmArrayBorrowsDisjoint (RangeBorrow rng1) (RangeBorrow rng2) = bvPropRangesDisjoint rng1 rng2 @@ -3870,7 +3815,8 @@ llvmArrayBorrowInArray ap b = -- | Shorthand for 'llvmArrayBorrowInArray' with a single index llvmArrayIndexInArray :: (1 <= w, KnownNat w) => LLVMArrayPerm w -> LLVMArrayIndex w -> [BVProp w] -llvmArrayIndexInArray ap ix = llvmArrayBorrowInArray ap (FieldBorrow ix) +llvmArrayIndexInArray ap ix = + llvmArrayBorrowInArray ap (FieldBorrow $ llvmArrayIndexCell ix) -- | Test if all cell numbers in a 'BVRange' are in an array permission and are -- not currently being borrowed @@ -3886,8 +3832,8 @@ llvmArrayIsOffsetArray :: (1 <= w, KnownNat w) => LLVMArrayPerm w -> LLVMArrayPerm w -> Maybe (PermExpr (BVType w)) llvmArrayIsOffsetArray ap1 ap2 | llvmArrayStride ap1 == llvmArrayStride ap2 - , Just (LLVMArrayIndex cell_num 0) <- - matchLLVMArrayField ap1 (llvmArrayOffset ap2) = Just cell_num + , Just (LLVMArrayIndex cell_num (BV.BV 0)) <- + matchLLVMArrayIndex ap1 (llvmArrayOffset ap2) = Just cell_num llvmArrayIsOffsetArray _ _ = Nothing -- | Build a 'BVRange' for the cells of a sub-array @ap2@ in @ap1@ @@ -3932,7 +3878,7 @@ llvmPermContainsOffset :: (1 <= w, KnownNat w) => PermExpr (BVType w) -> llvmPermContainsOffset off (Perm_LLVMField fp) | bvEq (llvmFieldOffset fp) off = Just [] llvmPermContainsOffset off (Perm_LLVMArray ap) - | Just ix <- matchLLVMArrayField ap off + | Just ix <- matchLLVMArrayIndex ap off , props <- llvmArrayIndexInArray ap ix , all bvPropCouldHold props = Just props @@ -3945,85 +3891,29 @@ llvmPermContainsOffset _ _ = Nothing -- | Return the total length of an LLVM array permission in bytes llvmArrayLengthBytes :: (1 <= w, KnownNat w) => LLVMArrayPerm w -> PermExpr (BVType w) -llvmArrayLengthBytes ap = - llvmArrayIndexByteOffset ap (LLVMArrayIndex (llvmArrayLen ap) 0) +llvmArrayLengthBytes ap = llvmArrayCellToAbsOffset ap (llvmArrayLen ap) -- | Return the byte offset of an array index from the beginning of the array llvmArrayIndexByteOffset :: (1 <= w, KnownNat w) => LLVMArrayPerm w -> LLVMArrayIndex w -> PermExpr (BVType w) -llvmArrayIndexByteOffset ap (LLVMArrayIndex cell fld_num) = - bvAdd (llvmArrayCellToOffset ap cell) - (llvmArrayFieldOffset (llvmArrayFields ap !! fld_num)) - --- | Return the field permission corresponding to the given index an array --- permission, offset by the array offset plus the byte offset of the field -llvmArrayFieldWithOffset :: (1 <= w, KnownNat w) => LLVMArrayPerm w -> - LLVMArrayIndex w -> LLVMArrayField w -llvmArrayFieldWithOffset ap ix = - if llvmArrayIndexFieldNum ix < length (llvmArrayFields ap) then - offsetLLVMArrayField - (bvAdd (llvmArrayOffset ap) (llvmArrayIndexByteOffset ap ix)) - (llvmArrayFields ap !! llvmArrayIndexFieldNum ix) - else - error "llvmArrayFieldWithOffset: index out of bounds" - --- | Get a list of all the fields in cell 0 of an array permission -llvmArrayHeadFields :: (1 <= w, KnownNat w) => LLVMArrayPerm w -> - [LLVMArrayField w] -llvmArrayHeadFields ap = - map (\i -> llvmArrayFieldWithOffset ap (LLVMArrayIndex (bvInt 0) i)) $ - [0 .. length (llvmArrayFields ap) - 1] - --- | Test if an array permission @ap@ is equivalent to a finite, --- statically-known list of field permissions. This is the case iff the array --- permission has a static constant length, in which case its field permissions --- are all of the permissions returned by 'llvmArrayFieldWithOffset' for array --- indices that are not borrowed in @ap@. --- --- In order to make the translation work, we also need there to be at least one --- complete array cell that is not borrowed. --- --- If all this is satisfied by @ap@, return the field permissions it is equal --- to, where those that comprise the un-borrowed cell are returned as the first --- element of the returned pair and the rest are the second. -llvmArrayAsFields :: (1 <= w, KnownNat w) => LLVMArrayPerm w -> - Maybe ([LLVMArrayField w], [LLVMArrayField w]) --- FIXME: this code is terrible! Simplify it! -llvmArrayAsFields ap - | Just len <- bvMatchConstInt (llvmArrayLen ap) - , Just cell <- - find (\i -> - not $ any (bvRangesCouldOverlap - (llvmArrayBorrowOffsets ap $ - RangeBorrow $ BVRange (bvInt i) $ bvInt 1) - . llvmArrayBorrowOffsets ap) $ llvmArrayBorrows ap) - [0 .. len-1] - , fld_nums <- [0 .. length (llvmArrayFields ap) - 1] - , all_ixs <- - concatMap (\cell' -> - map (LLVMArrayIndex $ bvInt cell') fld_nums) [0 .. len - 1] - = Just ( map (llvmArrayFieldWithOffset ap) $ - filter (bvEq (bvInt cell) . llvmArrayIndexCell) all_ixs - , map (llvmArrayFieldWithOffset ap) $ - filter (\ix -> - not (bvEq (bvInt cell) (llvmArrayIndexCell ix)) && - not (any (bvRangesCouldOverlap - (llvmArrayBorrowOffsets ap $ FieldBorrow ix) - . llvmArrayBorrowOffsets ap) $ llvmArrayBorrows ap)) - all_ixs) -llvmArrayAsFields _ = Nothing - --- | Map an offset to a borrow from an array, if possible -offsetToLLVMArrayBorrow :: (1 <= w, KnownNat w) => LLVMArrayPerm w -> - PermExpr (BVType w) -> Maybe (LLVMArrayBorrow w) -offsetToLLVMArrayBorrow ap off = FieldBorrow <$> matchLLVMArrayField ap off +llvmArrayIndexByteOffset ap (LLVMArrayIndex cell cell_off) = + bvAdd (llvmArrayCellToOffset ap cell) (bvBV cell_off) + +-- | Convert an array permission with a statically-known size @N@ to a list of +-- @memblock@ permissions for cells @0@ through @N-1@ +llvmArrayToBlocks :: (1 <= w, KnownNat w) => LLVMArrayPerm w -> + Maybe [LLVMBlockPerm w] +llvmArrayToBlocks ap + | Just len <- bvMatchConstInt $ llvmArrayLen ap = + Just $ map (blockForLLVMArrayIndex ap . bvInt) [0..len-1] +llvmArrayToBlocks _ = Nothing -- | Get the range of byte offsets represented by an array borrow relative to -- the beginning of the array permission llvmArrayBorrowOffsets :: (1 <= w, KnownNat w) => LLVMArrayPerm w -> LLVMArrayBorrow w -> BVRange w llvmArrayBorrowOffsets ap (FieldBorrow ix) = - bvRangeOfIndex $ llvmArrayIndexByteOffset ap ix + bvRangeOfIndex $ llvmArrayCellToAbsOffset ap ix llvmArrayBorrowOffsets ap (RangeBorrow r) = llvmArrayCellsToOffsets ap r -- | Get the range of byte offsets represented by an array borrow relative to @@ -4057,50 +3947,6 @@ llvmArrayPermDivide ap len = filter (not . borrow_in_first) (llvmArrayBorrows ap) }) -{- FIXME HERE: remove these...? - --- | Test if a specific range of byte offsets from the beginning of an array --- corresponds to a borrow already on an array -llvmArrayRangeIsBorrowed :: (1 <= w, KnownNat w) => - LLVMArrayPerm w -> BVRange w -> Bool -llvmArrayRangeIsBorrowed ap rng = - elem rng (map (llvmArrayBorrowOffsets ap) $ llvmArrayBorrows ap) - --- | Test if a specific array index and field number correspond to a borrow --- already on an array -llvmArrayIndexIsBorrowed :: (1 <= w, KnownNat w) => LLVMArrayPerm w -> - PermExpr (BVType w) -> Int -> Bool -llvmArrayIndexIsBorrowed ap ix fld_num = - llvmArrayRangeIsBorrowed ap $ llvmArrayIndexToRange ap ix fld_num - --- | Build 'BVProp's stating that each borrow in an array permission is disjoint --- from an index or range -llvmArrayBorrowsDisjoint :: (1 <= w, KnownNat w) => - LLVMArrayPerm w -> BVRange w -> [BVProp w] -llvmArrayBorrowsDisjoint ap range = - map (BVProp_RangesDisjoint range . llvmArrayBorrowOffsets ap) $ - llvmArrayBorrows ap - --- | Search through a list of atomic permissions to see if one of them is an --- LLVM array permission where the given field has been borrowed. If so, return --- the index of the array permission in the list, the array permission itself, --- and the index and field number of the field in the array -findLLVMArrayWithFieldBorrow :: (1 <= w, KnownNat w) => LLVMFieldPerm w -> - [AtomicPerm (LLVMPointerType w)] -> - Maybe (Int, LLVMArrayPerm w, - PermExpr (BVType w), Int) -findLLVMArrayWithFieldBorrow _ [] = Nothing -findLLVMArrayWithFieldBorrow fp (Perm_LLVMArray ap : _) - | Just (ix, fromInteger -> fld_num) <- - bvMatchFactorPlusConst (llvmArrayStride ap) - (bvSub (llvmFieldOffset fp) (llvmArrayOffset ap)) - , llvmArrayIndexIsBorrowed ap ix fld_num = - Just (0, ap, ix, fld_num) -findLLVMArrayWithFieldBorrow fp (_ : ps) = - fmap (\(i, ap, ix, fld_num) -> (i+1, ap, ix, fld_num)) $ - findLLVMArrayWithFieldBorrow fp ps --} - -- | Create a list of field permissions the cover @N@ bytes: -- -- > ptr((W,0) |-> true, (W,M) |-> true, (W,2*M) |-> true, @@ -4108,18 +3954,19 @@ findLLVMArrayWithFieldBorrow fp (_ : ps) = -- -- where @sz@ is the number of bytes allocated, @M@ is the machine word size in -- bytes, and @i@ is the greatest natural number such that @(i-1)*M < sz@ -llvmFieldsOfSize :: (1 <= w, KnownNat w) => f w -> Integer -> [LLVMArrayField w] +llvmFieldsOfSize :: (1 <= w, KnownNat w) => f w -> Integer -> + [AtomicPerm (LLVMPointerType w)] llvmFieldsOfSize (w :: f w) sz | sz_last_int <- 8 * (sz - prevMachineWord w sz) , Just (Some sz_last) <- someNat sz_last_int , Left LeqProof <- decideLeq (knownNat @1) sz_last = withKnownNat sz_last $ - map (\i -> LLVMArrayField $ + map (\i -> Perm_LLVMField $ (llvmFieldWrite0True @w) { llvmFieldOffset = bvInt (i * machineWordBytes w) }) [0 .. bytesToMachineWords w sz - 2] ++ - [LLVMArrayField $ + [Perm_LLVMField $ (llvmSizedFieldWrite0True w sz_last) { llvmFieldOffset = bvInt ((bytesToMachineWords w sz - 1) * machineWordBytes w) }] @@ -4129,8 +3976,13 @@ llvmFieldsOfSize (w :: f w) sz -- 'llvmFieldsOfSize' llvmFieldsPermOfSize :: (1 <= w, KnownNat w) => f w -> Integer -> ValuePerm (LLVMPointerType w) -llvmFieldsPermOfSize w n = - ValPerm_Conj $ map llvmArrayFieldToAtomicPerm $ llvmFieldsOfSize w n +llvmFieldsPermOfSize w n = ValPerm_Conj $ llvmFieldsOfSize w n + +-- | Create an LLVM shape for a single byte with @true@ permissions +llvmByteTrueShape :: (1 <= w, KnownNat w) => PermExpr (LLVMShapeType w) +llvmByteTrueShape = + PExpr_FieldShape $ LLVMFieldShape (ValPerm_True + :: ValuePerm (LLVMPointerType 8)) -- | Create an 'LLVMArrayPerm' for an array of uninitialized bytes llvmByteArrayArrayPerm :: (1 <= w, KnownNat w) => @@ -4138,18 +3990,10 @@ llvmByteArrayArrayPerm :: (1 <= w, KnownNat w) => PermExpr RWModalityType -> PermExpr LifetimeType -> LLVMArrayPerm w llvmByteArrayArrayPerm off len rw l = - LLVMArrayPerm { - llvmArrayOffset = off, - llvmArrayLen = len, - llvmArrayStride = 1, - llvmArrayFields = - [LLVMArrayField $ LLVMFieldPerm { - llvmFieldRW = rw, - llvmFieldLifetime = l, - llvmFieldOffset = bvInt 0, - llvmFieldContents = (ValPerm_True - :: ValuePerm (LLVMPointerType 8)) }], - llvmArrayBorrows = [] } + LLVMArrayPerm { llvmArrayRW = rw, llvmArrayLifetime = l, + llvmArrayOffset = off, llvmArrayLen = len, + llvmArrayStride = 1, llvmArrayCellShape = llvmByteTrueShape, + llvmArrayBorrows = [] } -- | Create a permission for an array of bytes llvmByteArrayPerm :: (1 <= w, KnownNat w) => @@ -4223,12 +4067,6 @@ offsetLLVMFieldPerm :: (1 <= w, KnownNat w) => PermExpr (BVType w) -> offsetLLVMFieldPerm off (LLVMFieldPerm {..}) = LLVMFieldPerm { llvmFieldOffset = bvAdd llvmFieldOffset off, ..} --- | Add an offset to an array field -offsetLLVMArrayField :: (1 <= w, KnownNat w) => PermExpr (BVType w) -> - LLVMArrayField w -> LLVMArrayField w -offsetLLVMArrayField off (LLVMArrayField fp) = - LLVMArrayField $ offsetLLVMFieldPerm off fp - -- | Add an offset to an array permission offsetLLVMArrayPerm :: (1 <= w, KnownNat w) => PermExpr (BVType w) -> LLVMArrayPerm w -> LLVMArrayPerm w @@ -4480,9 +4318,8 @@ atomicPermIsCopyable (Perm_LLVMField llvmFieldContents = p })) = permIsCopyable p atomicPermIsCopyable (Perm_LLVMField _) = False -atomicPermIsCopyable (Perm_LLVMArray - (LLVMArrayPerm { llvmArrayFields = fs })) = - all (atomicPermIsCopyable . llvmArrayFieldToAtomicPerm) fs +atomicPermIsCopyable (Perm_LLVMArray (LLVMArrayPerm {..})) = + llvmArrayRW == PExpr_Read && shapeIsCopyable llvmArrayRW llvmArrayCellShape atomicPermIsCopyable (Perm_LLVMBlock (LLVMBlockPerm {..})) = llvmBlockRW == PExpr_Read && shapeIsCopyable llvmBlockRW llvmBlockShape atomicPermIsCopyable (Perm_LLVMFree _) = True @@ -4536,8 +4373,7 @@ shapeIsCopyable rw (PExpr_PtrShape maybe_rw' _ sh) = let rw' = maybe rw id maybe_rw' in rw' == PExpr_Read && shapeIsCopyable rw' sh shapeIsCopyable _ (PExpr_FieldShape (LLVMFieldShape p)) = permIsCopyable p -shapeIsCopyable _ (PExpr_ArrayShape _ _ flds) = - all (\(LLVMFieldShape p) -> permIsCopyable p) flds +shapeIsCopyable rw (PExpr_ArrayShape _ _ sh) = shapeIsCopyable rw sh shapeIsCopyable rw (PExpr_SeqShape sh1 sh2) = shapeIsCopyable rw sh1 && shapeIsCopyable rw sh2 shapeIsCopyable rw (PExpr_OrShape sh1 sh2) = @@ -4695,8 +4531,8 @@ instance FreeVars (PermExpr a) where freeVars (PExpr_PtrShape maybe_rw maybe_l sh) = NameSet.unions [freeVars maybe_rw, freeVars maybe_l, freeVars sh] freeVars (PExpr_FieldShape fld) = freeVars fld - freeVars (PExpr_ArrayShape len _ flds) = - NameSet.union (freeVars len) (freeVars flds) + freeVars (PExpr_ArrayShape len _ sh) = + NameSet.union (freeVars len) (freeVars sh) freeVars (PExpr_SeqShape sh1 sh2) = NameSet.union (freeVars sh1) (freeVars sh2) freeVars (PExpr_OrShape sh1 sh2) = @@ -4763,14 +4599,13 @@ instance FreeVars (LLVMFieldPerm w sz) where NameSet.unions [freeVars llvmFieldRW, freeVars llvmFieldLifetime, freeVars llvmFieldOffset, freeVars llvmFieldContents] -instance FreeVars (LLVMArrayField w) where - freeVars (LLVMArrayField fp) = freeVars fp - instance FreeVars (LLVMArrayPerm w) where freeVars (LLVMArrayPerm {..}) = - NameSet.unions [freeVars llvmArrayOffset, + NameSet.unions [freeVars llvmArrayRW, + freeVars llvmArrayLifetime, + freeVars llvmArrayOffset, freeVars llvmArrayLen, - freeVars llvmArrayFields, + freeVars llvmArrayCellShape, freeVars llvmArrayBorrows] instance FreeVars (LLVMArrayIndex w) where @@ -4864,13 +4699,11 @@ instance NeededVars (LLVMFieldPerm w sz) where NameSet.unions [freeVars llvmFieldOffset, neededVars llvmFieldRW, neededVars llvmFieldLifetime, neededVars llvmFieldContents] -instance NeededVars (LLVMArrayField w) where - neededVars (LLVMArrayField fp) = neededVars fp - instance NeededVars (LLVMArrayPerm w) where neededVars (LLVMArrayPerm {..}) = - NameSet.unions [freeVars llvmArrayOffset, freeVars llvmArrayLen, - freeVars llvmArrayBorrows, neededVars llvmArrayFields] + NameSet.unions [neededVars llvmArrayRW, neededVars llvmArrayLifetime, + freeVars llvmArrayOffset, freeVars llvmArrayLen, + freeVars llvmArrayBorrows, neededVars llvmArrayCellShape] instance NeededVars (LLVMBlockPerm w) where neededVars (LLVMBlockPerm {..}) = @@ -4901,10 +4734,8 @@ readOnlyShape e@(PExpr_PtrShape _ (Just _) _) = e readOnlyShape (PExpr_PtrShape _ Nothing sh) = PExpr_PtrShape (Just PExpr_Read) Nothing $ readOnlyShape sh readOnlyShape e@(PExpr_FieldShape _) = e -readOnlyShape e@(PExpr_ArrayShape _ _ _) = - -- FIXME: when array shapes contain lists of shapes instead of lists of - -- permissions, this needs to map readOnlyShape to all of those shapes - e +readOnlyShape (PExpr_ArrayShape len stride sh) = + PExpr_ArrayShape len stride $ readOnlyShape sh readOnlyShape (PExpr_SeqShape sh1 sh2) = PExpr_SeqShape (readOnlyShape sh1) (readOnlyShape sh2) readOnlyShape (PExpr_OrShape sh1 sh2) = @@ -5087,9 +4918,9 @@ instance SubstVar s m => Substable s (PermExpr a) m where <*> genSubst s sh [nuMP| PExpr_FieldShape sh |] -> PExpr_FieldShape <$> genSubst s sh - [nuMP| PExpr_ArrayShape len stride flds |] -> + [nuMP| PExpr_ArrayShape len stride sh |] -> PExpr_ArrayShape <$> genSubst s len <*> return (mbLift stride) - <*> genSubst s flds + <*> genSubst s sh [nuMP| PExpr_SeqShape sh1 sh2 |] -> PExpr_SeqShape <$> genSubst s sh1 <*> genSubst s sh2 [nuMP| PExpr_OrShape sh1 sh2 |] -> @@ -5224,19 +5055,15 @@ instance SubstVar s m => Substable s (LLVMFieldPerm w sz) m where LLVMFieldPerm <$> genSubst s rw <*> genSubst s ls <*> genSubst s off <*> genSubst s p -instance SubstVar s m => Substable s (LLVMArrayField w) m where - genSubst s (mbMatch -> [nuMP| LLVMArrayField fp |]) = - LLVMArrayField <$> genSubst s fp - instance SubstVar s m => Substable s (LLVMArrayPerm w) m where - genSubst s (mbMatch -> [nuMP| LLVMArrayPerm off len stride pps bs |]) = - LLVMArrayPerm <$> genSubst s off <*> genSubst s len <*> - return (mbLift stride) <*> mapM (genSubst s) (mbList pps) - <*> mapM (genSubst s) (mbList bs) + genSubst s (mbMatch -> [nuMP| LLVMArrayPerm rw l off len stride sh bs |]) = + LLVMArrayPerm <$> genSubst s rw <*> genSubst s l <*> genSubst s off + <*> genSubst s len <*> return (mbLift stride) <*> genSubst s sh + <*> genSubst s bs instance SubstVar s m => Substable s (LLVMArrayIndex w) m where - genSubst s (mbMatch -> [nuMP| LLVMArrayIndex ix fld_num |]) = - LLVMArrayIndex <$> genSubst s ix <*> return (mbLift fld_num) + genSubst s (mbMatch -> [nuMP| LLVMArrayIndex ix off |]) = + LLVMArrayIndex <$> genSubst s ix <*> return (mbLift off) instance SubstVar s m => Substable s (LLVMArrayBorrow w) m where genSubst s mb_borrow = case mbMatch mb_borrow of @@ -5791,11 +5618,11 @@ instance AbstractVars (PermExpr a) where abstractPEVars ns1 ns2 (PExpr_FieldShape fsh) = absVarsReturnH ns1 ns2 ($(mkClosed [| PExpr_FieldShape |])) `clMbMbApplyM` abstractPEVars ns1 ns2 fsh - abstractPEVars ns1 ns2 (PExpr_ArrayShape len stride flds) = + abstractPEVars ns1 ns2 (PExpr_ArrayShape len stride sh) = absVarsReturnH ns1 ns2 ($(mkClosed [| flip PExpr_ArrayShape |]) `clApply` toClosed stride) `clMbMbApplyM` abstractPEVars ns1 ns2 len - `clMbMbApplyM` abstractPEVars ns1 ns2 flds + `clMbMbApplyM` abstractPEVars ns1 ns2 sh abstractPEVars ns1 ns2 (PExpr_SeqShape sh1 sh2) = absVarsReturnH ns1 ns2 $(mkClosed [| PExpr_SeqShape |]) `clMbMbApplyM` abstractPEVars ns1 ns2 sh1 @@ -5950,14 +5777,11 @@ instance AbstractVars (LLVMFieldPerm w sz) where `clMbMbApplyM` abstractPEVars ns1 ns2 off `clMbMbApplyM` abstractPEVars ns1 ns2 p -instance AbstractVars (LLVMArrayField w) where - abstractPEVars ns1 ns2 (LLVMArrayField fp) = - absVarsReturnH ns1 ns2 $(mkClosed [| LLVMArrayField |]) - `clMbMbApplyM` abstractPEVars ns1 ns2 fp - instance AbstractVars (LLVMArrayPerm w) where - abstractPEVars ns1 ns2 (LLVMArrayPerm off len str flds bs) = + abstractPEVars ns1 ns2 (LLVMArrayPerm rw l off len str flds bs) = absVarsReturnH ns1 ns2 $(mkClosed [| LLVMArrayPerm |]) + `clMbMbApplyM` abstractPEVars ns1 ns2 rw + `clMbMbApplyM` abstractPEVars ns1 ns2 l `clMbMbApplyM` abstractPEVars ns1 ns2 off `clMbMbApplyM` abstractPEVars ns1 ns2 len `clMbMbApplyM` abstractPEVars ns1 ns2 str @@ -5965,12 +5789,10 @@ instance AbstractVars (LLVMArrayPerm w) where `clMbMbApplyM` abstractPEVars ns1 ns2 bs instance AbstractVars (LLVMArrayIndex w) where - abstractPEVars ns1 ns2 (LLVMArrayIndex ix fld_num) = - absVarsReturnH ns1 ns2 $(mkClosed - [| \ix' fld_num' -> - LLVMArrayIndex ix' $ fromInteger fld_num' |]) + abstractPEVars ns1 ns2 (LLVMArrayIndex ix off) = + absVarsReturnH ns1 ns2 $(mkClosed [| LLVMArrayIndex |]) `clMbMbApplyM` abstractPEVars ns1 ns2 ix - `clMbMbApplyM` abstractPEVars ns1 ns2 (toInteger fld_num) + `clMbMbApplyM` abstractPEVars ns1 ns2 off instance AbstractVars (PermOffset a) where abstractPEVars ns1 ns2 NoPermOffset = @@ -6145,8 +5967,8 @@ instance AbstractNamedShape w (PermExpr a) where abstractNSM (PExpr_PtrShape rw l sh) = mbMap3 PExpr_PtrShape <$> abstractNSM rw <*> abstractNSM l <*> abstractNSM sh abstractNSM (PExpr_FieldShape fsh) = fmap PExpr_FieldShape <$> abstractNSM fsh - abstractNSM (PExpr_ArrayShape len s flds) = - mbMap3 PExpr_ArrayShape <$> abstractNSM len <*> pureBindingM s <*> abstractNSM flds + abstractNSM (PExpr_ArrayShape len s sh) = + mbMap3 PExpr_ArrayShape <$> abstractNSM len <*> pureBindingM s <*> abstractNSM sh abstractNSM (PExpr_SeqShape sh1 sh2) = mbMap2 PExpr_SeqShape <$> abstractNSM sh1 <*> abstractNSM sh2 abstractNSM (PExpr_OrShape sh1 sh2) = @@ -6202,18 +6024,19 @@ instance AbstractNamedShape w' (LLVMFieldPerm w sz) where mbMap4 LLVMFieldPerm <$> abstractNSM rw <*> abstractNSM l <*> abstractNSM off <*> abstractNSM p -instance AbstractNamedShape w' (LLVMArrayPerm w) where - abstractNSM (LLVMArrayPerm off len s pps bs) = - mbMap5 LLVMArrayPerm <$> abstractNSM off <*> abstractNSM len - <*> pureBindingM s <*> abstractNSM pps - <*> abstractNSM bs +-- | FIXME: move this to Hobbits? +mbApplyM :: Applicative m => m (Mb ctx (a -> b)) -> m (Mb ctx a) -> m (Mb ctx b) +mbApplyM f x = mbApply <$> f <*> x -instance AbstractNamedShape w' (LLVMArrayField w) where - abstractNSM (LLVMArrayField fp) = fmap LLVMArrayField <$> abstractNSM fp +instance AbstractNamedShape w' (LLVMArrayPerm w) where + abstractNSM (LLVMArrayPerm rw l off len stride sh bs) = + pureBindingM LLVMArrayPerm `mbApplyM` abstractNSM rw + `mbApplyM` abstractNSM l `mbApplyM` abstractNSM off + `mbApplyM` abstractNSM len `mbApplyM` pureBindingM stride + `mbApplyM` abstractNSM sh `mbApplyM` abstractNSM bs instance AbstractNamedShape w' (LLVMArrayBorrow w) where - abstractNSM (FieldBorrow (LLVMArrayIndex e i)) = - fmap (\e' -> FieldBorrow (LLVMArrayIndex e' i)) <$> abstractNSM e + abstractNSM (FieldBorrow ix) = fmap FieldBorrow <$> abstractNSM ix abstractNSM (RangeBorrow rng) = pureBindingM (RangeBorrow rng) instance AbstractNamedShape w' (LLVMBlockPerm w) where @@ -6739,15 +6562,14 @@ instance (1 <= w, KnownNat w, 1 <= sz, KnownNat sz) => getDetVarsClauses llvmFieldLifetime, getDetVarsClauses llvmFieldContents] -instance (1 <= w, KnownNat w) => GetDetVarsClauses (LLVMArrayField w) where - getDetVarsClauses (LLVMArrayField fp) = getDetVarsClauses fp - instance (1 <= w, KnownNat w) => GetDetVarsClauses (LLVMArrayPerm w) where getDetVarsClauses (LLVMArrayPerm {..}) = map (detVarsClauseAddLHS $ NameSet.unions [freeVars llvmArrayOffset, freeVars llvmArrayLen, - freeVars llvmArrayBorrows]) <$> - concat <$> mapM getDetVarsClauses llvmArrayFields + freeVars llvmArrayBorrows]) <$> concat <$> + sequence [getDetVarsClauses llvmArrayRW, + getDetVarsClauses llvmArrayLifetime, + getDetVarsClauses llvmArrayCellShape] instance (1 <= w, KnownNat w) => GetDetVarsClauses (LLVMBlockPerm w) where getDetVarsClauses (LLVMBlockPerm {..}) = @@ -6774,9 +6596,8 @@ getShapeDetVarsClauses (PExpr_PtrShape _ _ sh) = -- FIXME: maybe also include the variables determined by the modalities? getShapeDetVarsClauses sh getShapeDetVarsClauses (PExpr_FieldShape fldsh) = getDetVarsClauses fldsh -getShapeDetVarsClauses (PExpr_ArrayShape len _ fldshs) = - map (detVarsClauseAddLHS (freeVars len)) <$> - getDetVarsClauses fldshs +getShapeDetVarsClauses (PExpr_ArrayShape len _ sh) = + map (detVarsClauseAddLHS (freeVars len)) <$> getDetVarsClauses sh getShapeDetVarsClauses (PExpr_SeqShape sh1 sh2) | isJust $ llvmShapeLength sh1 = (++) <$> getDetVarsClauses sh1 <*> getDetVarsClauses sh2 From db7a74322128d0ca766c9f8d8903dbf0effb6232 Mon Sep 17 00:00:00 2001 From: Eddy Westbrook Date: Thu, 16 Sep 2021 16:03:44 -0700 Subject: [PATCH 47/98] updated examples to match the change to the SAW translation --- heapster-saw/examples/clearbufs.sawcore | 6 +++--- heapster-saw/examples/memcpy.saw | 2 +- heapster-saw/examples/rust_lifetimes.saw | 2 +- heapster-saw/examples/string_set.sawcore | 12 ++++++------ heapster-saw/examples/xor_swap_proofs.v | 4 ++-- 5 files changed, 13 insertions(+), 13 deletions(-) diff --git a/heapster-saw/examples/clearbufs.sawcore b/heapster-saw/examples/clearbufs.sawcore index b4d749c576..794f9a00bf 100644 --- a/heapster-saw/examples/clearbufs.sawcore +++ b/heapster-saw/examples/clearbufs.sawcore @@ -25,9 +25,9 @@ Mbox_def = Mbox; (m:Mbox) -> P m; Mbox__rec P f1 f2 m = Mbox#rec P f1 f2 m; -} ---unfoldMbox : Mbox -> Either #() (Mbox * Vec 64 Bool * BVVec 64 bv64_16 (Vec 64 Bool) * #()); +--unfoldMbox : Mbox -> Either #() (Mbox * Vec 64 Bool * BVVec 64 bv64_16 (Vec 64 Bool)); primitive -unfoldMbox : Mbox -> Either #() (Sigma (V64) (\ (len : V64) -> Mbox * BVVec 64 len (Vec 64 Bool) * #())); +unfoldMbox : Mbox -> Either #() (Sigma (V64) (\ (len : V64) -> Mbox * BVVec 64 len (Vec 64 Bool))); {-unfoldMbox m = Mbox__rec (\ (_:Mbox) -> Either #() (Mbox * Vec 64 Bool * BVVec 64 bv64_16 (Vec 64 Bool) * #())) @@ -38,7 +38,7 @@ unfoldMbox : Mbox -> Either #() (Sigma (V64) (\ (len : V64) -> Mbox * BVVec 64 l -} primitive -foldMbox : Either #() (Sigma (V64) (\ (len : V64) -> Mbox * BVVec 64 len (Vec 64 Bool) * #())) -> Mbox; +foldMbox : Either #() (Sigma (V64) (\ (len : V64) -> Mbox * BVVec 64 len (Vec 64 Bool))) -> Mbox; --(Mbox * Vec 64 Bool * (BVVec 64 bv64_16 (Vec 64 Bool)) * #()) -> Mbox; {- diff --git a/heapster-saw/examples/memcpy.saw b/heapster-saw/examples/memcpy.saw index e3193846bc..c5620066f8 100644 --- a/heapster-saw/examples/memcpy.saw +++ b/heapster-saw/examples/memcpy.saw @@ -3,7 +3,7 @@ env <- heapster_init_env_from_file "memcpy.sawcore" "memcpy.bc"; heapster_define_perm env "int64" " " "llvmptr 64" "exists x:bv 64.eq(llvmword(x))"; -heapster_assume_fun env "llvm.memcpy.p0i8.p0i8.i64" "(rw:rwmodality, l1:lifetime, l2:lifetime, sh:llvmshape 64, b:llvmblock 64, len:bv 64).arg0:[l1]memblock(W,0,len,sh), arg1:[l2]memblock(rw,0,len,eqsh(b)), arg2:eq(llvmword(len)) -o arg0:[l1]memblock(W,0,len,eqsh(b)), arg1:[l2]memblock(rw,0,len,eqsh(b))" "\\ (X:sort 0) (len:Vec 64 Bool) (x:X) (_:#()) -> returnM (#() * #() * #()) ((),(),())"; +heapster_assume_fun env "llvm.memcpy.p0i8.p0i8.i64" "(rw:rwmodality, l1:lifetime, l2:lifetime, sh:llvmshape 64, b:llvmblock 64, len:bv 64).arg0:[l1]memblock(W,0,len,sh), arg1:[l2]memblock(rw,0,len,eqsh(b)), arg2:eq(llvmword(len)) -o arg0:[l1]memblock(W,0,len,eqsh(b)), arg1:[l2]memblock(rw,0,len,eqsh(b))" "\\ (X:sort 0) (len:Vec 64 Bool) (x:X) (_:#()) -> returnM (#() * #()) ((),())"; heapster_typecheck_fun env "copy_int" "().arg0:int64<> -o ret:int64<>"; diff --git a/heapster-saw/examples/rust_lifetimes.saw b/heapster-saw/examples/rust_lifetimes.saw index fda06324e0..e30d5cfdbb 100644 --- a/heapster-saw/examples/rust_lifetimes.saw +++ b/heapster-saw/examples/rust_lifetimes.saw @@ -19,7 +19,7 @@ heapster_define_llvmshape env "u64" 64 "" "fieldsh(int64<>)"; ***/ // llvm.uadd.with.overflow.i64 -heapster_assume_fun env "llvm.uadd.with.overflow.i64" "().arg0:int64<>, arg1:int64<> -o ret:struct(int64<>,int1<>)" "\\ (x y:Vec 64 Bool) -> returnM (Vec 64 Bool * Vec 1 Bool * #()) (bvAdd 64 x y, gen 1 Bool (\\ (_:Nat) -> bvCarry 64 x y), ())"; +heapster_assume_fun env "llvm.uadd.with.overflow.i64" "().arg0:int64<>, arg1:int64<> -o ret:struct(int64<>,int1<>)" "\\ (x y:Vec 64 Bool) -> returnM (Vec 64 Bool * Vec 1 Bool) (bvAdd 64 x y, gen 1 Bool (\\ (_:Nat) -> bvCarry 64 x y))"; // llvm.expect.i1 heapster_assume_fun env "llvm.expect.i1" "().arg0:int1<>, arg1:int1<> -o ret:int1<>" "\\ (x y:Vec 1 Bool) -> returnM (Vec 1 Bool) x"; diff --git a/heapster-saw/examples/string_set.sawcore b/heapster-saw/examples/string_set.sawcore index eab0aa9e3a..ebb12ebe76 100644 --- a/heapster-saw/examples/string_set.sawcore +++ b/heapster-saw/examples/string_set.sawcore @@ -8,17 +8,17 @@ listInsertM a l s = returnM (List a) (Cons a s l); listRemoveM : (a : sort 0) -> (a -> a -> Bool) -> List a -> a -> - CompM (List a * a * #()); + CompM (List a * a); listRemoveM a test_eq l s = returnM - (List a * a * #()) + (List a * a) (List__rec a (\ (_:List a) -> List a) (Nil a) (\ (s':a) (_:List a) (rec:List a) -> ite (List a) (test_eq s s') rec (Cons a s' rec)) l, - s, ()); + s); ---------------------------------------------------------------------- -- Helper defs for Heapster examples @@ -30,14 +30,14 @@ stringListInsertM : List String -> String -> CompM (List String); stringListInsertM l s = returnM (List String) (Cons String s l); -stringListRemoveM : List String -> String -> CompM (stringList * String * #()); +stringListRemoveM : List String -> String -> CompM (stringList * String); stringListRemoveM l s = returnM - (stringList * String * #()) + (stringList * String) (List__rec String (\ (_:List String) -> List String) (Nil String) (\ (s':String) (_:List String) (rec:List String) -> ite (List String) (equalString s s') rec (Cons String s' rec)) l, - s, ()); + s); diff --git a/heapster-saw/examples/xor_swap_proofs.v b/heapster-saw/examples/xor_swap_proofs.v index f1eaeb38d9..2114d9ed90 100644 --- a/heapster-saw/examples/xor_swap_proofs.v +++ b/heapster-saw/examples/xor_swap_proofs.v @@ -13,8 +13,8 @@ Import xor_swap. Definition xor_swap_spec x1 x2 : - CompM (bitvector 64 * (bitvector 64 * unit)) := - returnM (x2, (x1, tt)). + CompM (bitvector 64 * bitvector 64) := + returnM (x2, x1). Arguments xor_swap_spec /. Lemma no_errors_xor_swap : refinesFun xor_swap (fun _ _ => noErrorsSpec). From 15b7d1948e17264f715a7a10f8dd15c06836e3f1 Mon Sep 17 00:00:00 2001 From: Eddy Westbrook Date: Thu, 16 Sep 2021 16:37:26 -0700 Subject: [PATCH 48/98] updated the IRT translation to match the updates to the SAW translation --- heapster-saw/src/Verifier/SAW/Heapster/IRTTranslation.hs | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/heapster-saw/src/Verifier/SAW/Heapster/IRTTranslation.hs b/heapster-saw/src/Verifier/SAW/Heapster/IRTTranslation.hs index 6fff2e599e..9602a78805 100644 --- a/heapster-saw/src/Verifier/SAW/Heapster/IRTTranslation.hs +++ b/heapster-saw/src/Verifier/SAW/Heapster/IRTTranslation.hs @@ -32,7 +32,6 @@ module Verifier.SAW.Heapster.IRTTranslation ( ) where import Numeric.Natural -import Data.Foldable import Data.Functor.Const import GHC.TypeLits import Control.Monad.Reader @@ -540,11 +539,10 @@ irtCtorOpenTerm c all_args = -- | Like 'tupleOfTypes' but with @IRT_prod@ irtProd :: [OpenTerm] -> IRTDescTransM ctx OpenTerm +irtProd [] = irtCtorOpenTerm "Prelude.IRT_unit" [] irtProd [x] = return x -irtProd xs = - do irtUnit <- irtCtorOpenTerm "Prelude.IRT_unit" [] - foldrM (\x xs' -> irtCtorOpenTerm "Prelude.IRT_prod" [x, xs']) - irtUnit xs +irtProd (x:xs) = + irtProd xs >>= \xs' -> irtCtorOpenTerm "Prelude.IRT_prod" [x, xs'] -- | A singleton list containing the result of 'irtCtorOpenTerm' irtCtor :: Ident -> [OpenTerm] -> IRTDescTransM ctx [OpenTerm] From 6fa6a47af30308a12bb458b3ddf90685f391c887 Mon Sep 17 00:00:00 2001 From: Eddy Westbrook Date: Mon, 20 Sep 2021 09:09:50 -0700 Subject: [PATCH 49/98] updated to use the new array permission with a shape for the cells --- .../Verifier/SAW/Heapster/LLVMGlobalConst.hs | 11 +--- .../src/Verifier/SAW/Heapster/RustTypes.hs | 55 ++++--------------- .../Verifier/SAW/Heapster/SAWTranslation.hs | 10 +--- .../src/Verifier/SAW/Heapster/UntypedAST.hs | 6 +- .../src/Verifier/SAW/Heapster/Widening.hs | 38 ++++++------- 5 files changed, 34 insertions(+), 86 deletions(-) diff --git a/heapster-saw/src/Verifier/SAW/Heapster/LLVMGlobalConst.hs b/heapster-saw/src/Verifier/SAW/Heapster/LLVMGlobalConst.hs index d739d24ce8..f43ede3746 100644 --- a/heapster-saw/src/Verifier/SAW/Heapster/LLVMGlobalConst.hs +++ b/heapster-saw/src/Verifier/SAW/Heapster/LLVMGlobalConst.hs @@ -87,16 +87,9 @@ translateLLVMValue w _ (L.ValSymbol sym) = return (PExpr_FieldShape (LLVMFieldShape p), t) translateLLVMValue w _ (L.ValArray tp elems) = do - -- First, translate the elements + -- First, translate the elements and their type ts <- map snd <$> mapM (translateLLVMValue w tp) elems - - -- Array shapes can only handle field shapes elements, so translate the - -- element type to and ensure it returns a field shape; FIXME: this could - -- actually handle sequences of field shapes if necessary (sh, saw_tp) <- translateLLVMType w tp - fsh <- case sh of - PExpr_FieldShape fsh -> return fsh - _ -> mzero -- Compute the array stride as the length of the element shape sh_len_expr <- lift $ llvmShapeLength sh @@ -108,7 +101,7 @@ translateLLVMValue w _ (L.ValArray tp elems) = (_,def_tm) <- translateLLVMValue w tp def_v -- Finally, build our array shape and SAW core value - return (PExpr_ArrayShape (bvInt $ fromIntegral $ length elems) sh_len [fsh], + return (PExpr_ArrayShape (bvInt $ fromIntegral $ length elems) sh_len sh, bvVecValueOpenTerm w saw_tp ts def_tm) translateLLVMValue w _ (L.ValPackedStruct elems) = mapM (translateLLVMTypedValue w) elems >>= \(unzip -> (shs,ts)) -> diff --git a/heapster-saw/src/Verifier/SAW/Heapster/RustTypes.hs b/heapster-saw/src/Verifier/SAW/Heapster/RustTypes.hs index 05910c3aae..10a5e05b75 100644 --- a/heapster-saw/src/Verifier/SAW/Heapster/RustTypes.hs +++ b/heapster-saw/src/Verifier/SAW/Heapster/RustTypes.hs @@ -240,40 +240,6 @@ namedShapeShapeFun w (SomeNamedShape nmsh) = pretty "Expected:" <+> pretty (intValue w), pretty "Actual:" <+> pretty (intValue (natRepr nmsh))] --- | A table for converting Rust base types to shapes -namedTypeTable :: (1 <= w, KnownNat w) => prx w -> [(String,SomeShapeFun w)] -namedTypeTable w = - [("bool", sizedIntShapeFun @_ @1 w Proxy), - ("i8", sizedIntShapeFun @_ @8 w Proxy), - ("u8", sizedIntShapeFun @_ @8 w Proxy), - ("i16", sizedIntShapeFun @_ @16 w Proxy), - ("u16", sizedIntShapeFun @_ @16 w Proxy), - ("i32", sizedIntShapeFun @_ @32 w Proxy), - ("u32", sizedIntShapeFun @_ @32 w Proxy), - ("i64", sizedIntShapeFun @_ @64 w Proxy), - ("u64", sizedIntShapeFun @_ @64 w Proxy), - - -- isize and usize are the same size as pointers, which is w - ("isize", sizedIntShapeFun w w), - ("usize", sizedIntShapeFun w w), - - -- Strings contain three fields: a pointer, a length, and a capacity - ("String", - constShapeFun (PExpr_ExShape $ nu $ \cap -> - (PExpr_SeqShape - -- The pointer to an array of bytes - (PExpr_PtrShape Nothing Nothing $ - PExpr_ArrayShape (PExpr_Var cap) 1 - [LLVMFieldShape $ ValPerm_Exists $ llvmExEqWord $ Proxy @8]) - (PExpr_SeqShape - -- The length value - (PExpr_FieldShape $ LLVMFieldShape $ - ValPerm_Exists $ llvmExEqWord w) - -- The capacity - (PExpr_FieldShape $ LLVMFieldShape $ ValPerm_Eq $ - PExpr_LLVMWord $ PExpr_Var cap))))) - ] - -- | A fully qualified Rust path without any of the parameters; e.g., -- @Foo::Bar::Baz@ just becomes @[Foo,Bar,Baz]@ newtype RustName = RustName [Ident] deriving (Eq) @@ -339,11 +305,12 @@ withRecType rust_n rust_ns rec_n = local (\info -> info { rciRecType = Just (rus -- the stride and the fields of the slice, where the latter can have the length -- free matchSliceShape :: PermExpr (LLVMShapeType w) -> - Maybe (Bytes, Binding (BVType w) [LLVMFieldShape w]) + Maybe (Bytes, + Binding (BVType w) (PermExpr (LLVMShapeType w))) matchSliceShape (PExpr_ExShape - [nuP| PExpr_ArrayShape (PExpr_Var len) stride fshs |]) + [nuP| PExpr_ArrayShape (PExpr_Var len) stride mb_sh |]) | Left Member_Base <- mbNameBoundP len = - Just (mbLift stride, fshs) + Just (mbLift stride, mb_sh) matchSliceShape (PExpr_NamedShape _ _ nmsh@(NamedShape _ _ (DefinedShapeBody _)) args) = matchSliceShape (unfoldNamedShape nmsh args) @@ -379,15 +346,13 @@ instance RsConvert w [PathParameters Span] (Some TypedPermExprs) where instance RsConvert w (Ty Span) (PermExpr (LLVMShapeType w)) where rsConvert w (Slice tp _) = do sh <- rsConvert w tp - case matchLLVMFieldShapeSeq sh of - Just fshs -> + case llvmShapeLength sh of + Just (bvMatchConstInt -> Just stride) -> return (PExpr_ExShape $ nu $ \n -> - PExpr_ArrayShape (PExpr_Var n) - (fromIntegral $ sum $ map llvmFieldShapeLength fshs) - fshs) + PExpr_ArrayShape (PExpr_Var n) (fromInteger stride) sh) _ -> rsPPInfo >>= \ppInfo -> - fail ("rsConvert: slices not yet supported of type: " + fail ("rsConvert: slices not supported for dynamically-sized type: " ++ show (RustPP.pretty tp) ++ " with translation:\n" ++ renderDoc (permPretty ppInfo sh)) rsConvert _ (Rptr Nothing _ _ _) = @@ -398,13 +363,13 @@ instance RsConvert w (Ty Span) (PermExpr (LLVMShapeType w)) where rw <- rsConvert w mut case sh of -- Test if sh is a slice type = an array of existential length - (matchSliceShape -> Just (stride,fshs)) -> + (matchSliceShape -> Just (stride,mb_sh)) -> -- If so, build a "fat pointer" = a pair of a pointer to our array -- shape plus a length value return $ PExpr_ExShape $ nu $ \n -> PExpr_SeqShape (PExpr_PtrShape rw Nothing $ PExpr_ArrayShape (PExpr_Var n) stride $ - subst1 (PExpr_Var n) fshs) + subst1 (PExpr_Var n) mb_sh) (PExpr_FieldShape $ LLVMFieldShape $ ValPerm_Eq $ PExpr_LLVMWord $ PExpr_Var n) diff --git a/heapster-saw/src/Verifier/SAW/Heapster/SAWTranslation.hs b/heapster-saw/src/Verifier/SAW/Heapster/SAWTranslation.hs index 3d1494f4b6..d0c8546427 100644 --- a/heapster-saw/src/Verifier/SAW/Heapster/SAWTranslation.hs +++ b/heapster-saw/src/Verifier/SAW/Heapster/SAWTranslation.hs @@ -2996,16 +2996,10 @@ translateSimplImpl (ps0 :: Proxy ps0) mb_simpl m = case mbMatch mb_simpl of m [nuMP| SImpl_ElimLLVMBlockField _ _ _ |] -> - do let mb_ps = fmap ((\case ValPerm_Conj ps -> ps - _ -> error "translateSimplImpl: SImpl_ElimLLVMBlockField, VPerm_Conj required" - ). distPermsHeadPerm . simplImplOut) mb_simpl - ttrans1 <- translate $ fmap (!!0) mb_ps - ttrans2 <- translate $ fmap (!!1) mb_ps + do ttrans <- translateSimplImplOutHead mb_simpl withPermStackM id (\(pctx :>: ptrans) -> - pctx :>: - PTrans_Conj [typeTransF (tupleTypeTrans ttrans1) [transTerm1 ptrans], - typeTransF ttrans2 [unitOpenTerm]]) + pctx :>: typeTransF ttrans [transTerm1 ptrans]) m [nuMP| SImpl_IntroLLVMBlockArray _ _ |] -> diff --git a/heapster-saw/src/Verifier/SAW/Heapster/UntypedAST.hs b/heapster-saw/src/Verifier/SAW/Heapster/UntypedAST.hs index 5716636ad2..b7d2a7962b 100644 --- a/heapster-saw/src/Verifier/SAW/Heapster/UntypedAST.hs +++ b/heapster-saw/src/Verifier/SAW/Heapster/UntypedAST.hs @@ -61,7 +61,7 @@ data AstExpr | ExExSh Pos String AstType AstExpr -- ^ existentially quantified shape | ExFieldSh Pos (Maybe AstExpr) AstExpr -- ^ field shape | ExPtrSh Pos (Maybe AstExpr) (Maybe AstExpr) AstExpr -- ^ pointer shape - | ExArraySh Pos AstExpr AstExpr [(Maybe AstExpr, AstExpr)] -- array shape + | ExArraySh Pos AstExpr AstExpr AstExpr -- array shape | ExEqual Pos AstExpr AstExpr -- ^ equal bitvector proposition | ExNotEqual Pos AstExpr AstExpr -- ^ not-equal bitvector proposition @@ -77,7 +77,7 @@ data AstExpr | ExPtr Pos (Maybe AstExpr) AstExpr AstExpr (Maybe AstExpr) AstExpr -- ^ pointer permission | ExMemblock Pos (Maybe AstExpr) AstExpr AstExpr AstExpr AstExpr -- ^ memblock permission | ExLlvmFunPtr Pos AstExpr AstExpr AstFunPerm -- ^ function pointer permission - | ExArray Pos AstExpr AstExpr AstExpr [ArrayPerm] -- array permission + | ExArray Pos (Maybe AstExpr) AstExpr AstExpr AstExpr AstExpr AstExpr -- array permission deriving Show -- | Returns outermost position @@ -116,7 +116,7 @@ instance HasPos AstExpr where pos (ExMemblock p _ _ _ _ _) = p pos (ExLlvmFunPtr p _ _ _ ) = p pos (ExLlvmFrame p _ ) = p - pos (ExArray p _ _ _ _ ) = p + pos (ExArray p _ _ _ _ _ _) = p pos (ExArraySh p _ _ _ ) = p -- | Returns outermost position diff --git a/heapster-saw/src/Verifier/SAW/Heapster/Widening.hs b/heapster-saw/src/Verifier/SAW/Heapster/Widening.hs index 449e4d0d03..ed69fe5a24 100644 --- a/heapster-saw/src/Verifier/SAW/Heapster/Widening.hs +++ b/heapster-saw/src/Verifier/SAW/Heapster/Widening.hs @@ -397,21 +397,11 @@ widenExpr' _ (PExpr_FieldShape (LLVMFieldShape p1)) (PExpr_FieldShape | Just Refl <- testEquality (exprLLVMTypeWidth p1) (exprLLVMTypeWidth p2) = PExpr_FieldShape <$> LLVMFieldShape <$> widenPerm knownRepr p1 p2 --- Array shapes can only be widened if they have the same length, stride, and --- fields whose ith fields have the same size for each i -widenExpr' _ (PExpr_ArrayShape len1 stride1 flds1) (PExpr_ArrayShape - len2 stride2 flds2) - | bvEq len1 len2 && stride1 == stride2 - , and (zipWith - (\(LLVMFieldShape p1) (LLVMFieldShape p2) -> - isJust $ testEquality (exprLLVMTypeWidth p1) (exprLLVMTypeWidth p2)) - flds1 flds2) = - PExpr_ArrayShape len1 stride1 <$> - zipWithM (\(LLVMFieldShape p1) (LLVMFieldShape p2) -> - case testEquality (exprLLVMTypeWidth p1) (exprLLVMTypeWidth p2) of - Just Refl -> LLVMFieldShape <$> widenPerm knownRepr p1 p2 - Nothing -> error "widenExpr: unreachable!") - flds1 flds2 +-- Array shapes can only be widened if they have the same length and stride +widenExpr' _ (PExpr_ArrayShape + len1 stride1 sh1) (PExpr_ArrayShape len2 stride2 sh2) + | bvEq len1 len2 && stride1 == stride2 = + PExpr_ArrayShape len1 stride1 <$> widenExpr sh1 sh2 -- FIXME: there should be some check that the first shapes have the same length, -- though this is more complex if they might have free variables...? @@ -548,16 +538,22 @@ widenAtomicPerms' tp (Perm_LLVMArray ap1 : ps1) ps2 = substEqVars wnmap (llvmArrayLen ap1) == substEqVars wnmap (llvmArrayLen ap2) && llvmArrayStride ap1 == llvmArrayStride ap2 && - substEqVars wnmap (llvmArrayFields ap1) - == substEqVars wnmap (llvmArrayFields ap2) + -- FIXME: widen the rw modalities? + substEqVars wnmap (llvmArrayRW ap1) + == substEqVars wnmap (llvmArrayRW ap2) && + substEqVars wnmap (llvmArrayLifetime ap1) + == substEqVars wnmap (llvmArrayLifetime ap2) && _ -> False) ps2 of Just i | Perm_LLVMArray ap2 <- ps2!!i -> -- NOTE: at this point, ap1 and ap2 are equal except for perhaps their - -- borrows, so we just filter out the borrows in ap1 that are also in ap2 - (Perm_LLVMArray (ap1 { llvmArrayBorrows = - filter (flip elem (llvmArrayBorrows ap2)) - (llvmArrayBorrows ap1) }) :) <$> + -- borrows and shapes, so we just filter out the borrows in ap1 that are + -- also in ap2 and widen the shapes + widen (llvmArrayCellShape ap1) (llvmArrayCellShape ap2) >>= \sh -> + (Perm_LLVMArray (ap1 { llvmArrayCellShape = sh, + llvmArrayBorrows = + filter (flip elem (llvmArrayBorrows ap2)) + (llvmArrayBorrows ap1) }) :) <$> widenAtomicPerms tp ps1 (deleteNth i ps2) _ -> -- We did not find an appropriate array on the RHS, so drop this one From c66a0c6ef1b07445dd1c8e6a8f87d729202ff580 Mon Sep 17 00:00:00 2001 From: Eddy Westbrook Date: Mon, 20 Sep 2021 09:14:58 -0700 Subject: [PATCH 50/98] started updating the permission implication prover with the new array permissions --- .../src/Verifier/SAW/Heapster/Implication.hs | 628 +++++++++--------- .../src/Verifier/SAW/Heapster/Permissions.hs | 136 ++-- 2 files changed, 401 insertions(+), 363 deletions(-) diff --git a/heapster-saw/src/Verifier/SAW/Heapster/Implication.hs b/heapster-saw/src/Verifier/SAW/Heapster/Implication.hs index 2ac3bd4d30..b95531805f 100644 --- a/heapster-saw/src/Verifier/SAW/Heapster/Implication.hs +++ b/heapster-saw/src/Verifier/SAW/Heapster/Implication.hs @@ -66,6 +66,17 @@ import Verifier.SAW.Heapster.GenMonad import GHC.Stack +{- +FIXME HERE NOW: +- ArrayShape and Perm_LLVMArray: flds -> sh +- llvmArrayFields -> llvmArrayCellShape +- rework LLVMArrayIndex: call number + offset +- matchLLVMArrayField -> matchLLVMArrayIndex +- remove LLVMArrayField +- remove borrows +- replace array rules with array shape rules +-} + ---------------------------------------------------------------------- -- * Equality Proofs ---------------------------------------------------------------------- @@ -650,9 +661,17 @@ data SimplImpl ps_in ps_out where ExprVar (LLVMPointerType w) -> LLVMArrayPerm w -> [LLVMArrayBorrow w] -> SimplImpl (RNil :> LLVMPointerType w) (RNil :> LLVMPointerType w) + -- | Prove an empty array with length 0: + -- + -- > -o x:array(off,<0,*stride,fps,[]) + SImpl_LLVMArrayEmpty :: + (1 <= w, KnownNat w) => + ExprVar (LLVMPointerType w) -> LLVMArrayPerm w -> + SimplImpl RNil (RNil :> LLVMPointerType w) + -- | Convert an array to a field of the same size with @true@ contents: -- - -- > x:array(off,<(sz/stride/8),*stride,fps,[]) -o x:[l]ptr((rw,off) |-> true) + -- > x:array(off,<(sz/stride/8),*stride,sh,[]) -o x:[l]ptr((rw,off) |-> true) -- -- where all @fps@ must have the same @rw@ and @l@ SImpl_LLVMArrayToField :: @@ -660,26 +679,16 @@ data SimplImpl ps_in ps_out where ExprVar (LLVMPointerType w) -> LLVMArrayPerm w -> NatRepr sz -> SimplImpl (RNil :> LLVMPointerType w) (RNil :> LLVMPointerType w) - -- | Prove an empty array with length 0: - -- - -- > -o x:array(off,<0,*stride,fps,[]) - SImpl_LLVMArrayEmpty :: - (1 <= w, KnownNat w) => - ExprVar (LLVMPointerType w) -> LLVMArrayPerm w -> - SimplImpl RNil (RNil :> LLVMPointerType w) - - -- | Prove an array of static length from from field permissions for a single - -- cell, leaving borrows for all the other cells: + -- | Prove an array of length 1 from a block of its same shape: -- - -- > x:fps+(cell*w*stride) - -- > -o x:array(off, x:[l]memblock(rw,off,stride,sh) -o x:[l]array(rw,off,<1,*stride,sh,[]) + SImpl_LLVMArrayFromBlock :: (1 <= w, KnownNat w) => - ExprVar (LLVMPointerType w) -> LLVMArrayPerm w -> + ExprVar (LLVMPointerType w) -> LLVMBlockPerm w -> SimplImpl (RNil :> LLVMPointerType w) (RNil :> LLVMPointerType w) - -- | Copy out the @j@th field permission of the @i@th element of an array - -- permission, assuming that the @j@th field permission is copyable, where @j@ + -- | Copy out the @i@th cell of an array + -- permission, assuming it is copyable, where @j@ -- is a static 'Int' and @i@ is an expression. Requires a proposition -- permission on the top of the stack stating that @i@ is in the range of the -- array and that the specified field permission does not overlap with any of @@ -723,15 +732,16 @@ data SimplImpl ps_in ps_out where SimplImpl (RNil :> LLVMPointerType w :> LLVMPointerType w) (RNil :> LLVMPointerType w) - -- | Apply an implication to the fields of an array permission: + -- | Apply an implication to the cell shape of an array permission: -- - -- > y:fp1 * ... * fpn -o y:fp1' * ... * fpn' - -- > ------------------------------------------------ - -- > x:array(off, x:array(off, y:[l]memblock(rw,0,stride,sh1) -o y:[l]memblock(rw,0,stride,sh2) + -- > ---------------------------------------------------------------- + -- > x:array(off, x:array(off, - ExprVar (LLVMPointerType w) -> LLVMArrayPerm w -> [LLVMArrayField w] -> + ExprVar (LLVMPointerType w) -> LLVMArrayPerm w -> + PermExpr (LLVMShapeType w) -> Binding (LLVMPointerType w) (LocalPermImpl (RNil :> LLVMPointerType w) (RNil :> LLVMPointerType w)) -> @@ -947,43 +957,37 @@ data SimplImpl ps_in ps_out where SimplImpl (RNil :> LLVMPointerType w :> LLVMBlockType w) (RNil :> LLVMPointerType w) - -- | Prove an llvmblock permission of pointer shape from a pointer: + -- | Prove an llvmblock permission of pointer shape from one of field shape + -- containing a pointer permission: -- - -- > x:[l]ptr((rw,off,w) |-> [l2]memblock(rw2,off,'llvmShapeLength'(sh),sh)) + -- > x:[l]memblock(rw,off,w/8,fieldsh([l2]memblock(rw2,0,sh_len,sh))) -- > -o x:[l]memblock(rw,off,w/8,[l2]ptrsh(rw2,sh)) SImpl_IntroLLVMBlockPtr :: - (1 <= w, KnownNat w) => ExprVar (LLVMPointerType w) -> - Maybe (PermExpr RWModalityType) -> Maybe (PermExpr LifetimeType) -> - LLVMBlockPerm w -> + (1 <= w, KnownNat w) => ExprVar (LLVMPointerType w) -> LLVMBlockPerm w -> SimplImpl (RNil :> LLVMPointerType w) (RNil :> LLVMPointerType w) -- | Eliminate an llvmblock permission of pointer shape: -- -- > x:[l]memblock(rw,off,w/8,[l2]ptrsh(rw2,sh)) - -- > -o x:[l]ptr((rw,off,w) |-> - -- > [l2]memblock(rw2,off,'llvmShapeLength'(sh),sh)) + -- > -o x:[l]memblock(rw,off,w/8,fieldsh([l2]memblock(rw2,0,sh_len,sh))) SImpl_ElimLLVMBlockPtr :: - (1 <= w, KnownNat w) => ExprVar (LLVMPointerType w) -> - Maybe (PermExpr RWModalityType) -> Maybe (PermExpr LifetimeType) -> - LLVMBlockPerm w -> + (1 <= w, KnownNat w) => ExprVar (LLVMPointerType w) -> LLVMBlockPerm w -> SimplImpl (RNil :> LLVMPointerType w) (RNil :> LLVMPointerType w) -- | Prove a block of field shape from the corresponding field permission: -- - -- > x:[l]ptr((rw,off,sz) |-> p) -o x:memblock(rw,l,off,len+sz,ptrsh(sz,p)) + -- > x:[l]ptr((rw,off,sz) |-> p) -o x:memblock(rw,l,off,len+sz,fieldsh(sz,p)) SImpl_IntroLLVMBlockField :: (1 <= w, KnownNat w, 1 <= sz, KnownNat sz) => ExprVar (LLVMPointerType w) -> LLVMFieldPerm w sz -> SimplImpl (RNil :> LLVMPointerType w) (RNil :> LLVMPointerType w) -- | Eliminate a block of field shape to the corresponding field permission - -- plus an empty memblock for the remaining @len@, which is the extra arg: -- - -- > x:[l]memblock(rw,off,len,fieldsh(sz,p)) - -- > -o x:[l]ptr((rw,off,sz) |-> p) * [l]memblock(rw,off+sz,len-sz,emptysh) + -- > x:[l]memblock(rw,off,sz/8,fieldsh(sz,p)) -o x:[l]ptr((rw,off,sz) |-> p) SImpl_ElimLLVMBlockField :: (1 <= w, KnownNat w, 1 <= sz, KnownNat sz) => - ExprVar (LLVMPointerType w) -> LLVMFieldPerm w sz -> PermExpr (BVType w) -> + ExprVar (LLVMPointerType w) -> LLVMFieldPerm w sz -> SimplImpl (RNil :> LLVMPointerType w) (RNil :> LLVMPointerType w) -- | Prove a block of array shape from the corresponding array permission: @@ -1660,11 +1664,8 @@ simplImplIn (SImpl_LLVMArrayEmpty _ ap) = else error "simplImplIn: SImpl_LLVMArrayEmpty: malformed empty array permission" -simplImplIn (SImpl_LLVMArrayOneCell x ap) = - case llvmArrayAsFields ap of - Just (flds, []) -> - distPerms1 x (ValPerm_Conj $ map llvmArrayFieldToAtomicPerm flds) - _ -> error "simplImplIn: SImpl_LLVMArrayOneCell: unexpected form of array permission" +simplImplIn (SImpl_LLVMArrayFromBlock x bp) = + distPerms1 x $ ValPerm_LLVMBlock bp simplImplIn (SImpl_LLVMArrayIndexCopy x ap ix) = if llvmArrayIndexFieldNum ix < length (llvmArrayFields ap) && @@ -1762,25 +1763,14 @@ simplImplIn (SImpl_IntroLLVMBlockFromEq x bp y) = distPerms2 x (ValPerm_Conj1 $ Perm_LLVMBlock $ bp { llvmBlockShape = PExpr_EqShape $ PExpr_Var y }) y (ValPerm_Conj1 $ Perm_LLVMBlockShape $ llvmBlockShape bp) -simplImplIn (SImpl_IntroLLVMBlockPtr x maybe_rw2 maybe_l2 bp) = - if llvmShapeLength (llvmBlockShape bp) == Just (llvmBlockLen bp) then - distPerms1 x (llvmBlockPtrPerm $ - llvmBlockAdjustModalities maybe_rw2 maybe_l2 bp) - else - error "simplImplIn: SImpl_IntroLLVMBlockPtr: incorrect length" -simplImplIn (SImpl_ElimLLVMBlockPtr x maybe_rw2 maybe_l2 bp) = - if llvmShapeLength (llvmBlockShape bp) == Just (llvmBlockLen bp) then - distPerms1 x (ValPerm_Conj1 $ Perm_LLVMBlock $ - bp { llvmBlockLen = bvInt (machineWordBytes bp), - llvmBlockShape = - PExpr_PtrShape maybe_rw2 maybe_l2 (llvmBlockShape bp) }) - else - error "simplImplIn: SImpl_ElimLLVMBlockPtr: incorrect length" +simplImplIn (SImpl_IntroLLVMBlockPtr x bp) = + distPerms1 x $ ValPerm_LLVMBlock $ llvmBlockPtrShapeUnfold bp +simplImplIn (SImpl_ElimLLVMBlockPtr x bp) = + distPerms1 x bp simplImplIn (SImpl_IntroLLVMBlockField x fp) = distPerms1 x (ValPerm_Conj1 $ Perm_LLVMField fp) -simplImplIn (SImpl_ElimLLVMBlockField x fp len) = - distPerms1 x (ValPerm_Conj1 $ Perm_LLVMBlock $ - (llvmFieldPermToBlock fp) { llvmBlockLen = len }) +simplImplIn (SImpl_ElimLLVMBlockField x fp) = + distPerms1 x (ValPerm_Conj1 $ Perm_LLVMBlock $ llvmFieldPermToBlock fp) simplImplIn (SImpl_IntroLLVMBlockArray x ap) = distPerms1 x (ValPerm_Conj1 $ Perm_LLVMArray ap) simplImplIn (SImpl_ElimLLVMBlockArray x ap) = @@ -1975,11 +1965,10 @@ simplImplOut (SImpl_LLVMArrayEmpty x ap) = else error "simplImplOut: SImpl_LLVMArrayEmpty: malformed empty array permission" -simplImplOut (SImpl_LLVMArrayOneCell x ap) = - case llvmArrayAsFields ap of - Just (_, []) -> - distPerms1 x (ValPerm_Conj1 $ Perm_LLVMArray ap) - _ -> error "simplImplOut: SImpl_LLVMArrayOneCell: unexpected form of array permission" +simplImplIn (SImpl_LLVMArrayFromBlock x bp) = + case llvmBlockPermToArray1 bp of + Just ap -> distPerms1 x $ ValPerm_LLVMArray ap + _ -> error "simplImplOut: SImpl_LLVMArrayOneCell: block perm with non-static length" simplImplOut (SImpl_LLVMArrayIndexCopy x ap ix) = if llvmArrayIndexFieldNum ix < length (llvmArrayFields ap) && @@ -2007,8 +1996,8 @@ simplImplOut (SImpl_LLVMArrayIndexReturn x ap ix) = else error "simplImplOut: SImpl_LLVMArrayIndexReturn: index not being borrowed" -simplImplOut (SImpl_LLVMArrayContents x ap flds _) = - distPerms1 x (ValPerm_Conj [Perm_LLVMArray $ ap { llvmArrayFields = flds }]) +simplImplOut (SImpl_LLVMArrayContents x ap sh _) = + distPerms1 x (ValPerm_Conj [Perm_LLVMArray $ ap { llvmArrayCellShape = sh }]) simplImplOut (SImpl_LLVMFieldIsPtr x fp) = distPerms2 x (ValPerm_Conj1 Perm_IsLLVMPtr) @@ -2089,31 +2078,14 @@ simplImplOut (SImpl_ElimLLVMBlockNamed x bp nmsh) = _ -> error "simplImplOut: SImpl_ElimLLVMBlockNamed: unexpected block shape" simplImplOut (SImpl_IntroLLVMBlockFromEq x bp _) = distPerms1 x (ValPerm_Conj1 $ Perm_LLVMBlock bp) -simplImplOut (SImpl_IntroLLVMBlockPtr x maybe_rw2 maybe_l2 bp) = - if llvmShapeLength (llvmBlockShape bp) == Just (llvmBlockLen bp) then - distPerms1 x (ValPerm_Conj1 $ Perm_LLVMBlock $ - bp { llvmBlockLen = bvInt (machineWordBytes bp), - llvmBlockShape = - PExpr_PtrShape maybe_rw2 maybe_l2 (llvmBlockShape bp) }) - else - error "simplImplOut: SImpl_IntroLLVMBlockPtr: incorrect length" -simplImplOut (SImpl_ElimLLVMBlockPtr x maybe_rw2 maybe_l2 bp) = - if llvmShapeLength (llvmBlockShape bp) == Just (llvmBlockLen bp) then - distPerms1 x (llvmBlockPtrPerm $ - llvmBlockAdjustModalities maybe_rw2 maybe_l2 bp) - else - error "simplImplOut: SImpl_ElimLLVMBlockPtr: incorrect length" +simplImplOut (SImpl_IntroLLVMBlockPtr x bp) = + distPerms1 x $ ValPerm_LLVMBlock bp +simplImplOut (SImpl_ElimLLVMBlockPtr x bp) = + distPerms1 x $ ValPerm_LLVMBlock llvmBlockPtrShapeUnfold bp simplImplOut (SImpl_IntroLLVMBlockField x fp) = distPerms1 x (ValPerm_Conj1 $ Perm_LLVMBlock $ llvmFieldPermToBlock fp) -simplImplOut (SImpl_ElimLLVMBlockField x fp len) = - let bp_fp = llvmFieldPermToBlock fp - sz = llvmFieldLen fp in - distPerms1 x (ValPerm_Conj - [Perm_LLVMField fp, - Perm_LLVMBlock $ - bp_fp { llvmBlockOffset = bvAdd (llvmFieldOffset fp) sz, - llvmBlockLen = bvSub len sz, - llvmBlockShape = PExpr_EmptyShape }]) +simplImplOut (SImpl_ElimLLVMBlockField x fp) = + distPerms1 x $ ValPerm_LLVMField fp simplImplOut (SImpl_IntroLLVMBlockArray x ap) = case llvmAtomicPermToBlock (Perm_LLVMArray ap) of Just bp -> distPerms1 x (ValPerm_Conj1 $ Perm_LLVMBlock bp) @@ -2416,8 +2388,8 @@ instance SubstVar PermVarSubst m => <*> return (mbLift sz) [nuMP| SImpl_LLVMArrayEmpty x ap |] -> SImpl_LLVMArrayEmpty <$> genSubst s x <*> genSubst s ap - [nuMP| SImpl_LLVMArrayOneCell x ap |] -> - SImpl_LLVMArrayOneCell <$> genSubst s x <*> genSubst s ap + [nuMP| SImpl_LLVMArrayFromBlock x bp |] -> + SImpl_LLVMArrayFromBlock <$> genSubst s x <*> genSubst s bp [nuMP| SImpl_LLVMArrayIndexCopy x ap ix |] -> SImpl_LLVMArrayIndexCopy <$> genSubst s x <*> genSubst s ap <*> genSubst s ix [nuMP| SImpl_LLVMArrayIndexBorrow x ap ix |] -> @@ -2426,9 +2398,9 @@ instance SubstVar PermVarSubst m => [nuMP| SImpl_LLVMArrayIndexReturn x ap ix |] -> SImpl_LLVMArrayIndexReturn <$> genSubst s x <*> genSubst s ap <*> genSubst s ix - [nuMP| SImpl_LLVMArrayContents x ap flds mb_mb_impl |] -> + [nuMP| SImpl_LLVMArrayContents x ap sh mb_mb_impl |] -> SImpl_LLVMArrayContents <$> genSubst s x <*> genSubst s ap <*> - genSubst s flds <*> genSubst s mb_mb_impl + genSubst s sh <*> genSubst s mb_mb_impl [nuMP| SImpl_LLVMFieldIsPtr x fp |] -> SImpl_LLVMFieldIsPtr <$> genSubst s x <*> genSubst s fp [nuMP| SImpl_LLVMArrayIsPtr x ap |] -> @@ -2493,17 +2465,14 @@ instance SubstVar PermVarSubst m => [nuMP| SImpl_IntroLLVMBlockFromEq x bp y |] -> SImpl_IntroLLVMBlockFromEq <$> genSubst s x <*> genSubst s bp <*> genSubst s y - [nuMP| SImpl_IntroLLVMBlockPtr x maybe_rw maybe_l bp |] -> - SImpl_IntroLLVMBlockPtr <$> genSubst s x <*> genSubst s maybe_rw - <*> genSubst s maybe_l <*> genSubst s bp - [nuMP| SImpl_ElimLLVMBlockPtr x maybe_rw maybe_l bp |] -> - SImpl_ElimLLVMBlockPtr <$> genSubst s x <*> genSubst s maybe_rw - <*> genSubst s maybe_l <*> genSubst s bp + [nuMP| SImpl_IntroLLVMBlockPtr x bp |] -> + SImpl_IntroLLVMBlockPtr <$> genSubst s x <*> genSubst s bp + [nuMP| SImpl_ElimLLVMBlockPtr x bp |] -> + SImpl_ElimLLVMBlockPtr <$> genSubst s x <*> genSubst s bp [nuMP| SImpl_IntroLLVMBlockField x fp |] -> SImpl_IntroLLVMBlockField <$> genSubst s x <*> genSubst s fp - [nuMP| SImpl_ElimLLVMBlockField x fp len |] -> + [nuMP| SImpl_ElimLLVMBlockField x fp |] -> SImpl_ElimLLVMBlockField <$> genSubst s x <*> genSubst s fp - <*> genSubst s len [nuMP| SImpl_IntroLLVMBlockArray x fp |] -> SImpl_IntroLLVMBlockArray <$> genSubst s x <*> genSubst s fp [nuMP| SImpl_ElimLLVMBlockArray x fp |] -> @@ -3581,6 +3550,30 @@ implCopySwapConjM x ps i = implCopyConjM x ps i >>> implSwapM x (ValPerm_Conj1 $ ps!!i) x (ValPerm_Conj ps) +-- | Either extract or copy the @i@th atomic permission in the conjunct on the +-- top of the stack, leaving the extracted or copied permission just below the +-- top of the stack and the remaining other permissions on top of the stack. +-- Return the list of conjuncts remaining on top of the stack. +implGetConjM :: NuMatchingAny1 r => ExprVar a -> [AtomicPerm a] -> Int -> + ImplM vars s r (ps :> a :> a) (ps :> a) [AtomicPerm a] +implGetConjM x ps i = + if atomicPermIsCopyable (ps!!i) then + implCopyConjM x ps i >>> return ps + else + implExtractConjM x ps i >>> return (deleteNth i ps) + +-- | Either extract or copy the @i@th atomic permission in the conjunct on the +-- top of the stack, leaving the extracted or copied permission on top of the +-- stack and the remaining other permissions just below it. Return the list of +-- conjuncts remaining just below the top of the stack. +implGetSwapConjM :: NuMatchingAny1 r => ExprVar a -> [AtomicPerm a] -> Int -> + ImplM vars s r (ps :> a :> a) (ps :> a) [AtomicPerm a] +implGetSwapConjM x ps i = + if atomicPermIsCopyable (ps!!i) then + implCopySwapConjM x ps i >>> return ps + else + implExtractSwapConjM x ps i >>> return (deleteNth i ps) + -- | Either extract or copy the @i@th atomic permission in the conjunct on the -- top of the stack, popping the remaining permissions implGetPopConjM :: NuMatchingAny1 r => ExprVar a -> [AtomicPerm a] -> Int -> @@ -3845,19 +3838,19 @@ introLLVMFieldContentsM x y fp = -- | Borrow a field from an LLVM array permission on the top of the stack, after -- proving (with 'implTryProveBVProps') that the index is in the array exclusive -- of any outstanding borrows (see 'llvmArrayIndexInArray'). Return the --- resulting array permission with the borrow and the borrowed field permission, --- leaving the arry permission on top of the stack and the field permission just +-- resulting array permission with the borrow and the borrowed cell permission, +-- leaving the array permission on top of the stack and the cell permission just -- below it on the stack. -implLLVMArrayIndexBorrow :: +implLLVMArrayCellBorrow :: (1 <= w, KnownNat w, NuMatchingAny1 r) => - ExprVar (LLVMPointerType w) -> LLVMArrayPerm w -> LLVMArrayIndex w -> + ExprVar (LLVMPointerType w) -> LLVMArrayPerm w -> PermExpr (BVType w) -> ImplM vars s r (ps :> LLVMPointerType w :> LLVMPointerType w) - (ps :> LLVMPointerType w) (LLVMArrayPerm w, LLVMArrayField w) -implLLVMArrayIndexBorrow x ap ix = - implTryProveBVProps x (llvmArrayIndexInArray ap ix) >>> - implSimplM Proxy (SImpl_LLVMArrayIndexBorrow x ap ix) >>> + (ps :> LLVMPointerType w) (LLVMArrayPerm w, LLVMBlockPerm w) +implLLVMArrayIndexBorrow x ap cell = + implTryProveBVProps x (llvmArrayCellInArray ap cell) >>> + implSimplM Proxy (SImpl_LLVMArrayIndexBorrow x ap cell) >>> pure (llvmArrayAddBorrow (FieldBorrow ix) ap, - llvmArrayFieldWithOffset ap ix) + blockForLLVMArrayCell ap cell) -- | Copy a field from an LLVM array permission on the top of the stack, after -- proving (with 'implTryProveBVProps') that the index is in the array exclusive @@ -3983,15 +3976,6 @@ implLLVMArrayEmpty :: ImplM vars s r (ps :> LLVMPointerType w) ps () implLLVMArrayEmpty x ap = implSimplM Proxy (SImpl_LLVMArrayEmpty x ap) --- | Prove an array that can be expressed as the conjunction of @N@ fields from --- those @N@ fields, assuming a proof of those fields is on the top of the stack -implLLVMArrayOneCell :: (1 <= w, KnownNat w, NuMatchingAny1 r) => - ExprVar (LLVMPointerType w) -> LLVMArrayPerm w -> - ImplM vars s r (ps :> LLVMPointerType w) - (ps :> LLVMPointerType w) () -implLLVMArrayOneCell x ap = - implSimplM Proxy (SImpl_LLVMArrayOneCell x ap) - -- | Prove the @memblock@ permission returned by @'llvmAtomicPermToBlock' p@ -- from a proof of @p@ on top of the stack, assuming it returned one @@ -4070,6 +4054,7 @@ implElimLLVMBlock x bp@(LLVMBlockPerm { llvmBlockShape = implSimplM Proxy (SImpl_ElimLLVMBlockPtr x maybe_rw maybe_l bp') -- For a field shape, eliminate to a field permission +{- implElimLLVMBlock x (LLVMBlockPerm { llvmBlockShape = PExpr_FieldShape (LLVMFieldShape p) , ..}) = @@ -4084,6 +4069,7 @@ implElimLLVMBlock x (LLVMBlockPerm { llvmBlockShape = implElimLLVMBlock x bp@(LLVMBlockPerm { llvmBlockShape = PExpr_ArrayShape _ _ _ }) = implSimplM Proxy (SImpl_ElimLLVMBlockArray x $ llvmArrayBlockToArrayPerm bp) +-} -- Special case: for shape sh1;emptysh where the natural length of sh1 is the -- same as the length of the block permission, eliminate the emptysh, converting @@ -4625,11 +4611,12 @@ proveEqCast x f e mb_e = -- lifetime-in-bindings @mb_l@, assuming the permission @x:F@ is on the top -- of the stack. Try to coerce the permission to @x:F@, possibly by -- instantiating existential variables in @mb_l@ and/or splitting lifetimes. +-- Return the resulting lifetime used for @mb_l@. proveVarLifetimeFunctor :: (KnownRepr TypeRepr a, NuMatchingAny1 r) => ExprVar a -> LifetimeFunctor args a -> PermExprs args -> PermExpr LifetimeType -> Mb vars (PermExpr LifetimeType) -> - ImplM vars s r (ps :> a) (ps :> a) () + ImplM vars s r (ps :> a) (ps :> a) (PermExpr LifetimeType) proveVarLifetimeFunctor x f args l mb_l = do psubst <- getPSubst proveVarLifetimeFunctor' x f args l mb_l psubst @@ -4640,14 +4627,14 @@ proveVarLifetimeFunctor' :: ExprVar a -> LifetimeFunctor args a -> PermExprs args -> PermExpr LifetimeType -> Mb vars (PermExpr LifetimeType) -> PartialSubst vars -> - ImplM vars s r (ps :> a) (ps :> a) () + ImplM vars s r (ps :> a) (ps :> a) (PermExpr LifetimeType) proveVarLifetimeFunctor' x f args l mb_l psubst = case mbMatch mb_l of -- If mb_l is an unset evar, set mb_l = l and return [nuMP| PExpr_Var mb_z |] | Left memb <- mbNameBoundP mb_z , Nothing <- psubstLookup psubst memb -> - setVarM memb l + setVarM memb l >>> return l -- If mb_l is a set evar, substitute for it and recurse [nuMP| PExpr_Var mb_z |] @@ -4657,7 +4644,7 @@ proveVarLifetimeFunctor' x f args l mb_l psubst = case mbMatch mb_l of -- If mb_l==l, we are done _ | mbLift $ fmap (== l) mb_l -> - pure () + return l -- If mb_l is a free variable l2 /= l, we need to split or weaken the lifetime [nuMP| PExpr_Var mb_z |] @@ -4674,7 +4661,8 @@ proveVarLifetimeFunctor' x f args l mb_l psubst = case mbMatch mb_l of getPerm l2 >>>= \case l2_p@(ValPerm_LOwned sub_ls ps_in ps_out) -> implPushM l2 l2_p >>> - implSplitLifetimeM x f args l l2 sub_ls ps_in ps_out + implSplitLifetimeM x f args l l2 sub_ls ps_in ps_out >>> + return (PExpr_Var l2) _ -> error ("proveVarLifetimeFunctor: unexpected error: " ++ "l2 lost its lowned perms") @@ -4682,7 +4670,8 @@ proveVarLifetimeFunctor' x f args l mb_l psubst = case mbMatch mb_l of _ -> let (l',l'_p) = lcurrentPerm l l2 in proveVarImplInt l' (fmap (const l'_p) mb_z) >>> - implSimplM Proxy (SImpl_WeakenLifetime x f args l l2) + implSimplM Proxy (SImpl_WeakenLifetime x f args l l2) >>> + return (PExpr_Var l2) -- Otherwise, fail; this should only include the case where the RHS is always -- but the LHS is not, which we cannot do anything with @@ -5051,8 +5040,21 @@ extractNeededLLVMFieldPerm x ap _ _ mb_fp = -- * Proving LLVM Array Permissions ---------------------------------------------------------------------- --- | FIXME HERE NOW: document, especially the bool flag = first iteration and --- that the bools with each perm are whether they can be used +FIXME HERE NOWNOW: +- proveVarLLVMArray needs array perms inside a binding the first time around + because of the modalities +- figure out the cases for using SImpl_LLVMArrayFromBlock below + +-- | Prove an LLVM array permission @ap@ from permissions @x:(p1 * ... *pn)@ on +-- the top of the stack, and ensuring that any remaining permissions for @x@ get +-- popped back to the primary permissions for @x@. The 'Bool' flag should be +-- 'True' for the initial call to this function, but 'False' if it is called +-- recursively by itself. This is used to determine if array permissions on the +-- left that might start before @ap@ can be used: the algorithm starts by trying +-- to prove as big of a prefix of an array permission as it can, and then +-- recursively tries to prove the remainder of the array, so on the subsequent +-- calls it should only use permissions for the remainder of the array that +-- precisely match the portion of the desired array that we still need. proveVarLLVMArray :: (1 <= w, KnownNat w, NuMatchingAny1 r) => ExprVar (LLVMPointerType w) -> Bool -> [AtomicPerm (LLVMPointerType w)] -> LLVMArrayPerm w -> @@ -5068,8 +5070,7 @@ proveVarLLVMArray x first_p ps ap = proveVarLLVMArrayH x first_p ps ap --- | FIXME HERE NOW: document, especially the bool flag = first iteration and --- that the bools with each perm are whether they can be used +-- | The implementation of 'proveVarLLVMArray' proveVarLLVMArrayH :: (1 <= w, KnownNat w, NuMatchingAny1 r) => ExprVar (LLVMPointerType w) -> Bool -> [AtomicPerm (LLVMPointerType w)] -> LLVMArrayPerm w -> @@ -5089,7 +5090,9 @@ proveVarLLVMArrayH x _ ps ap mbVarsM (ValPerm_LLVMArray ap) >>>= \mb_p -> proveVarImplInt x mb_p --- If the required array permission ap is equivalent to a sequence of field +-- If the required array permission ap has an offset that matches + +is equivalent to a sequence of field -- permissions that we have all of, then prove it by proving those field -- permissions. This is accomplished by first proving the array with the -- un-borrowed cell that is allowed by 'implLLVMArrayOneCell' and then @@ -5111,6 +5114,7 @@ proveVarLLVMArrayH x _ ps ap implPopM x (ValPerm_Conj1 $ Perm_LLVMArray ap') >>> mbVarsM (ValPerm_Conj1 $ Perm_LLVMArray ap) >>>= \mb_p -> proveVarImplInt x mb_p +-} -- Otherwise, choose the best-matching array permission and copy, borrow, or use -- it directly (beg, borrow, or steal it) @@ -5138,7 +5142,9 @@ proveVarLLVMArrayH x first_p ps ap = ps [0..]) --- | FIXME HERE NOW: document this +-- | Prove an array permission @ap@ using the @i@th conjunct @pi@ on the top of +-- the stack, assuming @pi@ is the supplied array permission @ap_lhs@ and +-- @x:p1*...*pn@ is on top of the stack. proveVarLLVMArray_ArrayStep :: (1 <= w, KnownNat w, NuMatchingAny1 r) => ExprVar (LLVMPointerType w) -> [AtomicPerm (LLVMPointerType w)] -> LLVMArrayPerm w -> @@ -5157,6 +5163,8 @@ proveVarLLVMArray_ArrayStep x ps ap i ap_lhs = -- | The main workhorse of 'proveVarLLVMArray_ArrayStep' +-- +-- FIXME: this should handle array read-write modalities and lifetimes proveVarLLVMArray_ArrayStepH :: (1 <= w, KnownNat w, NuMatchingAny1 r) => ExprVar (LLVMPointerType w) -> [AtomicPerm (LLVMPointerType w)] -> LLVMArrayPerm w -> @@ -5222,29 +5230,27 @@ proveVarLLVMArray_ArrayStepH x ps ap i ap_lhs | bvEq (llvmArrayOffset ap_lhs) (llvmArrayOffset ap) , bvEq (llvmArrayLen ap_lhs) (llvmArrayLen ap) , llvmArrayStride ap_lhs == llvmArrayStride ap - , llvmArrayFields ap_lhs == llvmArrayFields ap + , llvmArrayCellShape ap_lhs == llvmArrayCellShape ap , llvmArrayBorrowsPermuteTo ap_lhs (llvmArrayBorrows ap) = implGetPopConjM x ps i >>> implLLVMArrayRearrange x ap_lhs (llvmArrayBorrows ap) --- If ap and ap_lhs have the same range and stride but their fields are --- different, prove the rhs fields from the lhs fields +-- If ap and ap_lhs have the same range and stride but their cells have +-- different shapes, prove the rhs shape from the lhs shape proveVarLLVMArray_ArrayStepH x ps ap i ap_lhs | bvEq (llvmArrayOffset ap_lhs) (llvmArrayOffset ap) , bvEq (llvmArrayLen ap_lhs) (llvmArrayLen ap) , llvmArrayStride ap_lhs == llvmArrayStride ap - , flds <- llvmArrayFields ap - , flds_lhs <- llvmArrayFields ap_lhs - , ap' <- ap { llvmArrayFields = flds_lhs } + , ap' <- ap { llvmArrayCellShape = sh_lhs } , dps_in <- - nu $ \y -> distPerms1 y $ ValPerm_Conj $ - map llvmArrayFieldToAtomicPerm flds_lhs + nu $ \y -> distPerms1 y $ ValPerm_LLVMBlock $ + blockForLLVMArrayIndex ap $ bvInt 0 , dps_out <- - nu $ \y -> distPerms1 y $ ValPerm_Conj $ - map llvmArrayFieldToAtomicPerm flds = + nu $ \y -> distPerms1 y $ ValPerm_LLVMBlock $ + blockForLLVMArrayIndex ap_lhs $ bvInt 0 = proveVarLLVMArray_ArrayStep x ps ap' i ap_lhs >>> localMbProveVars dps_in dps_out >>>= \mb_impl -> - implSimplM Proxy (SImpl_LLVMArrayContents x ap' flds mb_impl) + implSimplM Proxy (SImpl_LLVMArrayContents x ap' sh mb_impl) -- If ap is contained inside ap_lhs at a cell boundary then copy or borrow ap -- from ap_lhs depending on whether they are copyable @@ -5253,8 +5259,7 @@ proveVarLLVMArray_ArrayStepH x ps ap i ap_lhs (llvmArrayAbsOffsets ap) (llvmArrayAbsOffsets ap_lhs)) , llvmArrayStride ap_lhs == llvmArrayStride ap , llvmArrayFields ap_lhs == llvmArrayFields ap - , Just (LLVMArrayIndex _ 0) <- - matchLLVMArrayField ap_lhs (llvmArrayOffset ap) = + , Just _ <- llvmArrayIsOffsetArray ap_lhs ap = implExtractConjM x ps i >>> implPopM x (ValPerm_Conj $ deleteNth i ps) >>> if atomicPermIsCopyable (Perm_LLVMArray ap) then @@ -5271,8 +5276,7 @@ proveVarLLVMArray_ArrayStepH x ps ap i ap_lhs proveVarLLVMArray_ArrayStepH x ps ap i ap_lhs | llvmArrayStride ap_lhs == llvmArrayStride ap , llvmArrayFields ap_lhs == llvmArrayFields ap - , Just (LLVMArrayIndex ap_cell_num 0) <- - matchLLVMArrayField ap_lhs (llvmArrayOffset ap) = + , Just ap_cell_num <- llvmArrayIsOffsetArray ap_lhs ap = -- Split ap into ap_first = the portion of ap covered by ap_lhs and ap_rest let (ap_first, ap_rest) = @@ -5426,7 +5430,7 @@ proveVarLLVMBlock :: ImplM vars s r (ps :> LLVMPointerType w) (ps :> LLVMPointerType w) () proveVarLLVMBlock x ps mb_bp = do psubst <- getPSubst - proveVarLLVMBlocks x ps psubst [mb_bp] [] + proveVarLLVMBlocks x ps psubst [mb_bp] -- | Prove a conjunction of block and atomic permissions for @x@, assuming all @@ -5437,34 +5441,33 @@ proveVarLLVMBlock x ps mb_bp = -- A central motivation of this algorithm is to do as little elimination on the -- left or introduction on the right as possible, in order to build the smallest -- derivation we can. The algorithm iterates through the block permissions on --- the right, trying for each of them to either match it up with a block --- permission on the left or simplify it to a non-block permission. The first --- stage of the algorithm attempts to break down permissions on the left that --- overlap with but are not contained in the current block permission on the --- right we are trying to prove, so that we end up with permissions on the left --- that are no bigger than the right. This stage is performed by --- 'proveVarLLVMBlocks1'. The algorithm then repeatedly breaks down the --- right-hand block permission we are trying to prove, going back to stage one --- if necessary if this leads to it being smaller than some left-hand +-- the right, trying for each of them to match it up with a block permission on +-- the left. The first stage of the algorithm attempts to break down permissions +-- on the left that overlap with but are not contained in the current block +-- permission on the right we are trying to prove, so that we end up with +-- permissions on the left that are no bigger than the right. This stage is +-- performed by 'proveVarLLVMBlocks1'. The algorithm then repeatedly breaks down +-- the right-hand block permission we are trying to prove, going back to stage +-- one if necessary if this leads to it being smaller than some left-hand -- permission, until we either get a precise match or we eventually break the --- right-hand permission down to a non-block permission. This stage is performed --- by 'proveVarLLVMBlocks2'. +-- right-hand permission down to block permission whose offset, size, and shape +-- matches one on the left. This stage is performed by 'proveVarLLVMBlocks2'. proveVarLLVMBlocks :: (1 <= w, KnownNat w, NuMatchingAny1 r) => ExprVar (LLVMPointerType w) -> [AtomicPerm (LLVMPointerType w)] -> PartialSubst vars -> - [Mb vars (LLVMBlockPerm w)] -> [Mb vars (AtomicPerm (LLVMPointerType w))] -> + [Mb vars (LLVMBlockPerm w)] -> ImplM vars s r (ps :> LLVMPointerType w) (ps :> LLVMPointerType w) () proveVarLLVMBlocks x ps psubst mb_bps mb_ps = -- This substitution is to only print the existential vars once, on the -- outside; also, substituting here ensures that we only traverse the -- permissions once - mbSubstM (\s -> (map s mb_bps, map s mb_ps)) >>>= \mb_bps_ps -> + mbSubstM (\s -> map s mb_bps) >>>= \mb_bps' -> implTraceM (\i -> sep [pretty "proveVarLLVMBlocks", permPretty i x <> colon <> permPretty i ps, - pretty "-o", permPretty i mb_bps_ps]) >>> - proveVarLLVMBlocks1 x ps psubst mb_bps mb_ps + pretty "-o", permPretty i mb_bps']) >>> + proveVarLLVMBlocks1 x ps psubst mb_bps -- | Call 'proveVarLLVMBlock' in a context extended with a fresh existential @@ -5474,12 +5477,12 @@ proveVarLLVMBlocksExt1 :: (1 <= w, KnownNat w, KnownRepr TypeRepr tp, NuMatchingAny1 r) => ExprVar (LLVMPointerType w) -> [AtomicPerm (LLVMPointerType w)] -> PartialSubst vars -> Mb (vars :> tp) (LLVMBlockPerm w) -> - [Mb vars (LLVMBlockPerm w)] -> [Mb vars (AtomicPerm (LLVMPointerType w))] -> + [Mb vars (LLVMBlockPerm w)] -> ImplM vars s r (ps :> LLVMPointerType w) (ps :> LLVMPointerType w) (PermExpr tp) -proveVarLLVMBlocksExt1 x ps psubst mb_bp_ext mb_bps mb_ps = +proveVarLLVMBlocksExt1 x ps psubst mb_bp_ext mb_bps = fmap snd $ withExtVarsM $ proveVarLLVMBlocks x ps (extPSubst psubst) - (mb_bp_ext : map extMb mb_bps) (map extMb mb_ps) + (mb_bp_ext : map extMb mb_bps) -- | Like 'proveVarLLVMBlockExt1' but bind 2 existential variables, which can be -- used in 0 or more block permissions we want to prove @@ -5488,32 +5491,81 @@ proveVarLLVMBlocksExt2 :: KnownRepr TypeRepr tp2, NuMatchingAny1 r) => ExprVar (LLVMPointerType w) -> [AtomicPerm (LLVMPointerType w)] -> PartialSubst vars -> Mb (vars :> tp1 :> tp2) [LLVMBlockPerm w] -> - [Mb vars (LLVMBlockPerm w)] -> [Mb vars (AtomicPerm (LLVMPointerType w))] -> + [Mb vars (LLVMBlockPerm w)] -> ImplM vars s r (ps :> LLVMPointerType w) (ps :> LLVMPointerType w) (PermExpr tp1, PermExpr tp2) -proveVarLLVMBlocksExt2 x ps psubst mb_bps_ext mb_bps mb_ps = +proveVarLLVMBlocksExt2 x ps psubst mb_bps_ext mb_bps = withExtVarsM (withExtVarsM $ proveVarLLVMBlocks x ps (extPSubst $ extPSubst psubst) - (mbList mb_bps_ext ++ (map (extMb . extMb) mb_bps)) - (map (extMb . extMb) mb_ps)) >>= \((_,e2),e1) -> + (mbList mb_bps_ext ++ (map (extMb . extMb) mb_bps))) >>= \((_,e2),e1) -> pure (e1,e2) +-- | Assume the first block permission is on top of the stack, and attempt to +-- coerce its read-write modality to that of the second, leaving the resulting +-- block permission on top of the stack. Return the resulting block permission. +equalizeBlockRWs :: (1 <= w, KnownNat w, NuMatchingAny1 r) => + ExprVar (LLVMPointerType w) -> LLVMBlockPerm w -> + Mb vars (LLVMBlockPerm w) -> + ImplM vars s r + (ps :> LLVMPointerType w) (ps :> LLVMPointerType w) + (LLVMBlockPerm w) +equalizeBlockRWs x bp mb_bp + | mbLift (fmap ((== llvmBlockRW bp) . llvmBlockRW) mb_bp) = + return bp +equalizeBlockRWs x bp mb_bp + | [nuMP| PExpr_Read |] <- mbMatch (fmap llvmBlockRW mb_bp) = + implSimplM Proxy (SImpl_DemoteLLVMBlockRW x bp) >>> + return (bp { llvmBlockRW = PExpr_Read }) +equalizeBlockRWs x bp mb_bp = + proveEqCast x (\rw -> ValPerm_LLVMBlock $ bp { llvmBlockRW = rw }) + (llvmBlockRW bp) (fmap llvmBlockRW mb_bp) >>> + return bp + +-- | Assume the first block permission is on top of the stack, and attempt to +-- coerce its lifetime to that of the second, leaving the resulting block +-- permission on top of the stack. Return the resulting block permission. +equalizeBlockLifetimes :: (1 <= w, KnownNat w, NuMatchingAny1 r) => + ExprVar (LLVMPointerType w) -> LLVMBlockPerm w -> + Mb vars (LLVMBlockPerm w) -> + ImplM vars s r + (ps :> LLVMPointerType w) (ps :> LLVMPointerType w) + (LLVMBlockPerm w) +equalizeBlockLifetimes x bp mb_bp = + let (f, args) = blockToLTFunc bp' in + proveVarLifetimeFunctor x f args (llvmBlockLifetime bp) + (fmap llvmBlockLifetime mb_bp) >>>= \l -> + return (bp { llvmBlockLifetime = l }) + +-- | Assume the first block permission is on top of the stack, and attempt to +-- coerce its read-write modality and lifetime to those of the second, leaving +-- the resulting block permission on top of the stack. Return the resulting +-- block permission. +equalizeBlockModalities :: (1 <= w, KnownNat w, NuMatchingAny1 r) => + ExprVar (LLVMPointerType w) -> LLVMBlockPerm w -> + Mb vars (LLVMBlockPerm w) -> + ImplM vars s r + (ps :> LLVMPointerType w) (ps :> LLVMPointerType w) + (LLVMBlockPerm w) +equalizeBlockModalities x bp mb_bp = + equalizeBlockRWs x bp mb_bp >>>= \bp' -> + equalizeBlockLifetimes x bp' mb_bp + -- | Stage 1 of 'proveVarLLVMBlocks'. See that comments on that function. proveVarLLVMBlocks1 :: (1 <= w, KnownNat w, NuMatchingAny1 r) => ExprVar (LLVMPointerType w) -> [AtomicPerm (LLVMPointerType w)] -> PartialSubst vars -> - [Mb vars (LLVMBlockPerm w)] -> [Mb vars (AtomicPerm (LLVMPointerType w))] -> + [Mb vars (LLVMBlockPerm w)] -> ImplM vars s r (ps :> LLVMPointerType w) (ps :> LLVMPointerType w) () --- If we are done with blocks, call proveVarConjImpl -proveVarLLVMBlocks1 x ps _ [] mb_ps = - mbSubstM (\s -> map s mb_ps) >>>= proveVarConjImpl x ps +-- We are done, yay! Pop ps and build a true permission +proveVarLLVMBlocks1 x ps _ [] = + implPopM x (ValPerm_Conj ps) >>> introConjM x -- If the offset, length, and shape of the top block matches one that we already -- have, just cast the rwmodality and lifetime and prove the remaining perms -proveVarLLVMBlocks1 x ps psubst (mb_bp:mb_bps) mb_ps +proveVarLLVMBlocks1 x ps psubst (mb_bp:mb_bps) | Just off <- partialSubst psubst $ fmap llvmBlockOffset mb_bp , Just len <- partialSubst psubst $ fmap llvmBlockLen mb_bp , Just i <- findIndex (\case @@ -5526,44 +5578,26 @@ proveVarLLVMBlocks1 x ps psubst (mb_bp:mb_bps) mb_ps , Perm_LLVMBlock bp <- ps!!i = -- Copy or extract the memblock perm we chose to the top of the stack - (if atomicPermIsCopyable (ps!!i) then - implCopySwapConjM x ps i >>> pure ps - else - implExtractSwapConjM x ps i >>> pure (deleteNth i ps)) >>>= \ps' -> - - -- Cast it to have the correct RW modality - (case (llvmBlockRW bp, fmap llvmBlockRW mb_bp) of - -- If the modalities are already equal, do nothing - (rw, mb_rw) | mbLift (fmap (== rw) mb_rw) -> pure () - (_, mbMatch -> [nuMP| PExpr_Read |]) -> - implSimplM Proxy (SImpl_DemoteLLVMBlockRW x bp) - _ -> - proveEqCast x (\rw -> ValPerm_LLVMBlock $ bp { llvmBlockRW = rw }) - (llvmBlockRW bp) (fmap llvmBlockRW mb_bp)) >>> - getTopDistPerm x >>>= \(ValPerm_LLVMBlock bp') -> + implGetConjM x ps i >>>= \ps' -> - -- Get the lifetime correct - let (f, args) = blockToLTFunc bp' in - proveVarLifetimeFunctor x f args (llvmBlockLifetime bp) (fmap - llvmBlockLifetime - mb_bp) >>> - getTopDistPerm x >>>= \(ValPerm_LLVMBlock bp'') -> + -- Make the input block have the required modalities + equalizeBlockModalities x bp mb_bp >>>= \bp' -> -- Move it down below ps' - implSwapM x (ValPerm_Conj ps') x (ValPerm_LLVMBlock bp'') >>> + implSwapM x (ValPerm_Conj ps') x (ValPerm_LLVMBlock bp') >>> -- Recursively prove the remaining perms - proveVarLLVMBlocks x ps' psubst mb_bps mb_ps >>> + proveVarLLVMBlocks x ps' psubst mb_bps >>> getTopDistPerm x >>>= \(ValPerm_Conj ps_out) -> -- Finally, combine the one memblock perm we chose with the rest of them - implInsertConjM x (Perm_LLVMBlock bp'') ps_out 0 + implInsertConjM x (Perm_LLVMBlock bp') ps_out 0 -- If the offset and length of the top block matches one that we already have on -- the left, but the left-hand permission has a defined shape, unfold the -- defined shape -proveVarLLVMBlocks1 x ps psubst mb_bps_in@(mb_bp:_) mb_ps +proveVarLLVMBlocks1 x ps psubst mb_bps_in@(mb_bp:_) | Just off <- partialSubst psubst $ fmap llvmBlockOffset mb_bp , Just len <- partialSubst psubst $ fmap llvmBlockLen mb_bp , Just i <- findIndex @@ -5575,14 +5609,14 @@ proveVarLLVMBlocks1 x ps psubst mb_bps_in@(mb_bp:_) mb_ps bvEq (llvmBlockLen bp) len _ -> False) ps = implElimAppendIthLLVMBlock x ps i >>>= \ps' -> - proveVarLLVMBlocks x ps' psubst mb_bps_in mb_ps + proveVarLLVMBlocks x ps' psubst mb_bps_in -- If the offset and length of the top block matches one that we already have on -- the left, but the left-hand permission has an unneeded empty shape at the -- end, i.e., is of the form sh;emptysh where the natural length of sh is the -- length of the left-hand permission, remove that trailing empty shape -proveVarLLVMBlocks1 x ps psubst mb_bps_in@(mb_bp:_) mb_ps +proveVarLLVMBlocks1 x ps psubst mb_bps_in@(mb_bp:_) | Just off <- partialSubst psubst $ fmap llvmBlockOffset mb_bp , Just len <- partialSubst psubst $ fmap llvmBlockLen mb_bp , Just i <- findIndex @@ -5595,7 +5629,7 @@ proveVarLLVMBlocks1 x ps psubst mb_bps_in@(mb_bp:_) mb_ps bvEq len len' _ -> False) ps = implElimAppendIthLLVMBlock x ps i >>>= \ps' -> - proveVarLLVMBlocks x ps' psubst mb_bps_in mb_ps + proveVarLLVMBlocks x ps' psubst mb_bps_in -- If there is a left-hand permission with empty shape whose range overlaps with @@ -5603,7 +5637,7 @@ proveVarLLVMBlocks1 x ps psubst mb_bps_in@(mb_bp:_) mb_ps -- in or disjoint from the range of mb_bp; i.e., split it at the beginning -- and/or end of mb_bp. We exclude mb_bp with length 0 as a pathological edge -- case. -proveVarLLVMBlocks1 x ps psubst mb_bps_in@(mb_bp:_) mb_ps +proveVarLLVMBlocks1 x ps psubst mb_bps_in@(mb_bp:_) | Just off <- partialSubst psubst $ fmap llvmBlockOffset mb_bp , Just len <- partialSubst psubst $ fmap llvmBlockLen mb_bp , rng <- BVRange off len @@ -5611,7 +5645,7 @@ proveVarLLVMBlocks1 x ps psubst mb_bps_in@(mb_bp:_) mb_ps , Just i <- findIndex (\case Perm_LLVMBlock bp -> llvmBlockShape bp == PExpr_EmptyShape && - bvRangesCouldOverlap (llvmBlockRange bp) rng && + bvRangesOverlap (llvmBlockRange bp) rng && not (bvRangeSubset (llvmBlockRange bp) rng) _ -> False) ps , Perm_LLVMBlock bp <- ps!!i = @@ -5625,32 +5659,32 @@ proveVarLLVMBlocks1 x ps psubst mb_bps_in@(mb_bp:_) mb_ps implSimplM Proxy (SImpl_SplitLLVMBlockEmpty x bp len1) >>> getTopDistPerm x >>>= \(ValPerm_Conj ps') -> implAppendConjsM x (deleteNth i ps) ps' >>> - proveVarLLVMBlocks x (deleteNth i ps ++ ps') psubst mb_bps_in mb_ps + proveVarLLVMBlocks x (deleteNth i ps ++ ps') psubst mb_bps_in -- If there is a left-hand permission whose range overlaps with but is not -- contained in that of mb_bp, eliminate it. Note that we exclude mb_bp with -- length 0 for this case, since eliminating on the left does not help prove -- these permissions. -proveVarLLVMBlocks1 x ps psubst mb_bps_in@(mb_bp:_) mb_ps +proveVarLLVMBlocks1 x ps psubst mb_bps_in@(mb_bp:_) | Just off <- partialSubst psubst $ fmap llvmBlockOffset mb_bp , Just len <- partialSubst psubst $ fmap llvmBlockLen mb_bp , not (bvIsZero len) , rng <- BVRange off len , Just i <- findIndex (\case Perm_LLVMBlock bp -> - bvRangesCouldOverlap (llvmBlockRange bp) rng && + bvRangesOverlap (llvmBlockRange bp) rng && not (bvRangeSubset (llvmBlockRange bp) rng) _ -> False) ps = implElimAppendIthLLVMBlock x ps i >>>= \ps' -> - proveVarLLVMBlocks x ps' psubst mb_bps_in mb_ps + proveVarLLVMBlocks x ps' psubst mb_bps_in -- If none of the above cases match for stage 1, proceed to stage 2, which -- operates by induction on the shape -proveVarLLVMBlocks1 x ps psubst (mb_bp:mb_bps) mb_ps = +proveVarLLVMBlocks1 x ps psubst (mb_bp:mb_bps) = proveVarLLVMBlocks2 x ps psubst mb_bp (mbMatch $ - fmap llvmBlockShape mb_bp) mb_bps mb_ps + fmap llvmBlockShape mb_bp) mb_bps -- | Stage 2 of 'proveVarLLVMBlocks'. See that comments on that function. The @@ -5659,18 +5693,18 @@ proveVarLLVMBlocks2 :: (1 <= w, KnownNat w, NuMatchingAny1 r) => ExprVar (LLVMPointerType w) -> [AtomicPerm (LLVMPointerType w)] -> PartialSubst vars -> Mb vars (LLVMBlockPerm w) -> MatchedMb vars (PermExpr (LLVMShapeType w)) -> - [Mb vars (LLVMBlockPerm w)] -> [Mb vars (AtomicPerm (LLVMPointerType w))] -> + [Mb vars (LLVMBlockPerm w)] -> ImplM vars s r (ps :> LLVMPointerType w) (ps :> LLVMPointerType w) () -- If proving the empty shape for length 0, recursively prove everything else -- and then use the empty introduction rule -proveVarLLVMBlocks2 x ps psubst mb_bp [nuMP| PExpr_EmptyShape |] mb_bps mb_ps +proveVarLLVMBlocks2 x ps psubst mb_bp [nuMP| PExpr_EmptyShape |] mb_bps | Just len <- partialSubst psubst $ fmap llvmBlockLen mb_bp , bvIsZero len = -- Do the recursive call without the empty shape and remember what -- permissions it proved - proveVarLLVMBlocks x ps psubst mb_bps mb_ps >>> + proveVarLLVMBlocks x ps psubst mb_bps >>> getTopDistPerm x >>>= \(ValPerm_Conj ps_out) -> -- Substitute into the required block perm and prove it with @@ -5687,12 +5721,12 @@ proveVarLLVMBlocks2 x ps psubst mb_bp [nuMP| PExpr_EmptyShape |] mb_bps mb_ps -- If proving the empty shape otherwise, prove an arbitrary memblock permission, -- i.e., with shape y for evar y, and coerce it to the empty shape -proveVarLLVMBlocks2 x ps psubst mb_bp [nuMP| PExpr_EmptyShape |] mb_bps mb_ps = +proveVarLLVMBlocks2 x ps psubst mb_bp [nuMP| PExpr_EmptyShape |] mb_bps = -- Locally bind z_sh for the shape of the memblock perm and recurse let mb_bp' = mbCombine RL.typeCtxProxies $ flip fmap mb_bp $ \bp -> nu $ \z_sh -> bp { llvmBlockShape = PExpr_Var z_sh } in - proveVarLLVMBlocksExt1 x ps psubst mb_bp' mb_bps mb_ps >>> + proveVarLLVMBlocksExt1 x ps psubst mb_bp' mb_bps >>> -- Extract out the block perm we proved and coerce it to the empty shape getTopDistPerm x >>>= \(ValPerm_Conj ps_out) -> @@ -5709,7 +5743,7 @@ proveVarLLVMBlocks2 x ps psubst mb_bp [nuMP| PExpr_EmptyShape |] mb_bps mb_ps = -- not match the above cases) whose length is longer than the natural length of -- its shape, prove the memblock with the natural length as well as an -- additional memblock with empty shape and then sequence them together. -proveVarLLVMBlocks2 x ps psubst mb_bp _ mb_bps mb_ps +proveVarLLVMBlocks2 x ps psubst mb_bp _ mb_bps | Just len <- partialSubst psubst (fmap llvmBlockLen mb_bp) , mbLift $ fmap (maybe False (`bvLt` len) . llvmShapeLength . llvmBlockShape) mb_bp = @@ -5724,7 +5758,7 @@ proveVarLLVMBlocks2 x ps psubst mb_bp _ mb_bps mb_ps llvmBlockShape = PExpr_EmptyShape }]) mb_bp in -- Next, do the recursive call - proveVarLLVMBlocks x ps psubst (mbList mb_bps' ++ mb_bps) mb_ps >>> + proveVarLLVMBlocks x ps psubst (mbList mb_bps' ++ mb_bps) >>> -- Move the correctly-sized perm + the empty shape one to the top of the -- stack and sequence them, and then eliminate the empty shape at the end @@ -5742,7 +5776,7 @@ proveVarLLVMBlocks2 x ps psubst mb_bp _ mb_bps mb_ps -- For an unfoldable named shape, prove its unfolding first and then fold it -proveVarLLVMBlocks2 x ps psubst mb_bp mb_sh mb_bps mb_ps +proveVarLLVMBlocks2 x ps psubst mb_bp mb_sh mb_bps | [nuMP| PExpr_NamedShape rw l nmsh args |] <- mb_sh , [nuMP| TrueRepr |] <- mbMatch $ fmap namedShapeCanUnfoldRepr nmsh , [nuMP| Just mb_sh' |] <- mbMatch $ (mbMap3 unfoldModalizeNamedShape rw l nmsh @@ -5752,7 +5786,7 @@ proveVarLLVMBlocks2 x ps psubst mb_bp mb_sh mb_bps mb_ps else return ()) >>> let mb_bp' = mbMap2 (\bp sh' -> (bp { llvmBlockShape = sh' })) mb_bp mb_sh' in - proveVarLLVMBlocks x ps psubst (mb_bp' : mb_bps) mb_ps >>> + proveVarLLVMBlocks x ps psubst (mb_bp' : mb_bps) >>> -- Extract out the block perm we proved getTopDistPerm x >>>= \(ValPerm_Conj ps_out) -> @@ -5773,7 +5807,7 @@ proveVarLLVMBlocks2 x ps psubst mb_bp mb_sh mb_bps mb_ps -- permission is to have it on the left, but we don't have a memblock permission -- on the left with this exact offset, length, and shape, because it would have -- matched some previous case, so try to eliminate a memblock and recurse -proveVarLLVMBlocks2 x ps psubst mb_bp mb_sh mb_bps mb_ps +proveVarLLVMBlocks2 x ps psubst mb_bp mb_sh mb_bps | [nuMP| PExpr_NamedShape _ _ nmsh _ |] <- mb_sh , [nuMP| FalseRepr |] <- mbMatch $ fmap namedShapeCanUnfoldRepr nmsh , Just off <- partialSubst psubst $ fmap llvmBlockOffset mb_bp @@ -5783,24 +5817,23 @@ proveVarLLVMBlocks2 x ps psubst mb_bp mb_sh mb_bps mb_ps _ -> False) ps , Perm_LLVMBlock _ <- ps!!i = implElimAppendIthLLVMBlock x ps i >>>= \ps' -> - proveVarLLVMBlocks x ps' psubst (mb_bp:mb_bps) mb_ps + proveVarLLVMBlocks x ps' psubst (mb_bp:mb_bps) -- If proving an equality shape eqsh(z) for evar z which has already been set, -- substitute for z and recurse -proveVarLLVMBlocks2 x ps psubst mb_bp mb_sh mb_bps mb_ps +proveVarLLVMBlocks2 x ps psubst mb_bp mb_sh mb_bps | [nuMP| PExpr_EqShape (PExpr_Var mb_z) |] <- mb_sh , Left memb <- mbNameBoundP mb_z , Just blk <- psubstLookup psubst memb = proveVarLLVMBlocks x ps psubst (fmap (\bp -> bp { llvmBlockShape = PExpr_EqShape blk }) mb_bp : mb_bps) - mb_ps -- If proving an equality shape eqsh(z) for unset evar z, prove any memblock -- perm with the given offset and length and eliminate it to an llvmblock with -- an equality shape -proveVarLLVMBlocks2 x ps psubst mb_bp mb_sh mb_bps mb_ps +proveVarLLVMBlocks2 x ps psubst mb_bp mb_sh mb_bps | [nuMP| PExpr_EqShape (PExpr_Var mb_z) |] <- mb_sh , Left memb <- mbNameBoundP mb_z , Nothing <- psubstLookup psubst memb = @@ -5809,7 +5842,7 @@ proveVarLLVMBlocks2 x ps psubst mb_bp mb_sh mb_bps mb_ps let mb_bp' = mbCombine RL.typeCtxProxies $ flip fmap mb_bp $ \bp -> nu $ \z_sh -> bp { llvmBlockShape = PExpr_Var z_sh } in - proveVarLLVMBlocksExt1 x ps psubst mb_bp' mb_bps mb_ps >>> + proveVarLLVMBlocksExt1 x ps psubst mb_bp' mb_bps >>> -- Extract out the block perm we proved getTopDistPerm x >>>= \(ValPerm_Conj ps_out) -> @@ -5830,7 +5863,7 @@ proveVarLLVMBlocks2 x ps psubst mb_bp mb_sh mb_bps mb_ps -- have it on the left, but we don't have a memblock permission on the left with -- this exactly offset, length, and shape, because it would have matched the -- first case above, so try to eliminate a memblock and recurse -proveVarLLVMBlocks2 x ps psubst mb_bp mb_sh mb_bps mb_ps +proveVarLLVMBlocks2 x ps psubst mb_bp mb_sh mb_bps | [nuMP| PExpr_EqShape (PExpr_Var mb_z) |] <- mb_sh , Right _ <- mbNameBoundP mb_z , Just off <- partialSubst psubst $ fmap llvmBlockOffset mb_bp @@ -5840,25 +5873,18 @@ proveVarLLVMBlocks2 x ps psubst mb_bp mb_sh mb_bps mb_ps _ -> False) ps , Perm_LLVMBlock _ <- ps!!i = implElimAppendIthLLVMBlock x ps i >>>= \ps' -> - proveVarLLVMBlocks x ps' psubst (mb_bp:mb_bps) mb_ps + proveVarLLVMBlocks x ps' psubst (mb_bp:mb_bps) --- If proving a pointer shape, prove the required permission by adding it to ps; --- this requires the pointed-to shape to have a well-defined length -proveVarLLVMBlocks2 x ps psubst mb_bp mb_sh mb_bps mb_ps - | [nuMP| PExpr_PtrShape mb_rw mb_l mb_sh' |] <- mb_sh - , mbLift $ fmap (isJust . llvmShapeLength) mb_sh' = - - -- Add a permission for a pointer to the required shape to mb_ps, and - -- recursively call proveVarLLVMBlocks to prove it and everything else - let mb_p_ptr = - mbMap4 (\bp maybe_rw maybe_l sh -> - (llvmBlockPtrAtomicPerm $ - llvmBlockAdjustModalities maybe_rw maybe_l $ - bp { llvmBlockLen = fromJust (llvmShapeLength sh), - llvmBlockShape = sh })) - mb_bp mb_rw mb_l mb_sh' in - proveVarLLVMBlocks x ps psubst mb_bps (mb_p_ptr:mb_ps) >>> +-- If proving a pointer shape, prove the 'llvmBlockPtrShapeUnfold' permission, +-- assuming it is defined +proveVarLLVMBlocks2 x ps psubst mb_bp mb_sh mb_bps + | [nuMP| PExpr_PtrShape _ _ _ |] <- mb_sh + , [nuMP| Just mb_bp' |] <- fmap llvmBlockPtrShapeUnfold mb_bp + + -- Recursively prove the required field permission and all the other block + -- permissions + proveVarLLVMBlocks x ps psubst (mb_bp':mb_bps) >>> -- Move the pointer permission we proved to the top of the stack getTopDistPerm x >>>= \(ValPerm_Conj ps') -> @@ -5867,70 +5893,54 @@ proveVarLLVMBlocks2 x ps psubst mb_bp mb_sh mb_bps mb_ps -- Use the SImpl_IntroLLVMBlockPtr rule to prove the required memblock perm partialSubstForceM mb_bp "proveVarLLVMBlocks" >>>= \bp -> - let PExpr_PtrShape maybe_rw maybe_l sh = llvmBlockShape bp in - let Just sh_len = llvmShapeLength sh in - implSimplM Proxy (SImpl_IntroLLVMBlockPtr x maybe_rw maybe_l $ - bp { llvmBlockLen = sh_len, llvmBlockShape = sh }) >>> + implSimplM Proxy (SImpl_IntroLLVMBlockPtr x bp) >>> -- Finally, move the memblock perm we proved back into position implSwapInsertConjM x (Perm_LLVMBlock bp) (deleteNth i ps') 0 --- If proving a field shape, prove the required permission by adding it to ps +-- If proving a field shape, prove the remaining blocks and then prove the +-- corresponding field permission proveVarLLVMBlocks2 x ps psubst mb_bp mb_sh mb_bps mb_ps - | [nuMP| PExpr_FieldShape (LLVMFieldShape mb_p) |] <- mb_sh = - - -- Add the field permission to the required permission to mb_ps, and - -- recursively call proveVarLLVMBlocks to prove it and everything else - let mb_fp = - mbMap2 (\bp p -> - (llvmBlockPtrFieldPerm bp) { llvmFieldContents = p }) - mb_bp mb_p in - let mb_p' = fmap Perm_LLVMField mb_fp in - proveVarLLVMBlocks x ps psubst mb_bps (mb_p':mb_ps) >>> + | [nuMP| PExpr_FieldShape (LLVMFieldShape mb_p) |] <- mb_sh + , sz <- mbExprLLVMTypeWidth mb_p = - -- Move the pointer permission we proved to the top of the stack + -- Recursively prove the remaining block permissions + proveVarLLVMBlocks x ps psubst mb_bps >>> getTopDistPerm x >>>= \(ValPerm_Conj ps') -> - let i = length mb_bps in - implExtractSwapConjM x ps' i >>> - -- Use the SImpl_IntroLLVMBlockField rule to prove the required memblock perm - partialSubstForceM (mbMap2 (,) - mb_bp mb_fp) "proveVarLLVMBlocks" >>>= \(bp,fp) -> + -- Prove the corresponding field permission + proveVarImplInt x (mbMapCl + $(mkClosed [| ValPerm_LLVMField . fromJust . + llvmBlockPermToField sz |]) mb_bp) >>> + getTopDistPerm x >>>= \(ValPerm_LLVMField fp) -> + + -- Finally, convert the field perm to a block and move it into position implSimplM Proxy (SImpl_IntroLLVMBlockField x fp) >>> - - -- Finally, move the memblock perm we proved back into position - implSwapInsertConjM x (Perm_LLVMBlock bp) (deleteNth i ps') 0 + implSwapInsertConjM x (Perm_LLVMBlock $ llvmFieldPermToBlock fp) ps' 0 --- If proving an array shape, just like in the field case, prove the required --- array permission and then pad it out with an empty memblock permission +-- If proving a field shape, prove the remaining blocks and then prove the +-- corresponding array permission proveVarLLVMBlocks2 x ps psubst mb_bp mb_sh mb_bps mb_ps | [nuMP| PExpr_ArrayShape _ _ _ |] <- mb_sh = - - -- Add the array permission to the required permission to mb_ps, and - -- recursively call proveVarLLVMBlocks to prove it and everything else - let mb_ap = fmap llvmArrayBlockToArrayPerm mb_bp in - let mb_p = fmap Perm_LLVMArray mb_ap in - proveVarLLVMBlocks x ps psubst mb_bps (mb_p:mb_ps) >>> - - -- Move the pointer permission we proved to the top of the stack + -- Recursively prove the remaining block permissions + proveVarLLVMBlocks x ps psubst mb_bps >>> getTopDistPerm x >>>= \(ValPerm_Conj ps') -> - let i = length mb_bps in - implExtractSwapConjM x ps' i >>> - -- Use the SImpl_IntroLLVMBlockArray rule to prove the memblock perm - partialSubstForceM (mbMap2 (,) - mb_bp mb_ap) "proveVarLLVMBlocks" >>>= \(bp,ap) -> + -- Prove the corresponding array permission + proveVarImplInt x (mbMapCl $(mkClosed [| ValPerm_LLVMArray . fromJust . + llvmBlockPermToArray |]) mb_bp) >>> + getTopDistPerm x >>>= \(ValPerm_LLVMArray ap) -> + + -- Finally, convert the array perm to a block and move it into position implSimplM Proxy (SImpl_IntroLLVMBlockArray x ap) >>> - - -- Finally, move the memblock perm we proved back into position - implSwapInsertConjM x (Perm_LLVMBlock bp) (deleteNth i ps') 0 + implSwapInsertConjM x (Perm_LLVMBlock $ llvmArrayPermToBlock ap) ps' 0 -- If proving a sequence shape, prove the two shapes and combine them; this -- requires the first shape to have a well-defined length -proveVarLLVMBlocks2 x ps psubst mb_bp mb_sh mb_bps mb_ps +proveVarLLVMBlocks2 x ps psubst mb_bp mb_sh mb_bps | [nuMP| PExpr_SeqShape mb_sh1 _ |] <- mb_sh , mbLift $ fmap (isJust . llvmShapeLength) mb_sh1 = @@ -5943,7 +5953,7 @@ proveVarLLVMBlocks2 x ps psubst mb_bp mb_sh mb_bps mb_ps bp { llvmBlockOffset = bvAdd (llvmBlockOffset bp) len1, llvmBlockLen = bvSub (llvmBlockLen bp) len1, llvmBlockShape = sh2 }]) mb_bp in - proveVarLLVMBlocks x ps psubst (mbList mb_bps12 ++ mb_bps) mb_ps >>> + proveVarLLVMBlocks x ps psubst (mbList mb_bps12 ++ mb_bps) >>> -- Move the block permissions we proved to the top of the stack getTopDistPerm x >>>= \(ValPerm_Conj ps') -> @@ -5964,7 +5974,7 @@ proveVarLLVMBlocks2 x ps psubst mb_bp mb_sh mb_bps mb_ps -- If proving a tagged union shape where we have an equality permission on the -- left that matches one of the disjuncts, prove that disjunct and or it up with -- the other disjuncts -proveVarLLVMBlocks2 x ps psubst mb_bp _ mb_bps mb_ps +proveVarLLVMBlocks2 x ps psubst mb_bp _ mb_bps | [nuMP| Just mb_tag_u |] <- mbMatch $ fmap (asTaggedUnionShape . llvmBlockShape) mb_bp , Just off <- partialSubst psubst $ fmap llvmBlockOffset mb_bp @@ -5974,8 +5984,7 @@ proveVarLLVMBlocks2 x ps psubst mb_bp _ mb_bps mb_ps -- Recursively prove the ith disjunct proveVarLLVMBlocks x ps psubst - (mbMap2 (\bp sh -> bp { llvmBlockShape = sh }) mb_bp mb_sh : mb_bps) - mb_ps >>> + (mbMap2 (\bp sh -> bp { llvmBlockShape = sh }) mb_bp mb_sh : mb_bps) >>> -- Move the block permission with shape mb_sh to the top of the stack getTopDistPerm x >>>= \(ValPerm_Conj ps') -> @@ -5990,7 +5999,7 @@ proveVarLLVMBlocks2 x ps psubst mb_bp _ mb_bps mb_ps -- If proving a disjunctive shape, try to prove one of the disjuncts -proveVarLLVMBlocks2 x ps psubst mb_bp mb_sh mb_bps mb_ps +proveVarLLVMBlocks2 x ps psubst mb_bp mb_sh mb_bps | [nuMP| PExpr_OrShape mb_sh1 mb_sh2 |] <- mb_sh = -- Build a computation that tries returning True here, and if that fails @@ -6000,7 +6009,7 @@ proveVarLLVMBlocks2 x ps psubst mb_bp mb_sh mb_bps mb_ps -- Prove the chosen shape by recursively calling proveVarLLVMBlocks let mb_sh' = if is_case1 then mb_sh1 else mb_sh2 in let mb_bp' = mbMap2 (\bp sh -> bp { llvmBlockShape = sh }) mb_bp mb_sh' in - proveVarLLVMBlocks x ps psubst (mb_bp' : mb_bps) mb_ps >>> + proveVarLLVMBlocks x ps psubst (mb_bp' : mb_bps) >>> -- Move the block permission we proved to the top of the stack getTopDistPerm x >>>= \(ValPerm_Conj ps') -> @@ -6021,7 +6030,7 @@ proveVarLLVMBlocks2 x ps psubst mb_bp mb_sh mb_bps mb_ps -- If proving an existential shape, introduce an evar and recurse -proveVarLLVMBlocks2 x ps psubst mb_bp mb_sh mb_bps mb_ps +proveVarLLVMBlocks2 x ps psubst mb_bp mb_sh mb_bps | [nuMP| PExpr_ExShape mb_mb_sh' |] <- mb_sh = -- Prove the sub-shape in the context of a new existential variable @@ -6030,7 +6039,7 @@ proveVarLLVMBlocks2 x ps psubst mb_bp mb_sh mb_bps mb_ps mbMap2 (\bp mb_sh' -> fmap (\sh -> bp { llvmBlockShape = sh }) mb_sh') mb_bp mb_mb_sh' in - proveVarLLVMBlocksExt1 x ps psubst mb_bp' mb_bps mb_ps >>>= \e -> + proveVarLLVMBlocksExt1 x ps psubst mb_bp' mb_bps >>>= \e -> -- Move the block permission we proved to the top of the stack getTopDistPerm x >>>= \(ValPerm_Conj ps') -> @@ -6049,17 +6058,17 @@ proveVarLLVMBlocks2 x ps psubst mb_bp mb_sh mb_bps mb_ps -- If proving an evar shape that has already been set, substitute and recurse -proveVarLLVMBlocks2 x ps psubst mb_bp mb_sh mb_bps mb_ps +proveVarLLVMBlocks2 x ps psubst mb_bp mb_sh mb_bps | [nuMP| PExpr_Var mb_z |] <- mb_sh , Left memb <- mbNameBoundP mb_z , Just sh <- psubstLookup psubst memb = let mb_bp' = fmap (\bp -> bp { llvmBlockShape = sh }) mb_bp in - proveVarLLVMBlocks x ps psubst (mb_bp' : mb_bps) mb_ps + proveVarLLVMBlocks x ps psubst (mb_bp' : mb_bps) -- If z is unset and len == 0, just set z to the empty shape and recurse in -- order to call the len == 0 empty shape case above -proveVarLLVMBlocks2 x ps psubst mb_bp mb_sh mb_bps mb_ps +proveVarLLVMBlocks2 x ps psubst mb_bp mb_sh mb_bps | [nuMP| PExpr_Var mb_z |] <- mb_sh , Left memb <- mbNameBoundP mb_z , Nothing <- psubstLookup psubst memb @@ -6067,13 +6076,13 @@ proveVarLLVMBlocks2 x ps psubst mb_bp mb_sh mb_bps mb_ps , bvIsZero len = setVarM memb PExpr_EmptyShape >>> let mb_bp' = fmap (\bp -> bp { llvmBlockShape = PExpr_EmptyShape }) mb_bp in - proveVarLLVMBlocks x ps psubst (mb_bp' : mb_bps) mb_ps + proveVarLLVMBlocks x ps psubst (mb_bp' : mb_bps) -- If z is unset and there is a field permission with the required offset and -- length, set z to a field shape with equality permission to an existential -- variable, which is the most general field permission we can make -proveVarLLVMBlocks2 x ps psubst mb_bp mb_sh mb_bps mb_ps +proveVarLLVMBlocks2 x ps psubst mb_bp mb_sh mb_bps | [nuMP| PExpr_Var mb_z |] <- mb_sh , Left memb <- mbNameBoundP mb_z , Nothing <- psubstLookup psubst memb @@ -6090,7 +6099,7 @@ proveVarLLVMBlocks2 x ps psubst mb_bp mb_sh mb_bps mb_ps bp { llvmBlockShape = PExpr_FieldShape $ LLVMFieldShape $ ValPerm_Eq $ PExpr_Var y } in - proveVarLLVMBlocksExt1 x ps psubst mb_bp' mb_bps mb_ps >>>= \e -> + proveVarLLVMBlocksExt1 x ps psubst mb_bp' mb_bps >>>= \e -> -- Set z = fieldsh(eq(e)) where e was the value we determined for y; -- otherwise we are done, because our required block perm is already proved @@ -6101,7 +6110,7 @@ proveVarLLVMBlocks2 x ps psubst mb_bp mb_sh mb_bps mb_ps -- If z is unset and there is an atomic permission with the required offset and -- length (which is not a field permission, because otherwise the previous case -- would match), set z to the shape of that atomic permission and recurse -proveVarLLVMBlocks2 x ps psubst mb_bp mb_sh mb_bps mb_ps +proveVarLLVMBlocks2 x ps psubst mb_bp mb_sh mb_bps | [nuMP| PExpr_Var mb_z |] <- mb_sh , Left memb <- mbNameBoundP mb_z , Nothing <- psubstLookup psubst memb @@ -6114,7 +6123,7 @@ proveVarLLVMBlocks2 x ps psubst mb_bp mb_sh mb_bps mb_ps setVarM memb sh_lhs >>> let mb_bp' = fmap (\bp -> bp { llvmBlockShape = sh_lhs }) mb_bp in - proveVarLLVMBlocks x ps psubst (mb_bp' : mb_bps) mb_ps + proveVarLLVMBlocks x ps psubst (mb_bp' : mb_bps) -- If z is unset and there is an atomic permission with the required offset (but @@ -6122,7 +6131,7 @@ proveVarLLVMBlocks2 x ps psubst mb_bp mb_sh mb_bps mb_ps -- case), split our memblock permission into two memblock permissions with -- unknown shapes but where the first has the length of this atomic permission -- (so the previous case will match), and then recurse -proveVarLLVMBlocks2 x ps psubst mb_bp mb_sh mb_bps mb_ps +proveVarLLVMBlocks2 x ps psubst mb_bp mb_sh mb_bps | [nuMP| PExpr_Var mb_z |] <- mb_sh , Left memb <- mbNameBoundP mb_z , Nothing <- psubstLookup psubst memb @@ -6141,7 +6150,7 @@ proveVarLLVMBlocks2 x ps psubst mb_bp mb_sh mb_bps mb_ps bp { llvmBlockOffset = bvAdd (llvmBlockOffset bp) len1, llvmBlockLen = bvSub (llvmBlockLen bp) len1, llvmBlockShape = PExpr_Var z_sh2 }] in - proveVarLLVMBlocksExt2 x ps psubst mb_bps12 mb_bps mb_ps >>> + proveVarLLVMBlocksExt2 x ps psubst mb_bps12 mb_bps >>> -- Move the two block permissions we proved to the top of the stack getTopDistPerm x >>>= \(ValPerm_Conj ps_ret) -> @@ -6162,11 +6171,10 @@ proveVarLLVMBlocks2 x ps psubst mb_bp mb_sh mb_bps mb_ps implSwapInsertConjM x (Perm_LLVMBlock bp) ps_ret' 0 -proveVarLLVMBlocks2 x ps _ mb_bp _ mb_bps mb_ps = - mbSubstM (\s -> - ValPerm_Conj (map (Perm_LLVMBlock . s) (mb_bp:mb_bps) - ++ map s mb_ps)) >>>= \mb_bps_ps -> - implFailVarM "proveVarLLVMBlock" x (ValPerm_Conj ps) mb_bps_ps +proveVarLLVMBlocks2 x ps _ mb_bp _ mb_bps = + mbSubstM (\s -> ValPerm_Conj (map (Perm_LLVMBlock . s) + (mb_bp:mb_bps))) >>>= \mb_bps' -> + implFailVarM "proveVarLLVMBlock" x (ValPerm_Conj ps) mb_bps' ---------------------------------------------------------------------- diff --git a/heapster-saw/src/Verifier/SAW/Heapster/Permissions.hs b/heapster-saw/src/Verifier/SAW/Heapster/Permissions.hs index e33d4767e3..329de117ac 100644 --- a/heapster-saw/src/Verifier/SAW/Heapster/Permissions.hs +++ b/heapster-saw/src/Verifier/SAW/Heapster/Permissions.hs @@ -3183,20 +3183,70 @@ llvmFieldPermToBlock fp = llvmBlockLen = llvmFieldLen fp, llvmBlockShape = PExpr_FieldShape (LLVMFieldShape $ llvmFieldContents fp) } +-- | Convert a block permission to a field permission, if possible +llvmBlockPermToField :: (1 <= w, KnownNat w, 1 <= sz, KnownNat sz) => + NatRepr sz -> LLVMBlockPerm w -> + Maybe (LLVMFieldPerm w sz) +llvmBlockPermToField sz bp + | PExpr_FieldShape (LLVMFieldShape p) <- llvmBlockShape bp + , Just Refl <- testEquality sz (exprLLVMTypeWidth p) = + Just $ LLVMFieldPerm { llvmFieldRW = llvmBlockRW bp, + llvmFieldLifetime = llvmBlockLifetime bp, + llvmFieldOffset = llvmBlockOffset bp, + llvmFieldContents = p } +llvmBlockPermToField _ _ = Nothing + +-- | Convert an array permission with no borrows to a block permission +llvmArrayPermToBlock :: (1 <= w, KnownNat w) => + LLVMArrayPerm w -> Maybe (LLVMBlockPerm w) +llvmArrayPermToBlock ap + | [] <- llvmArrayBorrows ap = + Just $ LLVMBlockPerm + { llvmBlockRW = llvmArrayRW ap, + llvmBlockLifetime = llvmArrayLifetime ap, + llvmBlockOffset = llvmArrayOffset ap, + llvmBlockLen = bvMult (llvmArrayStride ap) (llvmArrayLen ap), + llvmBlockShape = + PExpr_ArrayShape (llvmArrayLen ap) (llvmArrayStride ap) + (llvmArrayCellShape ap) } +llvmArrayPermToBlock _ = Nothing + +-- | Convert a block permission with array shape to an array permission +llvmBlockPermToArray :: (1 <= w, KnownNat w) => LLVMBlockPerm w -> + Maybe (LLVMArrayPerm w) +llvmBlockPermToArray bp + | PExpr_ArrayShape len stride sh <- llvmBlockShape bp = + Just $ LLVMArrayPerm + { llvmArrayRW = llvmBlockRW bp, + llvmArrayLifetime = llvmBlockLifetime bp, + llvmArrayOffset = llvmBlockOffset bp, + llvmArrayLen = bvMult (toInteger stride) len, + llvmArrayStride = stride, + llvmArrayCellShape = sh, + llvmArrayBorrows = [] } +llvmBlockPermToArray _ = Nothing + +-- | Convert a block permission with statically-known length @len@ to an +-- equivalent array of length 1 with stride @len@ +llvmBlockPermToArray1 :: (1 <= w, KnownNat w) => LLVMBlockPerm w -> + Maybe (LLVMArrayPerm w) +llvmBlockPermToArray1 bp + | stride <- bvMatchConstInt $ llvmBlockLen bp = + Just $ LLVMArrayPerm + { llvmArrayRW = llvmBlockRW bp, + llvmArrayLifetime = llvmBlockLifetime bp, + llvmArrayOffset = llvmBlockOffset bp, + llvmArrayLen = bvInt 1, + llvmArrayStride = fromInteger stride, + llvmArrayCellShape = llvmBlockShape bp, + llvmArrayBorrows = [] } +llvmBlockPermToArray1 _ = Nothing + -- | Convert an atomic permission to a @memblock@, if possible llvmAtomicPermToBlock :: AtomicPerm (LLVMPointerType w) -> Maybe (LLVMBlockPerm w) llvmAtomicPermToBlock (Perm_LLVMField fp) = Just $ llvmFieldPermToBlock fp -llvmAtomicPermToBlock (Perm_LLVMArray ap) - | [] <- llvmArrayBorrows ap - = Just $ LLVMBlockPerm - { llvmBlockRW = llvmArrayRW ap, - llvmBlockLifetime = llvmArrayLifetime ap, - llvmBlockOffset = llvmArrayOffset ap, - llvmBlockLen = bvMult (llvmArrayStride ap) (llvmArrayLen ap), - llvmBlockShape = - PExpr_ArrayShape (llvmArrayLen ap) (llvmArrayStride ap) - (llvmArrayCellShape ap) } +llvmAtomicPermToBlock (Perm_LLVMArray ap) = llvmArrayPermToBlock ap llvmAtomicPermToBlock (Perm_LLVMBlock bp) = Just bp llvmAtomicPermToBlock _ = Nothing @@ -3292,22 +3342,6 @@ llvmShapeLength (PExpr_ExShape mb_sh) = partialSubst (emptyPSubst $ singletonCruCtx $ knownRepr) mb_len _ -> Nothing --- | Convert a @memblock@ permission with array shape to an array permission -llvmArrayBlockToArrayPerm :: (1 <= w, KnownNat w) => LLVMBlockPerm w -> - LLVMArrayPerm w -llvmArrayBlockToArrayPerm bp - | PExpr_ArrayShape len stride sh <- llvmBlockShape bp = - LLVMArrayPerm - { llvmArrayRW = llvmBlockRW bp, - llvmArrayLifetime = llvmBlockLifetime bp, - llvmArrayOffset = llvmBlockOffset bp, - llvmArrayLen = bvMult (toInteger stride) len, - llvmArrayStride = stride, - llvmArrayBorrows = [], - llvmArrayCellShape = sh } -llvmArrayBlockToArrayPerm _ = - error "llvmArrayBlockToArrayPerm: block perm not of array shape" - -- | Adjust the read/write and lifetime modalities of a block permission by -- setting those modalities that are supplied as arguments llvmBlockAdjustModalities :: Maybe (PermExpr RWModalityType) -> @@ -3318,36 +3352,32 @@ llvmBlockAdjustModalities maybe_rw maybe_l bp = l = maybe (llvmBlockLifetime bp) id maybe_l in bp { llvmBlockRW = rw, llvmBlockLifetime = l } --- | Create a field permission for a pointer to a block permission which uses --- the offset, read/write modality, and lifetime of the block permission; that --- is, return +-- | Convert a block permission of pointer shape to the block permission of +-- field shape that it represents. That is, convert the block permission -- --- > [l]ptr((rw,off) |-> [l]memblock(rw,0,len,sh)) -llvmBlockPtrFieldPerm :: (1 <= w, KnownNat w) => LLVMBlockPerm w -> - LLVMFieldPerm w w -llvmBlockPtrFieldPerm bp = - LLVMFieldPerm - { llvmFieldRW = llvmBlockRW bp, - llvmFieldLifetime = llvmBlockLifetime bp, - llvmFieldOffset = llvmBlockOffset bp, - llvmFieldContents = ValPerm_LLVMBlock (bp { llvmBlockOffset = bvInt 0 }) } - --- | Create a pointer atomic permission to a block permission which uses the --- offset, read/write modality, and lifetime of the block permission; that is, --- return +-- > [l]memblock(rw,off,w/8,[l2]ptrsh(rw2,sh)) -- --- > [l]ptr((rw,off) |-> [l]memblock(rw,0,len,sh)) -llvmBlockPtrAtomicPerm :: (1 <= w, KnownNat w) => LLVMBlockPerm w -> - AtomicPerm (LLVMPointerType w) -llvmBlockPtrAtomicPerm bp = Perm_LLVMField $ llvmBlockPtrFieldPerm bp - --- | Create a pointer permission to a block permission which uses the offset, --- read/write modality, and lifetime of the block permission; that is, return +-- to -- --- > [l]ptr((rw,off) |-> [l]memblock(rw,0,len,sh)) -llvmBlockPtrPerm :: (1 <= w, KnownNat w) => LLVMBlockPerm w -> - ValuePerm (LLVMPointerType w) -llvmBlockPtrPerm bp = ValPerm_Conj1 $ llvmBlockPtrAtomicPerm bp +-- > [l]memblock(rw,off,w/8,fieldsh([l2]memblock(rw2,0,sh_len,sh))) +-- +-- where @sh_len@ is the 'llvmShapeLength' of @sh@. It is an error if the input +-- block permission does not have the required form displayed above. +llvmBlockPtrShapeUnfold :: (1 <= w, KnownNat w) => LLVMBlockPerm w -> + Maybe (LLVMBlockPerm w) +llvmBlockPtrShapeUnfold bp + | PExpr_PtrShape maybe_rw maybe_l sh <- llvmBlockShape bp + , Just sh_len <- llvmShapeLength sh + , bvEq (llvmBlockLen bp) (bvInt $ machineWordBytes bp) = + Just $ bp { llvmBlockShape = + PExpr_FieldShape $ LLVMFieldShape $ ValPerm_LLVMBlock $ + LLVMBlockPerm + { llvmBlockRW = maybe (llvmBlockRW bp) id maybe_rw, + llvmBlockLifetime = maybe (llvmBlockLifetime bp) id maybe_l, + llvmBlockOffset = bvInt 0, + llvmBlockLen = sh_len, + llvmBlockShape = sh } } +llvmBlockPtrShapeUnfold _ = Nothing -- | Create a read block permission with shape @sh@, i.e., the 'LLVMBlockPerm' -- corresponding to the permission @memblock(R,0,'llvmShapeLength'(sh),sh)@ From e336c758c33d5799f1475bbe91c02095e349d209 Mon Sep 17 00:00:00 2001 From: Eddy Westbrook Date: Tue, 21 Sep 2021 17:21:22 -0700 Subject: [PATCH 51/98] added support for array permissions in lowned permissions; fixed a few small bugs --- .../src/Verifier/SAW/Heapster/Permissions.hs | 176 ++++++++++++++---- 1 file changed, 144 insertions(+), 32 deletions(-) diff --git a/heapster-saw/src/Verifier/SAW/Heapster/Permissions.hs b/heapster-saw/src/Verifier/SAW/Heapster/Permissions.hs index 329de117ac..53bd215349 100644 --- a/heapster-saw/src/Verifier/SAW/Heapster/Permissions.hs +++ b/heapster-saw/src/Verifier/SAW/Heapster/Permissions.hs @@ -1667,6 +1667,36 @@ data LLVMArrayPerm w = llvmArrayStrideBits :: LLVMArrayPerm w -> Integer llvmArrayStrideBits = toInteger . bytesToBits . llvmArrayStride +-- | Get the rw-modality-in-binding of an array permission in binding +mbLLVMArrayRW :: Mb ctx (LLVMArrayPerm w) -> Mb ctx (PermExpr RWModalityType) +mbLLVMArrayRW = mbMapCl $(mkClosed [| llvmArrayRW |]) + +-- | Get the lifetime-in-binding of an array permission in binding +mbLLVMArrayLifetime :: Mb ctx (LLVMArrayPerm w) -> + Mb ctx (PermExpr LifetimeType) +mbLLVMArrayLifetime = mbMapCl $(mkClosed [| llvmArrayLifetime |]) + +-- | Get the offset-in-binding of an array permission in binding +mbLLVMArrayOffset :: Mb ctx (LLVMArrayPerm w) -> Mb ctx (PermExpr (BVType w)) +mbLLVMArrayOffset = mbMapCl $(mkClosed [| llvmArrayOffset |]) + +-- | Get the length-in-binding of an array permission in binding +mbLLVMArrayLen :: Mb ctx (LLVMArrayPerm w) -> Mb ctx (PermExpr (BVType w)) +mbLLVMArrayLen = mbMapCl $(mkClosed [| llvmArrayLen |]) + +-- | Get the stride of an array permission in binding +mbLLVMArrayStride :: Mb ctx (LLVMArrayPerm w) -> Bytes +mbLLVMArrayStride = mbLift . mbMapCl $(mkClosed [| llvmArrayStride |]) + +-- | Get the cell-shape-in-binding of an array permission in binding +mbLLVMArrayCellShape :: Mb ctx (LLVMArrayPerm w) -> + Mb ctx (PermExpr (LLVMShapeType w)) +mbLLVMArrayCellShape = mbMapCl $(mkClosed [| llvmArrayCellShape |]) + +-- | Get the borrows in a binding for an array permission in binding +mbLLVMArrayBorrows :: Mb ctx (LLVMArrayPerm w) -> Mb ctx [LLVMArrayBorrow w] +mbLLVMArrayBorrows = mbMapCl $(mkClosed [| llvmArrayBorrows |]) + -- | An index or range of indices that are missing from an array perm -- -- FIXME: think about calling the just @LLVMArrayIndexSet@ @@ -1719,6 +1749,8 @@ data LOwnedPerm a where LOwnedPermField :: (1 <= w, KnownNat w, 1 <= sz, KnownNat sz) => PermExpr (LLVMPointerType w) -> LLVMFieldPerm w sz -> LOwnedPerm (LLVMPointerType w) + LOwnedPermArray :: (1 <= w, KnownNat w) => PermExpr (LLVMPointerType w) -> + LLVMArrayPerm w -> LOwnedPerm (LLVMPointerType w) LOwnedPermBlock :: (1 <= w, KnownNat w) => PermExpr (LLVMPointerType w) -> LLVMBlockPerm w -> LOwnedPerm (LLVMPointerType w) @@ -1732,6 +1764,11 @@ instance TestEquality LOwnedPerm where , e1 == e2 && fp1 == fp2 = Just Refl testEquality (LOwnedPermField _ _) _ = Nothing + testEquality (LOwnedPermArray e1 ap1) (LOwnedPermArray e2 ap2) + | Just Refl <- testEquality (exprType e1) (exprType e2) + , e1 == e2 && ap1 == ap2 + = Just Refl + testEquality (LOwnedPermArray _ _) _ = Nothing testEquality (LOwnedPermBlock e1 bp1) (LOwnedPermBlock e2 bp2) | Just Refl <- testEquality (exprType e1) (exprType e2) , e1 == e2 && bp1 == bp2 @@ -1749,6 +1786,8 @@ instance Eq1 LOwnedPerm where lownedPermExprAndPerm :: LOwnedPerm a -> ExprAndPerm a lownedPermExprAndPerm (LOwnedPermField e fp) = ExprAndPerm e $ ValPerm_LLVMField fp +lownedPermExprAndPerm (LOwnedPermArray e ap) = + ExprAndPerm e $ ValPerm_LLVMArray ap lownedPermExprAndPerm (LOwnedPermBlock e bp) = ExprAndPerm e $ ValPerm_LLVMBlock bp @@ -1763,6 +1802,8 @@ lownedPermVarAndPerm _ = Nothing varAndPermLOwnedPerm :: VarAndPerm a -> Maybe (LOwnedPerm a) varAndPermLOwnedPerm (VarAndPerm x (ValPerm_LLVMField fp)) = Just $ LOwnedPermField (PExpr_Var x) fp +varAndPermLOwnedPerm (VarAndPerm x (ValPerm_LLVMArray ap)) = + Just $ LOwnedPermArray (PExpr_Var x) ap varAndPermLOwnedPerm (VarAndPerm x (ValPerm_LLVMBlock bp)) = Just $ LOwnedPermBlock (PExpr_Var x) bp varAndPermLOwnedPerm _ = Nothing @@ -2412,6 +2453,12 @@ data LifetimeFunctor args a where PermExpr (BVType w) -> ValuePerm (LLVMPointerType sz) -> LifetimeFunctor (RNil :> RWModalityType) (LLVMPointerType w) + -- | The functor @\(l,rw) -> [l]array(rw,off, PermExpr (BVType w) -> + PermExpr (BVType w) -> Bytes -> + PermExpr (LLVMShapeType w) -> [LLVMArrayBorrow w] -> + LifetimeFunctor (RNil :> RWModalityType) (LLVMPointerType w) + -- | The functor @\(l,rw) -> [l]memblock(rw,off,len,sh) LTFunctorBlock :: (1 <= w, KnownNat w) => PermExpr (BVType w) -> PermExpr (BVType w) -> @@ -2425,6 +2472,8 @@ ltFuncApply :: LifetimeFunctor args a -> PermExprs args -> PermExpr LifetimeType -> ValuePerm a ltFuncApply (LTFunctorField off p) (MNil :>: rw) l = ValPerm_LLVMField $ LLVMFieldPerm rw l off p +ltFuncApply (LTFunctorArray off len stride sh bs) (MNil :>: rw) l = + ValPerm_LLVMArray $ LLVMArrayPerm rw l off len stride sh bs ltFuncApply (LTFunctorBlock off len sh) (MNil :>: rw) l = ValPerm_LLVMBlock $ LLVMBlockPerm rw l off len sh @@ -2433,6 +2482,8 @@ ltFuncApplyLOP :: ExprVar a -> LifetimeFunctor args a -> PermExprs args -> PermExpr LifetimeType -> LOwnedPerm a ltFuncApplyLOP x (LTFunctorField off p) (MNil :>: rw) l = LOwnedPermField (PExpr_Var x) $ LLVMFieldPerm rw l off p +ltFuncApplyLOP x (LTFunctorArray off len stride sh bs) (MNil :>: rw) l = + LOwnedPermArray (PExpr_Var x) $ LLVMArrayPerm rw l off len stride sh bs ltFuncApplyLOP x (LTFunctorBlock off len sh) (MNil :>: rw) l = LOwnedPermBlock (PExpr_Var x) $ LLVMBlockPerm rw l off len sh @@ -2441,6 +2492,8 @@ ltFuncApplyLOP x (LTFunctorBlock off len sh) (MNil :>: rw) l = ltFuncMinApply :: LifetimeFunctor args a -> PermExpr LifetimeType -> ValuePerm a ltFuncMinApply (LTFunctorField off p) l = ValPerm_LLVMField $ LLVMFieldPerm PExpr_Read l off p +ltFuncMinApply (LTFunctorArray off len stride sh bs) l = + ValPerm_LLVMArray $ LLVMArrayPerm PExpr_Read l off len stride sh bs ltFuncMinApply (LTFunctorBlock off len sh) l = ValPerm_LLVMBlock $ LLVMBlockPerm PExpr_Read l off len sh @@ -2450,6 +2503,8 @@ ltFuncMinApplyLOP :: ExprVar a -> LifetimeFunctor args a -> PermExpr LifetimeType -> LOwnedPerm a ltFuncMinApplyLOP x (LTFunctorField off p) l = LOwnedPermField (PExpr_Var x) $ LLVMFieldPerm PExpr_Read l off p +ltFuncMinApplyLOP x (LTFunctorArray off len stride sh bs) l = + LOwnedPermArray (PExpr_Var x) $ LLVMArrayPerm PExpr_Read l off len stride sh bs ltFuncMinApplyLOP x (LTFunctorBlock off len sh) l = LOwnedPermBlock (PExpr_Var x) $ LLVMBlockPerm PExpr_Read l off len sh @@ -2461,6 +2516,13 @@ fieldToLTFunc :: (1 <= w, KnownNat w, 1 <= sz, KnownNat sz) => fieldToLTFunc fp = (LTFunctorField (llvmFieldOffset fp) (llvmFieldContents fp), MNil :>: llvmFieldRW fp) +-- | Convert an array permission to a lifetime functor and its arguments +arrayToLTFunc :: (1 <= w, KnownNat w) => LLVMArrayPerm w -> + (LifetimeFunctor (RNil :> RWModalityType) (LLVMPointerType w), + PermExprs (RNil :> RWModalityType)) +arrayToLTFunc (LLVMArrayPerm rw _ off len stride sh bs) = + (LTFunctorArray off len stride sh bs, MNil :>: rw) + -- | Convert a block permission to a lifetime functor and its arguments blockToLTFunc :: (1 <= w, KnownNat w) => LLVMBlockPerm w -> (LifetimeFunctor (RNil :> RWModalityType) (LLVMPointerType w), @@ -3231,7 +3293,7 @@ llvmBlockPermToArray _ = Nothing llvmBlockPermToArray1 :: (1 <= w, KnownNat w) => LLVMBlockPerm w -> Maybe (LLVMArrayPerm w) llvmBlockPermToArray1 bp - | stride <- bvMatchConstInt $ llvmBlockLen bp = + | Just stride <- bvMatchConstInt $ llvmBlockLen bp = Just $ LLVMArrayPerm { llvmArrayRW = llvmBlockRW bp, llvmArrayLifetime = llvmBlockLifetime bp, @@ -3242,6 +3304,28 @@ llvmBlockPermToArray1 bp llvmArrayBorrows = [] } llvmBlockPermToArray1 _ = Nothing +-- | Get the permission for a single cell of an array permission +llvmArrayCellPerm :: (1 <= w, KnownNat w) => LLVMArrayPerm w -> + PermExpr (BVType w) -> LLVMBlockPerm w +llvmArrayCellPerm ap cell = + let off = bvAdd (llvmArrayOffset ap) (bvMult (llvmArrayStride ap) cell) in + LLVMBlockPerm { llvmBlockRW = llvmArrayRW ap, + llvmBlockLifetime = llvmArrayLifetime ap, + llvmBlockOffset = off, + llvmBlockLen = bvInt (toInteger $ llvmArrayStride ap), + llvmBlockShape = llvmArrayCellShape ap } + +-- | Get the permission for the first cell of an array permission +llvmArrayPermHead :: (1 <= w, KnownNat w) => LLVMArrayPerm w -> LLVMBlockPerm w +llvmArrayPermHead ap = llvmArrayCellPerm (bvInt 0) + +-- | Get the permission for all of an array permission after the first cell +llvmArrayPermTail :: (1 <= w, KnownNat w) => LLVMArrayPerm w -> LLVMArrayPerm w +llvmArrayPermTail ap = + let off1 = bvInt $ bytesToInteger $ llvmArrayStride ap in + ap { llvmArrayOffset = bvAdd (llvmArrayOffset ap) off1, + llvmArrayLen = bvSub (llvmArrayLen ap) (bvInt 1) } + -- | Convert an atomic permission to a @memblock@, if possible llvmAtomicPermToBlock :: AtomicPerm (LLVMPointerType w) -> Maybe (LLVMBlockPerm w) @@ -3700,25 +3784,13 @@ bytesToMachineWords w n = (n + machineWordBytes w - 1) `div` machineWordBytes w prevMachineWord :: KnownNat w => f w -> Integer -> Integer prevMachineWord w n = (bytesToMachineWords w n - 1) * machineWordBytes w --- | Build the @memblock@ permission that corresponds to a single cell of an --- array permission -blockForLLVMArrayIndex :: (1 <= w, KnownNat w) => LLVMArrayPerm w -> - PermExpr (BVType w) -> LLVMBlockPerm w -blockForLLVMArrayIndex ap ix = - LLVMBlockPerm - { llvmBlockRW = llvmArrayRW ap, - llvmBlockLifetime = llvmArrayLifetime ap, - llvmBlockOffset = llvmArrayCellToAbsOffset ap ix, - llvmBlockLen = bvInt (toInteger $ llvmArrayStride ap), - llvmBlockShape = llvmArrayCellShape ap } - -- | Build the permission that corresponds to a borrow from an array, i.e., that -- would need to be returned in order to remove this borrow. For 'RangeBorrow's, -- that is the sub-array permission with no borrows of its own. permForLLVMArrayBorrow :: (1 <= w, KnownNat w) => LLVMArrayPerm w -> LLVMArrayBorrow w -> ValuePerm (LLVMPointerType w) -permForLLVMArrayBorrow ap (FieldBorrow ix) = - ValPerm_LLVMBlock $ blockForLLVMArrayIndex ap ix +permForLLVMArrayBorrow ap (FieldBorrow cell) = + ValPerm_LLVMBlock $ llvmArrayCellPerm ap cell permForLLVMArrayBorrow ap (RangeBorrow (BVRange off len)) = ValPerm_Conj1 $ Perm_LLVMArray $ ap { llvmArrayOffset = llvmArrayCellToOffset ap off, @@ -3805,11 +3877,9 @@ matchLLVMArrayIndex ap o = bvMatchFactorPlusConst (bytesToInteger $ llvmArrayStride ap) rel_off return $ LLVMArrayIndex ix cell_off --- | Return a list 'BVProp' stating that the field(s) represented by an array --- borrow are in the "base" set of fields in an array, before the borrows are --- considered. We assume that the borrow is statically well-formed for that --- array, meaning that the static field number of a 'FieldBorrow' refers to a --- valid field in the array perm. +-- | Return a list 'BVProp' stating that the cell(s) represented by an array +-- borrow are in the "base" set of cells in an array, before the borrows are +-- considered llvmArrayBorrowInArrayBase :: (1 <= w, KnownNat w) => LLVMArrayPerm w -> LLVMArrayBorrow w -> [BVProp w] @@ -3848,6 +3918,12 @@ llvmArrayIndexInArray :: (1 <= w, KnownNat w) => LLVMArrayPerm w -> llvmArrayIndexInArray ap ix = llvmArrayBorrowInArray ap (FieldBorrow $ llvmArrayIndexCell ix) +-- | Test if a cell is in an array permission and is not currently being +-- borrowed +llvmArrayCellInArray :: (1 <= w, KnownNat w) => PermExpr (BVType w) -> + BVRange w -> [BVProp w] +llvmArrayCellInArray ap cell = llvmArrayBorrowInArray ap (FieldBorrow cell) + -- | Test if all cell numbers in a 'BVRange' are in an array permission and are -- not currently being borrowed llvmArrayCellsInArray :: (1 <= w, KnownNat w) => LLVMArrayPerm w -> @@ -3898,30 +3974,48 @@ llvmArrayContainsArray ap sub_ap = -- | Test if an atomic LLVM permission potentially allows a read or write of a -- given offset. If so, return a list of the propositions required for the read --- to be allowed. For LLVM field permissions, the offset of the field must --- statically match the supplied offset, so the list of propositions will be --- empty, while for arrays, the offset must only /not/ match any outstanding --- borrows, and the propositions returned codify that as well as the requirement --- that the offset is in the array range. +-- to be allowed, and whether the propositions definitely hold (as in +-- 'bvPropHolds') or only could hold (as in 'bvPropCouldHold'). For LLVM field +-- permissions, the offset of the field must statically match the supplied +-- offset, so the list of propositions will be empty, while for arrays, the +-- offset must only /not/ match any outstanding borrows, and the propositions +-- returned codify that as well as the requirement that the offset is in the +-- array range. llvmPermContainsOffset :: (1 <= w, KnownNat w) => PermExpr (BVType w) -> - AtomicPerm (LLVMPointerType w) -> Maybe [BVProp w] + AtomicPerm (LLVMPointerType w) -> + Maybe ([BVProp w], Bool) llvmPermContainsOffset off (Perm_LLVMField fp) - | bvEq (llvmFieldOffset fp) off = Just [] + | bvEq (llvmFieldOffset fp) off = Just ([], True) llvmPermContainsOffset off (Perm_LLVMArray ap) | Just ix <- matchLLVMArrayIndex ap off , props <- llvmArrayIndexInArray ap ix , all bvPropCouldHold props = - Just props + Just (props, all bvPropHolds props) llvmPermContainsOffset off (Perm_LLVMBlock bp) | prop <- bvPropInRange off (llvmBlockRange bp) , bvPropCouldHold prop = - Just [prop] + Just ([prop], bvPropHolds prop) llvmPermContainsOffset _ _ = Nothing +-- | Search through a list of permissions for either some permission that +-- definitely contains (as in 'bvPropHolds') the given offset or, failing that, +-- and if the supplied 'Bool' flag is 'True', for all permissions that could (as +-- in 'bvPropCouldHold') contain the given offset. Return the indices in the +-- list for the permissions that were found. +llvmPermIndicesForOffset :: (1 <= w, KnownNat w) => + [AtomicPerm (LLVMPointerType w)] -> Bool -> + PermExpr (BVType w) -> [Int] +llvmPermIndicesForOffset ps imprecise_p off = + let ixs_props = findMaybeIndices (llvmPermContainsOffset off) ps in + case findIndex (\(_,(_,holds)) -> holds) ixs_props of + Just i -> [i] + Nothing | imprecise_p -> map fst ixs_props + Nothing -> [] + -- | Return the total length of an LLVM array permission in bytes llvmArrayLengthBytes :: (1 <= w, KnownNat w) => LLVMArrayPerm w -> PermExpr (BVType w) -llvmArrayLengthBytes ap = llvmArrayCellToAbsOffset ap (llvmArrayLen ap) +llvmArrayLengthBytes ap = llvmArrayCellToOffset ap (llvmArrayLen ap) -- | Return the byte offset of an array index from the beginning of the array llvmArrayIndexByteOffset :: (1 <= w, KnownNat w) => LLVMArrayPerm w -> @@ -3935,7 +4029,7 @@ llvmArrayToBlocks :: (1 <= w, KnownNat w) => LLVMArrayPerm w -> Maybe [LLVMBlockPerm w] llvmArrayToBlocks ap | Just len <- bvMatchConstInt $ llvmArrayLen ap = - Just $ map (blockForLLVMArrayIndex ap . bvInt) [0..len-1] + Just $ map (llvmArrayCellPerm ap . bvInt) [0..len-1] llvmArrayToBlocks _ = Nothing -- | Get the range of byte offsets represented by an array borrow relative to @@ -3943,7 +4037,7 @@ llvmArrayToBlocks _ = Nothing llvmArrayBorrowOffsets :: (1 <= w, KnownNat w) => LLVMArrayPerm w -> LLVMArrayBorrow w -> BVRange w llvmArrayBorrowOffsets ap (FieldBorrow ix) = - bvRangeOfIndex $ llvmArrayCellToAbsOffset ap ix + bvRangeOfIndex $ llvmArrayCellToOffset ap ix llvmArrayBorrowOffsets ap (RangeBorrow r) = llvmArrayCellsToOffsets ap r -- | Get the range of byte offsets represented by an array borrow relative to @@ -4433,6 +4527,11 @@ lownedPermCouldProve (LOwnedPermField (PExpr_Var x) fp) ps = bvCouldBeInRange (llvmFieldOffset fp) rng _ -> False) $ varAtomicPermsInDistPerms x ps +lownedPermCouldProve (LOwnedPermArray (PExpr_Var x) ap) ps = + any (\case (llvmAtomicPermRange -> Just rng) -> + bvRangesCouldOverlap (llvmArrayAbsOffsets ap) rng + _ -> False) $ + varAtomicPermsInDistPerms x ps lownedPermCouldProve (LOwnedPermBlock (PExpr_Var x) bp) ps = any (\case (llvmAtomicPermRange -> Just rng) -> bvRangesCouldOverlap (llvmBlockRange bp) rng @@ -4657,6 +4756,8 @@ instance FreeVars (PermOffset tp) where instance FreeVars (LOwnedPerm a) where freeVars (LOwnedPermField e fp) = NameSet.unions [freeVars e, freeVars fp] + freeVars (LOwnedPermArray e ap) = + NameSet.unions [freeVars e, freeVars ap] freeVars (LOwnedPermBlock e bp) = NameSet.unions [freeVars e, freeVars bp] @@ -5113,6 +5214,8 @@ instance SubstVar s m => Substable s (LOwnedPerm a) m where genSubst s mb_x = case mbMatch mb_x of [nuMP| LOwnedPermField e fp |] -> LOwnedPermField <$> genSubst s e <*> genSubst s fp + [nuMP| LOwnedPermArray e ap |] -> + LOwnedPermArray <$> genSubst s e <*> genSubst s ap [nuMP| LOwnedPermBlock e bp |] -> LOwnedPermBlock <$> genSubst s e <*> genSubst s bp @@ -5166,6 +5269,9 @@ instance SubstVar s m => Substable s (LifetimeFunctor args a) m where genSubst s mb_x = case mbMatch mb_x of [nuMP| LTFunctorField off p |] -> LTFunctorField <$> genSubst s off <*> genSubst s p + [nuMP| LTFunctorArray off len stride sh bs |] -> + LTFunctorArray <$> genSubst s off <*> genSubst s len <*> + return (mbLift stride) <*> genSubst s sh <*> genSubst s bs [nuMP| LTFunctorBlock off len sh |] -> LTFunctorBlock <$> genSubst s off <*> genSubst s len <*> genSubst s sh @@ -5866,6 +5972,10 @@ instance AbstractVars (LOwnedPerm a) where absVarsReturnH ns1 ns2 $(mkClosed [| LOwnedPermField |]) `clMbMbApplyM` abstractPEVars ns1 ns2 e `clMbMbApplyM` abstractPEVars ns1 ns2 fp + abstractPEVars ns1 ns2 (LOwnedPermArray e ap) = + absVarsReturnH ns1 ns2 $(mkClosed [| LOwnedPermArray |]) + `clMbMbApplyM` abstractPEVars ns1 ns2 e + `clMbMbApplyM` abstractPEVars ns1 ns2 ap abstractPEVars ns1 ns2 (LOwnedPermBlock e bp) = absVarsReturnH ns1 ns2 $(mkClosed [| LOwnedPermBlock |]) `clMbMbApplyM` abstractPEVars ns1 ns2 e @@ -6082,6 +6192,8 @@ instance AbstractNamedShape w (LOwnedPerms ps) where instance AbstractNamedShape w (LOwnedPerm a) where abstractNSM (LOwnedPermField e fp) = mbMap2 LOwnedPermField <$> abstractNSM e <*> abstractNSM fp + abstractNSM (LOwnedPermArray e ap) = + mbMap2 LOwnedPermArray <$> abstractNSM e <*> abstractNSM ap abstractNSM (LOwnedPermBlock e bp) = mbMap2 LOwnedPermBlock <$> abstractNSM e <*> abstractNSM bp From e1599172fff903030740c934aa7888ad57a5961d Mon Sep 17 00:00:00 2001 From: Eddy Westbrook Date: Tue, 21 Sep 2021 17:21:44 -0700 Subject: [PATCH 52/98] more work moving two arrays with shapes for their cells --- .../src/Verifier/SAW/Heapster/Implication.hs | 833 ++++++++++-------- 1 file changed, 467 insertions(+), 366 deletions(-) diff --git a/heapster-saw/src/Verifier/SAW/Heapster/Implication.hs b/heapster-saw/src/Verifier/SAW/Heapster/Implication.hs index b95531805f..28e122f853 100644 --- a/heapster-saw/src/Verifier/SAW/Heapster/Implication.hs +++ b/heapster-saw/src/Verifier/SAW/Heapster/Implication.hs @@ -596,6 +596,15 @@ data SimplImpl ps_in ps_out where ExprVar (LLVMPointerType w) -> LLVMFieldPerm w sz -> SimplImpl (RNil :> LLVMPointerType w) (RNil :> LLVMPointerType w) + -- | Demote an LLVM array permission to read modality: + -- + -- > x:[l]array(rw,off, -o x:[l]array(R,off, + ExprVar (LLVMPointerType w) -> LLVMArrayPerm w -> + SimplImpl (RNil :> LLVMPointerType w) (RNil :> LLVMPointerType w) + -- | Copy an array permission out of a larger array permission, assuming that -- all fields of the array are copyable, using a proof that the copied array -- permission is contained in the larger one as per 'llvmArrayContainsArray', @@ -603,10 +612,10 @@ data SimplImpl ps_in ps_out where -- and that all borrows in the larger one are either preserved in the smaller -- or are disjoint from it: -- - -- > x:ar1=array(off1, x:ar1=array(off1, * x:prop('llvmArrayContainsArray' ar1 ar2) - -- > -o x:ar2=array(off2, * x:ar1=array(off1, -o x:ar2=[l]array(rw,off2, * x:ar1=[l]array(rw,off1, ExprVar (LLVMPointerType w) -> LLVMArrayPerm w -> LLVMArrayPerm w -> @@ -619,10 +628,10 @@ data SimplImpl ps_in ps_out where -- contained in the larger one and that all borrows in the larger one are -- either preserved in the smaller or are disjoint from it: -- - -- > x:ar1=array(off1, x:ar1=[l]array(rw,off1, * x:prop('llvmArrayContainsArray' ar1 ar2) - -- > -o x:ar2=array(off2, * x:array(off1, -o x:ar2=[l]array(rw,off2, * x:[l]array(rw,off1, ExprVar (LLVMPointerType w) -> LLVMArrayPerm w -> LLVMArrayPerm w -> @@ -631,9 +640,9 @@ data SimplImpl ps_in ps_out where -- | Return a borrowed range of an array permission, undoing a borrow: -- - -- > x:array(off2, * x:array(off1, -o x:array(off, x:[l]array(rw,off2, * x:[l]array(rw,off1, -o x:[l]array(rw,off, ExprVar (LLVMPointerType w) -> LLVMArrayPerm w -> LLVMArrayPerm w -> @@ -643,9 +652,9 @@ data SimplImpl ps_in ps_out where -- | Append two array permissions, assuming one ends where the other begins -- and that they have the same stride and fields: -- - -- > x:array(off1, * x:array(off2=off1+len*stride*word_size, -o x:array(off1, x:[l]array(rw, off1, * x:[l]array(rw,off2=off1+len*stride*word_size, -o x:[l]array(rw,off1, ExprVar (LLVMPointerType w) -> LLVMArrayPerm w -> LLVMArrayPerm w -> @@ -654,8 +663,8 @@ data SimplImpl ps_in ps_out where -- | Rearrange the order of the borrows in an array permission: -- - -- > x:array(off, -o x:array(off, x:[l]array(rw,off, -o x:[l]array(rw,off, ExprVar (LLVMPointerType w) -> LLVMArrayPerm w -> [LLVMArrayBorrow w] -> @@ -663,7 +672,7 @@ data SimplImpl ps_in ps_out where -- | Prove an empty array with length 0: -- - -- > -o x:array(off,<0,*stride,fps,[]) + -- > -o x:[l]array(rw,off,<0,*stride,sh,bs) SImpl_LLVMArrayEmpty :: (1 <= w, KnownNat w) => ExprVar (LLVMPointerType w) -> LLVMArrayPerm w -> @@ -687,48 +696,44 @@ data SimplImpl ps_in ps_out where ExprVar (LLVMPointerType w) -> LLVMBlockPerm w -> SimplImpl (RNil :> LLVMPointerType w) (RNil :> LLVMPointerType w) - -- | Copy out the @i@th cell of an array - -- permission, assuming it is copyable, where @j@ - -- is a static 'Int' and @i@ is an expression. Requires a proposition - -- permission on the top of the stack stating that @i@ is in the range of the - -- array and that the specified field permission does not overlap with any of - -- the existing borrows: + -- | Copy out the @i@th cell of an array permission, assuming it is + -- copyable. Requires a proposition permission on the top of the stack stating + -- that @i@ is in the range of the array and that it does not overlap with any + -- of the existing borrows: -- - -- > x:array(off, * x:(prop(i \in [off,len)) * disjoint(bs,i*stride+offset(fp_j))) - -- > -o x:(fp_j + off + i*stride) * x:array(off, x:[l]array(R,off, * x:(prop(i \in [off,len)) * disjoint(bs,i*stride)) + -- > -o x:[l]memblock(R,off + i*stride,stride,sh) + -- > * x:array(off, - ExprVar (LLVMPointerType w) -> LLVMArrayPerm w -> LLVMArrayIndex w -> + ExprVar (LLVMPointerType w) -> LLVMArrayPerm w -> PermExpr (BVType w) -> SimplImpl (RNil :> LLVMPointerType w :> LLVMPointerType w) (RNil :> LLVMPointerType w :> LLVMPointerType w) - -- | Borrow the @j@th field permission of the @i@th element of an array - -- permission, where @j@ is a static 'Int' and @i@ is an expression. Requires - -- a proposition permission on the top of the stack stating that @i@ is in the - -- range of the array and that the specified field permission does not overlap - -- with any of the existing borrows, and adds a borrow of the given field: + -- | Borrow the @i@th cell an array permission. Requires a proposition + -- permission on the top of the stack stating that @i@ is in the range of the + -- array and that it does not overlap with any of the existing borrows, and + -- adds a borrow of the given field: -- - -- > x:array(off, * x:(prop(i \in [off,len)) * disjoint(bs,i*stride+offset(fp_j))) - -- > -o x:(fp_j + off + i*stride) - -- > * x:array(off, x:[l]array(rw,off, * x:(prop(i \in [off,len)) * disjoint(bs,i*stride)) + -- > -o x:[l]memblock(rw,off + i*stride,stride,sh) + -- > * x:[l]array(rw,off, - ExprVar (LLVMPointerType w) -> LLVMArrayPerm w -> LLVMArrayIndex w -> + ExprVar (LLVMPointerType w) -> LLVMArrayPerm w -> PermExpr (BVType w) -> SimplImpl (RNil :> LLVMPointerType w :> LLVMPointerType w) (RNil :> LLVMPointerType w :> LLVMPointerType w) - -- | Return the @j@th field permission of the @i@th element of an array - -- permission, where @j@ is a static 'Int' and @i@ is an expression, undoing a - -- borrow: + -- | Return the @i@th cell of an array permission, undoing a borrow: -- - -- > x:(fp_j + offset + i*stride) - -- > * x:array(off, -o x:array(off, x:[l]memblock(rw,off + i*stride,stride,sh) + -- > * x:[l]array(rw,off, -o x:[l]array(rw,off, - ExprVar (LLVMPointerType w) -> LLVMArrayPerm w -> LLVMArrayIndex w -> + ExprVar (LLVMPointerType w) -> LLVMArrayPerm w -> PermExpr (BVType w) -> SimplImpl (RNil :> LLVMPointerType w :> LLVMPointerType w) (RNil :> LLVMPointerType w) @@ -1619,6 +1624,8 @@ simplImplIn (SImpl_IntroLLVMFieldContents x y fld) = y (llvmFieldContents fld) simplImplIn (SImpl_DemoteLLVMFieldRW x fld) = distPerms1 x (ValPerm_Conj [Perm_LLVMField fld]) +simplImplIn (SImpl_DemoteLLVMArrayRW x ap) = + distPerms1 x (ValPerm_Conj [Perm_LLVMArray ap]) simplImplIn (SImpl_LLVMArrayCopy x ap sub_ap) = if isJust (llvmArrayIsOffsetArray ap sub_ap) && atomicPermIsCopyable (Perm_LLVMArray ap) then @@ -1659,37 +1666,29 @@ simplImplIn (SImpl_LLVMArrayToField x ap _) = distPerms1 x (ValPerm_Conj1 $ Perm_LLVMArray ap) simplImplIn (SImpl_LLVMArrayEmpty _ ap) = - if bvEq (llvmArrayLen ap) (bvInt 0) && llvmArrayBorrows ap == [] then - DistPermsNil - else + if bvIsZero (llvmArrayLen ap) then DistPermsNil else error "simplImplIn: SImpl_LLVMArrayEmpty: malformed empty array permission" simplImplIn (SImpl_LLVMArrayFromBlock x bp) = distPerms1 x $ ValPerm_LLVMBlock bp -simplImplIn (SImpl_LLVMArrayIndexCopy x ap ix) = - if llvmArrayIndexFieldNum ix < length (llvmArrayFields ap) && - atomicPermIsCopyable (llvmArrayFieldToAtomicPerm $ - llvmArrayFieldWithOffset ap ix) then - distPerms2 x (ValPerm_Conj [Perm_LLVMArray ap]) - x (ValPerm_Conj $ map Perm_BVProp $ llvmArrayIndexInArray ap ix) +simplImplIn (SImpl_LLVMArrayCellCopy x ap cell) = + if atomicPermIsCopyable (Perm_LLVMArray ap) then + distPerms2 x (ValPerm_LLVMArray ap) + x (ValPerm_Conj $ map Perm_BVProp $ llvmArrayCellInArray ap cell) else - if llvmArrayIndexFieldNum ix >= length (llvmArrayFields ap) then - error "simplImplIn: SImpl_LLVMArrayIndexCopy: index out of range" - else - error "simplImplIn: SImpl_LLVMArrayIndexCopy: field is not copyable" + error "simplImplIn: SImpl_LLVMArrayCellCopy: array is not copyable" -simplImplIn (SImpl_LLVMArrayIndexBorrow x ap ix) = +simplImplIn (SImpl_LLVMArrayCellBorrow x ap cell) = distPerms2 x (ValPerm_Conj [Perm_LLVMArray ap]) - x (ValPerm_Conj $ map Perm_BVProp $ llvmArrayIndexInArray ap ix) + x (ValPerm_Conj $ map Perm_BVProp $ llvmArrayCellInArray ap cell) -simplImplIn (SImpl_LLVMArrayIndexReturn x ap ix) = - if elem (FieldBorrow ix) (llvmArrayBorrows ap) then - distPerms2 x (ValPerm_Conj1 $ llvmArrayFieldToAtomicPerm $ - llvmArrayFieldWithOffset ap ix) +simplImplIn (SImpl_LLVMArrayCellReturn x ap cell) = + if elem (FieldBorrow cell) (llvmArrayBorrows ap) then + distPerms2 x (ValPerm_LLVMBlock $ llvmArrayCellPerm ap cell) x (ValPerm_Conj [Perm_LLVMArray ap]) else - error "simplImplIn: SImpl_LLVMArrayIndexReturn: index not being borrowed" + error "simplImplIn: SImpl_LLVMArrayCellReturn: index not being borrowed" simplImplIn (SImpl_LLVMArrayContents x ap _ _) = distPerms1 x (ValPerm_Conj [Perm_LLVMArray ap]) @@ -1907,6 +1906,9 @@ simplImplOut (SImpl_IntroLLVMFieldContents x _ fld) = simplImplOut (SImpl_DemoteLLVMFieldRW x fld) = distPerms1 x (ValPerm_Conj [Perm_LLVMField $ fld { llvmFieldRW = PExpr_Read }]) +simplImplOut (SImpl_DemoteLLVMArrayRW x ap) = + distPerms1 x (ValPerm_Conj [Perm_LLVMArray $ + ap { llvmArrayRW = PExpr_Read }]) simplImplOut (SImpl_LLVMArrayCopy x ap sub_ap) = if isJust (llvmArrayIsOffsetArray ap sub_ap) && atomicPermIsCopyable (Perm_LLVMArray ap) then @@ -1960,41 +1962,32 @@ simplImplOut (SImpl_LLVMArrayToField x ap sz) = error "simplImplOut: SImpl_LLVMArrayToField: malformed array permission" simplImplOut (SImpl_LLVMArrayEmpty x ap) = - if bvEq (llvmArrayLen ap) (bvInt 0) && llvmArrayBorrows ap == [] then + if bvIsZero (llvmArrayLen ap) then distPerms1 x (ValPerm_Conj1 $ Perm_LLVMArray ap) else error "simplImplOut: SImpl_LLVMArrayEmpty: malformed empty array permission" -simplImplIn (SImpl_LLVMArrayFromBlock x bp) = +simplImplOut (SImpl_LLVMArrayFromBlock x bp) = case llvmBlockPermToArray1 bp of Just ap -> distPerms1 x $ ValPerm_LLVMArray ap _ -> error "simplImplOut: SImpl_LLVMArrayOneCell: block perm with non-static length" -simplImplOut (SImpl_LLVMArrayIndexCopy x ap ix) = - if llvmArrayIndexFieldNum ix < length (llvmArrayFields ap) && - atomicPermIsCopyable (llvmArrayFieldToAtomicPerm $ - llvmArrayFieldWithOffset ap ix) then - distPerms2 x (ValPerm_Conj1 $ llvmArrayFieldToAtomicPerm $ - llvmArrayFieldWithOffset ap ix) - x (ValPerm_Conj [Perm_LLVMArray ap]) +simplImplOut (SImpl_LLVMArrayCellCopy x ap cell) = + if atomicPermIsCopyable (Perm_LLVMArray ap) then + distPerms2 x (ValPerm_LLVMBlock $ llvmArrayCellPerm ap cell) + x (ValPerm__LLVMArray ap) else - if llvmArrayIndexFieldNum ix >= length (llvmArrayFields ap) then - error "simplImplOut: SImpl_LLVMArrayIndexCopy: index out of range" - else - error "simplImplOut: SImpl_LLVMArrayIndexCopy: field is not copyable" + error "simplImplOut: SImpl_LLVMArrayCellCopy: array is not copyable" -simplImplOut (SImpl_LLVMArrayIndexBorrow x ap ix) = - distPerms2 x (ValPerm_Conj1 $ llvmArrayFieldToAtomicPerm $ - llvmArrayFieldWithOffset ap ix) - x (ValPerm_Conj [Perm_LLVMArray $ - llvmArrayAddBorrow (FieldBorrow ix) ap]) +simplImplOut (SImpl_LLVMArrayCellBorrow x ap cell) = + distPerms2 x (ValPerm_LLVMBlock $ llvmArrayCellPerm ap cell) + x (ValPerm_LLVMArray $ llvmArrayAddBorrow (FieldBorrow cell) ap) -simplImplOut (SImpl_LLVMArrayIndexReturn x ap ix) = - if elem (FieldBorrow ix) (llvmArrayBorrows ap) then - distPerms1 x - (ValPerm_Conj [Perm_LLVMArray $ llvmArrayRemBorrow (FieldBorrow ix) ap]) +simplImplOut (SImpl_LLVMArrayCellReturn x ap cell) = + if elem (FieldBorrow cell) (llvmArrayBorrows ap) then + distPerms1 x (ValPerm_LLVMArray $ llvmArrayRemBorrow (FieldBorrow cell) ap) else - error "simplImplOut: SImpl_LLVMArrayIndexReturn: index not being borrowed" + error "simplImplOut: SImpl_LLVMArrayCellReturn: index not being borrowed" simplImplOut (SImpl_LLVMArrayContents x ap sh _) = distPerms1 x (ValPerm_Conj [Perm_LLVMArray $ ap { llvmArrayCellShape = sh }]) @@ -2373,6 +2366,8 @@ instance SubstVar PermVarSubst m => genSubst s fld [nuMP| SImpl_DemoteLLVMFieldRW x fld |] -> SImpl_DemoteLLVMFieldRW <$> genSubst s x <*> genSubst s fld + [nuMP| SImpl_DemoteLLVMArrayRW x ap |] -> + SImpl_DemoteLLVMArrayRW <$> genSubst s x <*> genSubst s ap [nuMP| SImpl_LLVMArrayCopy x ap rng |] -> SImpl_LLVMArrayCopy <$> genSubst s x <*> genSubst s ap <*> genSubst s rng [nuMP| SImpl_LLVMArrayBorrow x ap rng |] -> @@ -2390,14 +2385,14 @@ instance SubstVar PermVarSubst m => SImpl_LLVMArrayEmpty <$> genSubst s x <*> genSubst s ap [nuMP| SImpl_LLVMArrayFromBlock x bp |] -> SImpl_LLVMArrayFromBlock <$> genSubst s x <*> genSubst s bp - [nuMP| SImpl_LLVMArrayIndexCopy x ap ix |] -> - SImpl_LLVMArrayIndexCopy <$> genSubst s x <*> genSubst s ap <*> genSubst s ix - [nuMP| SImpl_LLVMArrayIndexBorrow x ap ix |] -> - SImpl_LLVMArrayIndexBorrow <$> genSubst s x <*> genSubst s ap <*> - genSubst s ix - [nuMP| SImpl_LLVMArrayIndexReturn x ap ix |] -> - SImpl_LLVMArrayIndexReturn <$> genSubst s x <*> genSubst s ap <*> - genSubst s ix + [nuMP| SImpl_LLVMArrayCellCopy x ap cell |] -> + SImpl_LLVMArrayCellCopy <$> genSubst s x <*> genSubst s ap <*> genSubst s cell + [nuMP| SImpl_LLVMArrayCellBorrow x ap cell |] -> + SImpl_LLVMArrayCellBorrow <$> genSubst s x <*> genSubst s ap <*> + genSubst s cell + [nuMP| SImpl_LLVMArrayCellReturn x ap cell |] -> + SImpl_LLVMArrayCellReturn <$> genSubst s x <*> genSubst s ap <*> + genSubst s cell [nuMP| SImpl_LLVMArrayContents x ap sh mb_mb_impl |] -> SImpl_LLVMArrayContents <$> genSubst s x <*> genSubst s ap <*> genSubst s sh <*> genSubst s mb_mb_impl @@ -2863,11 +2858,12 @@ getPerms = use implStatePerms getPerm :: ExprVar a -> ImplM vars s r ps ps (ValuePerm a) getPerm x = use (implStatePerms . varPerm x) --- | Get the pointer permissions for a variable @x@, assuming @x@ has LLVM --- pointer permissions -getLLVMPtrPerms :: ExprVar (LLVMPointerType w) -> - ImplM vars s r ps ps [LLVMPtrPerm w] -getLLVMPtrPerms x = use (implStatePerms . varPerm x . llvmPtrPerms) +-- | Look up the current permission for a given variable, assuming it has a +-- conjunctive permissions, and return the conjuncts +getAtomicPerms :: ExprVar a -> ImplM vars s r ps ps (ValuePerm a) +getAtomicPerms x = getPerm >>= \case + ValPerm_Conj ps -> return ps + _ -> error "getAtomicPerms: non-conjunctive permission" -- | Get the distinguished permission stack getDistPerms :: ImplM vars s r ps ps (DistPerms ps) @@ -3835,9 +3831,9 @@ introLLVMFieldContentsM :: introLLVMFieldContentsM x y fp = implSimplM Proxy (SImpl_IntroLLVMFieldContents x y fp) --- | Borrow a field from an LLVM array permission on the top of the stack, after +-- | Borrow a cell from an LLVM array permission on the top of the stack, after -- proving (with 'implTryProveBVProps') that the index is in the array exclusive --- of any outstanding borrows (see 'llvmArrayIndexInArray'). Return the +-- of any outstanding borrows (see 'llvmArrayCellInArray'). Return the -- resulting array permission with the borrow and the borrowed cell permission, -- leaving the array permission on top of the stack and the cell permission just -- below it on the stack. @@ -3846,34 +3842,34 @@ implLLVMArrayCellBorrow :: ExprVar (LLVMPointerType w) -> LLVMArrayPerm w -> PermExpr (BVType w) -> ImplM vars s r (ps :> LLVMPointerType w :> LLVMPointerType w) (ps :> LLVMPointerType w) (LLVMArrayPerm w, LLVMBlockPerm w) -implLLVMArrayIndexBorrow x ap cell = +implLLVMArrayCellBorrow x ap cell = implTryProveBVProps x (llvmArrayCellInArray ap cell) >>> - implSimplM Proxy (SImpl_LLVMArrayIndexBorrow x ap cell) >>> - pure (llvmArrayAddBorrow (FieldBorrow ix) ap, - blockForLLVMArrayCell ap cell) + implSimplM Proxy (SImpl_LLVMArrayCellBorrow x ap cell) >>> + pure (llvmArrayAddBorrow (FieldBorrow cell) ap, + llvmArrayCellPerm ap cell) --- | Copy a field from an LLVM array permission on the top of the stack, after +-- | Copy a cell from an LLVM array permission on the top of the stack, after -- proving (with 'implTryProveBVProps') that the index is in the array exclusive --- of any outstanding borrows (see 'llvmArrayIndexInArray') -implLLVMArrayIndexCopy :: +-- of any outstanding borrows (see 'llvmArrayCellInArray') +implLLVMArrayCellCopy :: (1 <= w, KnownNat w, NuMatchingAny1 r) => - ExprVar (LLVMPointerType w) -> LLVMArrayPerm w -> LLVMArrayIndex w -> + ExprVar (LLVMPointerType w) -> LLVMArrayPerm w -> PermExpr (BVType w) -> ImplM vars s r (ps :> LLVMPointerType w :> LLVMPointerType w) (ps :> LLVMPointerType w) () -implLLVMArrayIndexCopy x ap ix = - implTryProveBVProps x (llvmArrayIndexInArray ap ix) >>> - implSimplM Proxy (SImpl_LLVMArrayIndexCopy x ap ix) - --- | Return a field permission that has been borrowed from an array permission, --- where the array permission is on the top of the stack and the field --- permission borrowed from it is just below it -implLLVMArrayIndexReturn :: +implLLVMArrayCellCopy x ap cell = + implTryProveBVProps x (llvmArrayCellInArray ap cell) >>> + implSimplM Proxy (SImpl_LLVMArrayCellCopy x ap cell) + +-- | Return a cell that has been borrowed from an array permission, where the +-- array permission is on the top of the stack and the cell permission borrowed +-- from it is just below it +implLLVMArrayCellReturn :: (1 <= w, KnownNat w, NuMatchingAny1 r) => - ExprVar (LLVMPointerType w) -> LLVMArrayPerm w -> LLVMArrayIndex w -> + ExprVar (LLVMPointerType w) -> LLVMArrayPerm w -> PermExpr (BVType w) -> ImplM vars s r (ps :> LLVMPointerType w) (ps :> LLVMPointerType w :> LLVMPointerType w) () -implLLVMArrayIndexReturn x ap ix = - implSimplM Proxy (SImpl_LLVMArrayIndexReturn x ap ix) +implLLVMArrayCellReturn x ap cell = + implSimplM Proxy (SImpl_LLVMArrayCellReturn x ap cell) -- | Borrow a sub-array from an array as per 'SImpl_LLVMArrayBorrow', leaving -- the remainder of the larger array on the top of the stack and the borrowed @@ -3920,8 +3916,8 @@ implLLVMArrayBorrowBorrow :: ExprVar (LLVMPointerType w) -> LLVMArrayPerm w -> LLVMArrayBorrow w -> ImplM vars s r (ps :> LLVMPointerType w :> LLVMPointerType w) (ps :> LLVMPointerType w) (ValuePerm (LLVMPointerType w)) -implLLVMArrayBorrowBorrow x ap (FieldBorrow ix) = - implLLVMArrayIndexBorrow x ap ix >>>= \(ap',field) -> +implLLVMArrayBorrowBorrow x ap (FieldBorrow cell) = + implLLVMArrayCellBorrow x ap cell >>>= \(ap',field) -> let fld_p = ValPerm_Conj1 $ llvmArrayFieldToAtomicPerm field in implSwapM x fld_p x (ValPerm_LLVMArray ap') >>> pure fld_p @@ -3941,8 +3937,8 @@ implLLVMArrayReturnBorrow :: ExprVar (LLVMPointerType w) -> LLVMArrayPerm w -> LLVMArrayBorrow w -> ImplM vars s r (ps :> LLVMPointerType w) (ps :> LLVMPointerType w :> LLVMPointerType w) () -implLLVMArrayReturnBorrow x ap (FieldBorrow ix) = - implLLVMArrayIndexReturn x ap ix +implLLVMArrayReturnBorrow x ap (FieldBorrow cell) = + implLLVMArrayCellReturn x ap cell implLLVMArrayReturnBorrow x ap b@(RangeBorrow _) = let ValPerm_Conj1 (Perm_LLVMArray ap_ret) = permForLLVMArrayBorrow ap b in implLLVMArrayReturn x ap ap_ret >>> @@ -4110,7 +4106,7 @@ implElimLLVMBlock _ bp = -- for @x@. Extract the @i@th conjuct from @ps@, which should be a @memblock@ -- permission, pop the remaining permissions back to @x@, eliminate the -- @memblock@ permission using 'implElimLLVMBlock' if possible, and recombine --- all the resulting permissions. If the block permission cannot be elimnated, +-- all the resulting permissions. If the block permission cannot be eliminated, -- then fail. implElimPopIthLLVMBlock :: (1 <= w, KnownNat w, NuMatchingAny1 r) => ExprVar (LLVMPointerType w) -> @@ -4179,6 +4175,45 @@ implIntroOrShapeMultiM x bp (sh1 : shs) i = implIntroOrShapeMultiM _ _ _ _ = error "implIntroOrShapeMultiM" +-- | Assume @x:p1*...*pn@ is on top of the stack, and try to find a permission +-- @pi@ that contains a given offset @off@. If a @pi@ is found that definitely +-- contains @off@, in the sense of 'bvPropHolds', it is selected. Otherwise, if +-- the first 'Bool' flag is 'True', imprecise matches are allowed, which are +-- permissions @pi@ that could contain @off@ in the sense of 'bvPropCouldHold', +-- and all such imprecise matches are returned, using 'implCatchM' to try each +-- possibility and fallback to the next one if it fails. If the selected +-- permission @pi@ is a @memblock@ permission and the second 'Bool' flag is +-- 'True', it is then repeatedly eliminated in the sense of 'implElimLLVMBlock' +-- until a non-@memblock@ permission containing @off@ results, and this +-- permission is then used as the new @pi@. The resulting permission @pi@ is +-- then left on top of the stack and returned by the function, while the +-- remaining permissions for @x@ are recombined with any other existing +-- permissions for @x@. If no matches are found, fail using 'implFailVarM', +-- citing the supplied permission as the one we are trying to prove. +implGetLLVMPermForOffset :: + ExprVar (LLVMPointerType w) -> {- ^ the variable @x@ -} + [AtomicPerm (LLVMPointerType w)] -> {- ^ the permissions held for @x@ -} + Bool -> {- ^ whether imprecise matches are allowed -} + Bool -> {- ^ whether block permissions should be eliminated -} + PermExpr (BVType w) -> {- ^ the offset we are looking for -} + Mb ctx (ValuePerm (LLVMPointerType w)) -> {- ^ the perm we want to prove -} + ImplM vars s r (ps :> LLVMPointerType w) (ps :> LLVMPointerType w) + (AtomicPerm (LLVMPointerType w)) + +implGetLLVMPermForOffset x ps imprecise_p elim_blocks_p off mb_p = + case llvmPermIndicesForOffset ps imprecise_p off of + [] -> implFailVarM "implGetLLVMPermForOffset" x (ValPerm_Conj ps) mb_p + ixs -> + foldr1 implCatchM $ flip map ixs $ \i -> + implExtractConjM x ps i >>> implPopM x ps >>> + case p!!i of + Perm_LLVMBlock bp + | elim_blocks_p -> implElimLLVMBlockForOffset x bp off + p_i -> return p_i + +FIXME HERE NOWNOW: write implElimLLVMBlockForOffset + + ---------------------------------------------------------------------- -- * Support for Proving Lifetimes Are Current ---------------------------------------------------------------------- @@ -4333,6 +4368,11 @@ recombinePermConj x x_ps p@Perm_IsLLVMPtr implDropM x (ValPerm_Conj1 p) >>> pure x_ps +-- NOTE: the following is old, but it would never match anyway, because if we +-- have a field (or block) that was borrowed from an array, it almost certainly +-- was borrowed because we accessed it, so it will contain eq permissions and +-- its shape will not equal that of the array it was borrowed from +{- -- If p is a field that was borrowed from an array, return it; i.e., if we are -- returning x:ptr((rw,off+i*stride+j) |-> p) and x has a permission of the form -- x:array(off,>> recombinePermConj x x_ps' (Perm_LLVMArray $ llvmArrayRemBorrow (FieldBorrow ix) ap) +-} -- If p is an array that was borrowed from some other array, return it recombinePermConj x x_ps (Perm_LLVMArray ap) @@ -4604,9 +4645,48 @@ proveEqCast x f e mb_e = ---------------------------------------------------------------------- --- * Lifetime Proofs +-- * Modality Proofs ---------------------------------------------------------------------- +-- | Take in a variable @x@, a function @F@ from read/write modalities to atomic +-- permissions, a read/write modality @rw@, a modality-in-binding @mb_rw@, and +-- an implication rule to coerce from @F(rw)@ to @F('PExpr_Read')@. Attempt to +-- coerce permission @x:F(rw)@ to @x:F(mb_rw)@, instantiating existential +-- variables in @mb_rw@ if necessary. Return the resulting instantiation of +-- @mb_rw@. +equalizeRWs :: (1 <= w, KnownNat w, NuMatchingAny1 r) => + ExprVar a -> (PermExpr RWModality -> ValuePerm a) -> + PermExpr RWModality -> Mb ctx (PermExpr RWModality) -> + (PermExpr RWModality -> SimplImpl (RNil :> a) (RNil :> a)) -> + ImplM vars s r (ps :> a) (ps :> a) (PermExpr RWModality) +equalizeRWs x f rw mb_rw impl = + getPSubst >>>= \psubst -> equalizeRWs' x f rw psubst mb_rw impl + +-- | The main implementation of 'equalizeRWs' +equalizeRWsH :: (1 <= w, KnownNat w, NuMatchingAny1 r) => + ExprVar a -> (PermExpr RWModality -> ValuePerm a) -> + PermExpr RWModality -> PartialSubst vars -> + Mb ctx (PermExpr RWModality) -> + (PermExpr RWModality -> SimplImpl (RNil :> a) (RNil :> a)) -> + ImplM vars s r (ps :> a) (ps :> a) (PermExpr RWModality) + +-- If rw and mb_rw are already equal, just return rw +equalizeRWsH x f rw psubst mb_rw _ + | Just rw' <- partialSubst psubst mb_rw + , rw == rw' = return rw + +-- If mb_rw is read, weaken rw to read using the supplied rule +equalizeRWsH x f rw psubst mb_rw impl + | Just PExpr_Read <- partialSubst psubst mb_rw = + implSimplM Proxy (impl rw) >>> + return PExpr_Read + +-- Otherwise, prove rw = mb_rw and cast f(rw) to f(mb_rw) +equalizeRWsH x f rw psubst mb_rw _ = + proveEqCast x f rw mb_rw >>> + partialSubstForceM mb_rw "equalizeRWs: incomplete psubst" + + -- | Take a variable @x@, a lifetime functor @F@, a lifetime @l@, and a desired -- lifetime-in-bindings @mb_l@, assuming the permission @x:F@ is on the top -- of the stack. Try to coerce the permission to @x:F@, possibly by @@ -4823,6 +4903,15 @@ proveVarLLVMField :: PermExpr (BVType w) -> Mb vars (LLVMFieldPerm w sz) -> ImplM vars s r (ps :> LLVMPointerType w) (ps :> LLVMPointerType w) () +FIXME HERE NOWNOW: rewrite to use implGetLLVMPermForOffset, equalizeRWs, +and proveVarLifetimeFunctor + + + + + + + -- Special case: if the LHS is a memblock perm, unfold it and prove again proveVarLLVMField x ps i _ mb_fp | Perm_LLVMBlock _ <- ps!!i = @@ -4966,12 +5055,10 @@ extractNeededLLVMFieldPerm x (Perm_LLVMField fp) _ _ mb_fp , mbLift (fmap ((llvmFieldRW fp ==) . llvmFieldRW) mb_fp) = introConjM x >>> pure (fp, Nothing) --- If proving x:array(off, p) such that --- off=i*stride+j and the jth field of the ith index of the array is of the --- right size and is a read containing only copyable permissions, copy that --- field +-- If proving x:[l]array(rw,off, p) such that +-- off=i*stride+j and the array permission is copyable, copy cell i extractNeededLLVMFieldPerm x (Perm_LLVMArray ap) off' _ mb_fp - | Just ix <- matchLLVMArrayField ap off' + | Just ix <- matchLLVMArrayIndex ap off' , LLVMArrayField fp <- llvmArrayFieldWithOffset ap ix , Just Refl <- testEquality (llvmFieldSize fp) (mbLift $ fmap llvmFieldSize mb_fp) @@ -5040,275 +5127,292 @@ extractNeededLLVMFieldPerm x ap _ _ mb_fp = -- * Proving LLVM Array Permissions ---------------------------------------------------------------------- -FIXME HERE NOWNOW: -- proveVarLLVMArray needs array perms inside a binding the first time around - because of the modalities -- figure out the cases for using SImpl_LLVMArrayFromBlock below - -- | Prove an LLVM array permission @ap@ from permissions @x:(p1 * ... *pn)@ on --- the top of the stack, and ensuring that any remaining permissions for @x@ get --- popped back to the primary permissions for @x@. The 'Bool' flag should be --- 'True' for the initial call to this function, but 'False' if it is called --- recursively by itself. This is used to determine if array permissions on the --- left that might start before @ap@ can be used: the algorithm starts by trying --- to prove as big of a prefix of an array permission as it can, and then --- recursively tries to prove the remainder of the array, so on the subsequent --- calls it should only use permissions for the remainder of the array that --- precisely match the portion of the desired array that we still need. +-- the top of the stack, ensuring that any remaining permissions for @x@ get +-- popped back to the primary permissions for @x@ proveVarLLVMArray :: (1 <= w, KnownNat w, NuMatchingAny1 r) => ExprVar (LLVMPointerType w) -> - Bool -> [AtomicPerm (LLVMPointerType w)] -> LLVMArrayPerm w -> + Bool -> [AtomicPerm (LLVMPointerType w)] -> Mb vars (LLVMArrayPerm w) -> ImplM vars s r (ps :> LLVMPointerType w) (ps :> LLVMPointerType w) () -proveVarLLVMArray x first_p ps ap = +proveVarLLVMArray x first_p ps mb_ap = implTraceM (\i -> pretty "proveVarLLVMArray:" <+> permPretty i x <> colon <> align (sep [PP.group (permPretty i (ValPerm_Conj ps)), pretty "-o", PP.group (permPretty i (ValPerm_Conj1 $ Perm_LLVMArray ap))])) >>> - proveVarLLVMArrayH x first_p ps ap - + getPSubst >>>= \psubst -> + proveVarLLVMArrayH x first_p psubst ps mb_ap --- | The implementation of 'proveVarLLVMArray' proveVarLLVMArrayH :: (1 <= w, KnownNat w, NuMatchingAny1 r) => ExprVar (LLVMPointerType w) -> - Bool -> [AtomicPerm (LLVMPointerType w)] -> LLVMArrayPerm w -> + Bool -> [AtomicPerm (LLVMPointerType w)] -> PartialSubst vars -> + Mb vars (LLVMArrayPerm w) -> ImplM vars s r (ps :> LLVMPointerType w) (ps :> LLVMPointerType w) () --- When len = 0, we are done -proveVarLLVMArrayH x _ ps ap - | bvEq (llvmArrayLen ap) (bvInt 0) = - implPopM x (ValPerm_Conj ps) >>> implLLVMArrayEmpty x ap - --- If the offset of our array permission is inside a memblock permission, --- eliminate that memblock permission and try again -proveVarLLVMArrayH x _ ps ap - | Just i <- findIndex (isLLVMAtomicPermWithOffset $ llvmArrayOffset ap) ps - , Perm_LLVMBlock _ <- ps!!i = - implElimPopIthLLVMBlock x ps i >>> - mbVarsM (ValPerm_LLVMArray ap) >>>= \mb_p -> - proveVarImplInt x mb_p - --- If the required array permission ap has an offset that matches - -is equivalent to a sequence of field --- permissions that we have all of, then prove it by proving those field --- permissions. This is accomplished by first proving the array with the --- un-borrowed cell that is allowed by 'implLLVMArrayOneCell' and then --- recursively proving the desired array permission by calling proveVarImplInt, --- which will remove the necessary borrows. -proveVarLLVMArrayH x _ ps ap - | Just (flds1, flds2) <- llvmArrayAsFields ap - , all (\fld -> - any (isLLVMFieldPermWithOffset - (llvmArrayFieldOffset fld)) ps) (flds1 ++ flds2) = - implPopM x (ValPerm_Conj ps) >>> - mbVarsM (ValPerm_Conj $ - map llvmArrayFieldToAtomicPerm flds1) >>>= \mb_p_flds -> - proveVarImplInt x mb_p_flds >>> - let ap' = llvmArrayAddBorrows (map (fromJust - . offsetToLLVMArrayBorrow ap - . llvmArrayFieldOffset) flds2) ap in - implLLVMArrayOneCell x ap' >>> - implPopM x (ValPerm_Conj1 $ Perm_LLVMArray ap') >>> - mbVarsM (ValPerm_Conj1 $ Perm_LLVMArray ap) >>>= \mb_p -> - proveVarImplInt x mb_p --} - --- Otherwise, choose the best-matching array permission and copy, borrow, or use --- it directly (beg, borrow, or steal it) --- --- FIXME: need to handle the case where we have a field permission for the first --- cell of an array and an array permission for the rest -proveVarLLVMArrayH x first_p ps ap = - let best_elems :: [(Bool, a)] -> [a] - best_elems xs | Just i <- findIndex fst xs = [snd $ xs !! i] - best_elems xs = map snd xs in - - mbVarsM (Perm_LLVMArray ap) >>>= \mb_p -> - foldr1WithDefault implCatchM (proveVarAtomicImplUnfoldOrFail x ps mb_p) $ - best_elems $ - (let off = llvmArrayOffset ap in - catMaybes $ - zipWith (\p i -> case p of - Perm_LLVMArray ap_lhs - | precise <- bvEq off (llvmArrayOffset ap_lhs) - , (first_p || precise) - , Just cell_num <- llvmArrayIsOffsetArray ap_lhs ap - , bvCouldBeInRange cell_num (llvmArrayCells ap_lhs) -> - Just (precise, proveVarLLVMArray_ArrayStep x ps ap i ap_lhs) - _ -> Nothing) - ps [0..]) - - --- | Prove an array permission @ap@ using the @i@th conjunct @pi@ on the top of --- the stack, assuming @pi@ is the supplied array permission @ap_lhs@ and --- @x:p1*...*pn@ is on top of the stack. -proveVarLLVMArray_ArrayStep :: +-- Special case: if the length is 0, prove an empty array +proveVarLLVMArrayH x first_p psubst ps mb_ap + | Just len <- partialSubst psubst $ mbLLVMArrayLen mb_ap + , bvIsZero len = + partialSubstForceM mb_ap "proveVarLLVMArray: incomplete psubst" >>>= \ap -> + implLLVMArrayEmpty x ap + +proveVarLLVMArrayH x first_p _ ps mb_ap = + partialSubstForceM (mbLLVMArrayOffset mb_ap) + "proveVarLLVMArray: incomplete array offset" >>>= \off -> + implGetLLVMPermForOffset ps first_p True off >>>= \case + + -- If ps are eliminated to a field permission for off, pop all the permissions + -- for x and then prove the first cell of ap followed by the rest + p@(Perm_LLVMField _) -> + recombinePerm x (ValPerm_Conj1 p) >>> + proveVarLLVMArray_FromHead x mb_ap + + -- If ps are eliminated to an array permission for off, use it to prove ap, + -- after popping the remaining permissions for x + Perm_LLVMArray ap_lhs + | llvmArrayStride ap_lhs == mbLLVMArrayStride mb_ap -> + proveVarLLVMArray_FromArray x ps' ap_lhs mb_ap + + -- Because we told implGetLLVMPermForOffset to eliminate block perms, the only + -- other possible case is a named permission, so try to unfold it + p -> + getAtomicPerms x >>>= \ps -> + implSwapInsertConjM x p ps 0 >>> + proveVarAtomicImplUnfoldOrFail x (p:ps) + (mbMapCl $(mkClosed [| Perm_LLVMArray |]) mb_ap) + + +-- | Prove an array permission by proving its first cell and then its remaining +-- cells and appending them together +proveVarLLVMArray_FromHead :: + (1 <= w, KnownNat w, NuMatchingAny1 r) => + ExprVar (LLVMPointerType w) -> Mb vars (LLVMArrayPerm w) -> + ImplM vars s r (ps :> LLVMPointerType w) ps () +proveVarLLVMArray_FromHead x mb_ap = + -- Prove the head permission and convert to an array + let mb_bp = mbMapCl $(mkClosed [| llvmArrayPermHead |]) mb_ap + mb_p = mbMapCl $(mkClosed [| ValPerm_LLVMBlock |]) mb_bp in + proveVarImplInt x mb_bp >>> + partialSubstForceM mb_bp "proveVarLLVMArray: incomplete psubst" >>>= \bp_head -> + implSimplM Proxy (SImpl_LLVMArrayFromBlock x bp) >>> + let ap_head = case llvmBlockPermToArray1 bp_head of + Just ap -> ap + Nothing -> error "proveVarLLVMArray: unexpected form of head cell" in + + -- Test if the length of ap is 1 + partialSubstForceM (mbLLVMArrayLen mb_ap) + "proveVarLLVMArray: incomplete length" >>>= \len -> + if bvEq len (bvInt 1) then + -- If so, then we are done! + return () + else + ( + -- Otherwise, recursively prove the tail of mb_ap + getAtomicPerms x >>>= \ps'' -> + implPushM x (ValPerm_Conj ps'') >>> + let mb_ap_tail = mbMapCl $(mkClosed [| llvmArrayPermTailPerm |]) mb_ap in + proveVarLLVMArray x False ps'' mb_ap_tail >>> + + -- Append the head and the tail to get mb_ap + partialSubstForceM mb_ap_tail + "proveVarLLVMArray: incomplete psubst" >>>= \ap_tail -> + implLLVMArrayAppend x ap_head ap_tail + ) + + +-- | Prove an array permission @mb_ap@ using the array permission @ap_lhs@ on +-- top of the stack, assuming that @ap_lhs@ has the stride as @mb_ap@ and could +-- contain the offset of @mb_ap@. Return the resulting array permission that was +-- proved. +proveVarLLVMArray_FromArray :: (1 <= w, KnownNat w, NuMatchingAny1 r) => ExprVar (LLVMPointerType w) -> - [AtomicPerm (LLVMPointerType w)] -> LLVMArrayPerm w -> - Int -> LLVMArrayPerm w -> - ImplM vars s r (ps :> LLVMPointerType w) (ps :> LLVMPointerType w) () -proveVarLLVMArray_ArrayStep x ps ap i ap_lhs = + LLVMArrayPerm w -> Mb ctx (LLVMArrayPerm w) -> + ImplM vars s r (ps :> LLVMPointerType w) (ps :> LLVMPointerType w) + (LLVMArrayPerm w) +proveVarLLVMArray_FromArray x ap_lhs mb_ap = implTraceM (\info -> - pretty "proveVarLLVMArray_ArrayStep:" <+> + pretty "proveVarLLVMArray_FromArray:" <+> permPretty info x <> colon <> - align (sep [PP.group (permPretty info (ValPerm_Conj ps)), - parens (permPretty info (ValPerm_LLVMArray ap)), + align (sep [PP.group (permPretty info (ValPerm_Conj ps)) <> comma, + permPretty info (ValPerm_LLVMArray ap), pretty "-o", - PP.group (permPretty info (ValPerm_Conj1 $ - Perm_LLVMArray ap))])) >>> - proveVarLLVMArray_ArrayStepH x ps ap i ap_lhs + PP.group (permPretty info mb_ap)])) >>> + getAtomicPerms x >>>= \ps -> + partialSubstForceM (mbLLVMArrayOffset mb_ap) + "proveVarLLVMArray: incomplete psubst" >>>= \off -> + partialSubstForceM (mbLLVMArrayLen mb_ap) + "proveVarLLVMArray: incomplete psubst" >>>= \len -> + partialSubstForceM (mbLLVMArrayBorrows mb_ap) + "proveVarLLVMArray: incomplete array offset" >>>= \bs -> + proveVarLLVMArray_FromArray1 x ps ap_lhs off len bs mb_ap + + +-- | Prove an array permission @mb_ap@ with length and borrows set to the +-- supplied expression and list using the array permission @ap_lhs@ on top of +-- the stack, assuming that @off@ is the offset of @mb_ap@ and that @ap_lhs@ has +-- the same stride as @mb_ap@. Return the resulting array permission that was +-- proved. This function equalizes the offsets and lengths of @ap_lhs@ and +-- @mb_ap@ and then calls 'proveVarLLVMArray_FromArray2'. +proveVarLLVMArray_FromArray1 :: + (1 <= w, KnownNat w, NuMatchingAny1 r) => ExprVar (LLVMPointerType w) -> + [AtomicPerm (LLVMPointerType w)] -> LLVMArrayPerm w -> + PermExpr (BVType w) -> PermExpr (BVType w) -> [LLVMArrayBorrow w] -> + Mb ctx (LLVMArrayPerm w) -> + ImplM vars s r (ps :> LLVMPointerType w) (ps :> LLVMPointerType w) + (LLVMArrayPerm w) +FIXME HERE NOWNOW: deal with ap_lhs having an earlier offset than off by +borrowing or copying it + +-- If ap could be longer than ap_lhs and there is an atomic permission for x +-- that starts at the end of ap_lhs, then use ap_lhs to prove the first portion +-- of ap and then recursively prove the rest +proveVarLLVMArray_FromArray1 x ps ap_lhs off len bs mb_ap + | bvCouldBeLt (llvmArrayLen ap_lhs) len + , len' <- llvmArrayOffset ap_lhs + , any (isLLVMAtomicPermWithOffset len') ps + , (bs_first, bs_rest) <- + partition (\b -> + all bvPropCouldHold $ + llvmArrayBorrowInArrayBase ap_lhs b) bs = + -- Recursively prove ap with length len' and borrows that could be in the + -- first portion of ap + proveVarLLVMArray_FromArray1 x ps ap_lhs len' bs_first mb_ap >>>= \ap' -> + + -- Prove ap with the remaining offset, length, and borrows + let ap_rest = ap' { llvmArrayLen = bvSub len len', + llvmArrayOffset = bvAdd (llvmArrayOffset ap) len', + llvmArrayBorrows = bs_rest } in + mbVarsM ap_rest >>>= \mb_ap_rest -> + getAtomicPerms x >>>= \ps' -> + proveVarLLVMArray x False ps' mb_ap >>>= \ap_rest' -> --- | The main workhorse of 'proveVarLLVMArray_ArrayStep' --- --- FIXME: this should handle array read-write modalities and lifetimes -proveVarLLVMArray_ArrayStepH :: + -- Combine ap_first and ap_rest to get out ap + implLLVMArrayAppend x ap' ap_rest' >>> + implLLVMArrayRearrange x (ap' { llvmArrayLen = len, + llvmArrayBorrows = + bs_first ++ bs_rest }) bs >>> + return (ap' { llvmArrayLen = len, llvmArrayBorrows = bs }) + + +-- If ap_lhs could be longer than ap, borrow or copy len bytes of ap_lhs and +-- recurse +proveVarLLVMArray_FromArray1 x ps ap_lhs len bs mb_ap + | bvCouldBeLt len (llvmArrayLen ap_lhs) = + let ap_lhs' = ap_lhs { llvmArrayLen = len } in + (if atomicPermIsCopyable (Perm_LLVMArray ap) then + implLLVMArrayCopy x ap_lhs ap_lhs' >>> + recombinePerm x (ValPerm_Conj1 $ Perm_LLVMArray ap_lhs) + else + implLLVMArrayBorrow x ap_lhs ap_lhs' >>> + recombinePerm x (ValPerm_Conj1 $ Perm_LLVMArray $ + llvmArrayAddBorrow + (llvmSubArrayBorrow ap_lhs ap_lhs') ap_lhs)) >>> + getAtomicPerms x >>>= \ps' -> + proveVarLLVMArray_FromArray1 x ps' ap_lhs' len bs mb_ap + +-- If ap_lhs and mb_ap have the same length, proceed to phase 2 +proveVarLLVMArray_FromArray1 x ps ap_lhs len bs mb_ap + | bvEq len (llvmArrayLen ap_lhs) = + proveVarLLVMArray_FromArray2 x ps ap_lhs bs mb_ap + +-- If we get to this point, we can't prove mb_ap from ap_lhs, so fail +proveVarLLVMArray_FromArray1 x ps ap_lhs len bs mb_ap = + implFailVarM "proveVarLLVMArray_FromArray1" x + (ValPerm_Conj (Perm_LLVMArray ap_lhs:ps)) + (fmap (\ap -> ValPerm_LLVMArray $ ap { llvmArrayLen = len, + llvmArrayBorrows = bs }) mb_ap) + + +-- | Prove an array permission @mb_ap@ with borrows set to the supplied list and +-- length set to that of @ap_lhs@ using the array permission @ap_lhs@ on top of +-- the stack, assuming that @ap_lhs@ has the same offset and stride as @ap@. +-- Return the resulting array permission that was proved. +proveVarLLVMArray_FromArray2 :: (1 <= w, KnownNat w, NuMatchingAny1 r) => ExprVar (LLVMPointerType w) -> [AtomicPerm (LLVMPointerType w)] -> LLVMArrayPerm w -> - Int -> LLVMArrayPerm w -> - ImplM vars s r (ps :> LLVMPointerType w) (ps :> LLVMPointerType w) () + [LLVMArrayBorrow w] -> Mb ctx (LLVMArrayPerm w) -> + ImplM vars s r (ps :> LLVMPointerType w) (ps :> LLVMPointerType w) + (LLVMArrayPerm w) --- If there is a borrow in ap_lhs that is not in ap but might overlap with ap, --- return it to ap_lhs +-- If there is a borrow in ap_lhs that is not in ap, return it to ap_lhs -- -- FIXME: when an array ap_ret is being borrowed from ap_lhs, this code requires -- all of it to be returned, with no borrows, even though it could be that ap -- allows some of ap_ret to be borrowed -proveVarLLVMArray_ArrayStepH x ps ap i ap_lhs - | Just ap_cell_off <- llvmArrayIsOffsetArray ap_lhs ap - , Just b <- - find (\b -> - bvRangesCouldOverlap (llvmArrayBorrowAbsOffsets ap b) - (llvmArrayAbsOffsets ap) && - not (elem b $ llvmArrayBorrows ap)) - (map (cellOffsetLLVMArrayBorrow ap_cell_off) $ - llvmArrayBorrows ap_lhs) = - - -- Prove the rest of ap with b borrowed - let ap' = llvmArrayAddBorrow b ap in - proveVarLLVMArray_ArrayStep x ps ap' i ap_lhs >>> - - -- Prove the borrowed perm - let p = permForLLVMArrayBorrow ap b in - mbVarsM p >>>= \mb_p -> - proveVarImplInt x mb_p >>> - implSwapM x (ValPerm_Conj1 $ Perm_LLVMArray ap') x p >>> - - -- Return the borrowed perm to ap' to get ap - implLLVMArrayReturnBorrow x ap' b +proveVarLLVMArray_FromArray2 x ps ap_lhs bs mb_ap + | Just b <- find (flip notElem bs) (llvmArrayBorrows ap_lhs) = + + -- Prove the rest of ap with b borrowed + proveVarLLVMArray_FromArray2 x ps ap_lhs (b:bs) mb_ap >>>= \ap' -> + + -- Prove the borrowed perm + let p = permForLLVMArrayBorrow ap' b in + mbVarsM p >>>= \mb_p -> + proveVarImplInt x mb_p >>> + implSwapM x (ValPerm_Conj1 $ Perm_LLVMArray ap') x p >>> + + -- Return the borrowed perm to ap' to get ap + implLLVMArrayReturnBorrow x ap' b >>> + return (ap' { llvmArrayBorrows = bs }) -- If there is a borrow in ap that is not in ap_lhs, borrow it from ap_lhs. Note -- the assymmetry with the previous case: we only add borrows if we definitely -- have to, but we remove borrows if we might have to. -proveVarLLVMArray_ArrayStepH x ps ap i ap_lhs - | Just ap_lhs_cell_off <- llvmArrayIsOffsetArray ap ap_lhs - , Just b <- - find (\b -> - let b' = cellOffsetLLVMArrayBorrow ap_lhs_cell_off b in - bvRangesOverlap (llvmArrayBorrowAbsOffsets ap b) - (llvmArrayAbsOffsets ap_lhs) && - not (elem b' (llvmArrayBorrows ap_lhs))) - (llvmArrayBorrows ap) = +proveVarLLVMArray_FromArray2 x ps ap_lhs len bs mb_ap + | Just b <- find (flip notElem (llvmArrayBorrows ap_lhs)) bs = -- Prove the rest of ap without b borrowed - let ap' = llvmArrayRemBorrow b ap in - proveVarLLVMArray_ArrayStep x ps ap' i ap_lhs >>> + proveVarLLVMArray_FromArray x ps ap_lhs (delete b bs) mb_ap >>>= \ap' -> -- Borrow the permission if that is possible; this will fail if ap has a -- borrow that is not actually in its range. Note that the borrow is always -- added to the front of the list of borrows, so we need to rearrange. implLLVMArrayBorrowBorrow x ap' b >>>= \p -> recombinePerm x p >>> - implLLVMArrayRearrange x (llvmArrayAddBorrow b ap') (llvmArrayBorrows ap) - --- If ap and ap_lhs are equal up to the order of their borrows, just rearrange --- the borrows and we should be done -proveVarLLVMArray_ArrayStepH x ps ap i ap_lhs - | bvEq (llvmArrayOffset ap_lhs) (llvmArrayOffset ap) - , bvEq (llvmArrayLen ap_lhs) (llvmArrayLen ap) - , llvmArrayStride ap_lhs == llvmArrayStride ap - , llvmArrayCellShape ap_lhs == llvmArrayCellShape ap - , llvmArrayBorrowsPermuteTo ap_lhs (llvmArrayBorrows ap) = - implGetPopConjM x ps i >>> - implLLVMArrayRearrange x ap_lhs (llvmArrayBorrows ap) - --- If ap and ap_lhs have the same range and stride but their cells have --- different shapes, prove the rhs shape from the lhs shape -proveVarLLVMArray_ArrayStepH x ps ap i ap_lhs - | bvEq (llvmArrayOffset ap_lhs) (llvmArrayOffset ap) - , bvEq (llvmArrayLen ap_lhs) (llvmArrayLen ap) - , llvmArrayStride ap_lhs == llvmArrayStride ap - , ap' <- ap { llvmArrayCellShape = sh_lhs } - , dps_in <- - nu $ \y -> distPerms1 y $ ValPerm_LLVMBlock $ - blockForLLVMArrayIndex ap $ bvInt 0 - , dps_out <- - nu $ \y -> distPerms1 y $ ValPerm_LLVMBlock $ - blockForLLVMArrayIndex ap_lhs $ bvInt 0 = - proveVarLLVMArray_ArrayStep x ps ap' i ap_lhs >>> - localMbProveVars dps_in dps_out >>>= \mb_impl -> - implSimplM Proxy (SImpl_LLVMArrayContents x ap' sh mb_impl) - --- If ap is contained inside ap_lhs at a cell boundary then copy or borrow ap --- from ap_lhs depending on whether they are copyable -proveVarLLVMArray_ArrayStepH x ps ap i ap_lhs - | all bvPropCouldHold (bvPropRangeSubset - (llvmArrayAbsOffsets ap) (llvmArrayAbsOffsets ap_lhs)) - , llvmArrayStride ap_lhs == llvmArrayStride ap - , llvmArrayFields ap_lhs == llvmArrayFields ap - , Just _ <- llvmArrayIsOffsetArray ap_lhs ap = - implExtractConjM x ps i >>> - implPopM x (ValPerm_Conj $ deleteNth i ps) >>> - if atomicPermIsCopyable (Perm_LLVMArray ap) then - implLLVMArrayCopy x ap_lhs ap >>> - recombinePerm x (ValPerm_Conj1 $ Perm_LLVMArray ap_lhs) - else - implLLVMArrayBorrow x ap_lhs ap >>> - recombinePerm x (ValPerm_Conj1 $ Perm_LLVMArray $ - llvmArrayAddBorrow (llvmSubArrayBorrow ap_lhs ap) ap_lhs) - --- If we get to this case but ap is still at a cell boundary in ap_lhs then --- ap_lhs only satisfies some initial portion of ap, so borrow or copy that part --- of ap_lhs and continue proving the rest of ap -proveVarLLVMArray_ArrayStepH x ps ap i ap_lhs - | llvmArrayStride ap_lhs == llvmArrayStride ap - , llvmArrayFields ap_lhs == llvmArrayFields ap - , Just ap_cell_num <- llvmArrayIsOffsetArray ap_lhs ap = - - -- Split ap into ap_first = the portion of ap covered by ap_lhs and ap_rest - let (ap_first, ap_rest) = - llvmArrayPermDivide ap (bvSub (llvmArrayLen ap_lhs) ap_cell_num) in - - -- Copy or borrow ap_first from ap_lhs, leaving some ps' on top of the stack - -- and ap_first just below it - implExtractConjM x ps i >>> - implPopM x (ValPerm_Conj $ deleteNth i ps) >>> - (if atomicPermIsCopyable (Perm_LLVMArray ap_first) then - implLLVMArrayCopy x ap_lhs ap_first >>> - implPushM x (ValPerm_Conj $ deleteNth i ps) >>> - implInsertConjM x (Perm_LLVMArray ap_lhs) (deleteNth i ps) i >>> - pure ps - else - implLLVMArrayBorrow x ap_lhs ap_first >>> - implPushM x (ValPerm_Conj $ deleteNth i ps) >>> - let ap_lhs' = - llvmArrayAddBorrow (llvmSubArrayBorrow ap_lhs ap_first) ap_lhs in - implInsertConjM x (Perm_LLVMArray ap_lhs') (deleteNth i ps) i >>> - pure (replaceNth i (Perm_LLVMArray ap_lhs') ps)) >>>= \ps' -> - - -- Recursively prove ap_rest - proveVarLLVMArray x False ps' ap_rest >>> - - -- Combine ap_first and ap_rest to get out ap - implLLVMArrayAppend x ap_first ap_rest - + implLLVMArrayRearrange x (llvmArrayAddBorrow b ap') bs >>> + return (ap' { llvmArrayBorrows = bs }) + +-- If we get here then ap_lhs and ap have the same borrows, offset, length, and +-- stride, so equalize their modalities, prove the shape of mb_ap from that of +-- ap_lhs, rearrange their borrows, and we are done +proveVarLLVMArray_FromArrayH x ps ap_lhs len bs mb_ap = + -- Coerce the rw modality of ap_lhs to that of mb_ap, if possibe + equalizeRWs x (\rw -> ap_lhs { llvmArrayRW = rw }) + (llvmArrayRW ap_lhs) (mbLLVMArrayRW mb_ap) + (SImpl_DemoteLLVMArrayRW x ap_lhs) >>>= \rw -> + let ap_lhs' = ap_lhs { llvmArrayRW = rw } in + + -- Coerce the lifetime of ap_lhs to that of mb_ap, if possible + let (f, args) = arrayToLTFunc ap_lhs' in + proveVarLifetimeFunctor x f args (llvmFieldLifetime ap_lhs) + (mbLLVMArrayLifetime mb_ap) >>>= \l -> + let ap_lhs'' = ap_lhs' { llvmArrayLifetime = l } in + + -- Coerce the shape of ap_lhs to that of mb_ap, if necessary. Note that all + -- the fields of ap should be defined at this point except possible its cell + -- shape, but we cannot handle instantiating evars inside local implications, + -- so we require it to be defined as well, and we substitute into mb_ap. + partialSubstForceM mb_ap "proveVarLLVMArray: incomplete psubst" >>>= \ap -> + let sh = llvmArrayCellShape ap in + (if sh == llvmArrayCellShape ap_lhs then + -- If the shapes are already equal, do nothing + return ap_lhs'' + else + -- Otherwise, coerce the contents + let dps_in = nu $ \y -> distPerms1 y $ ValPerm_LLVMBlock $ + llvmArrayCellPerm ap $ bvInt 0 + dps_out = nu $ \y -> distPerms1 y $ ValPerm_LLVMBlock $ + llvmArrayCellPerm ap_lhs'' $ bvInt 0 in + localMbProveVars dps_in dps_out >>>= \mb_impl -> + implSimplM Proxy (SImpl_LLVMArrayContents x ap_lhs'' sh mb_impl) >>> + return (ap_lhs'' { llvmArrayCellShape = sh })) >>>= \ap_lhs''' -> --- Otherwise we don't know what to do so we fail -proveVarLLVMArray_ArrayStepH _x _ps _ap _i _ap_lhs = - implFailMsgM "proveVarLLVMArray_ArrayStep" + -- Finally, rearrange the borrows of ap_lhs to match bs + implLLVMArrayRearrange x ap_lhs''' bs >>> + return (ap_lhs''' { llvmArrayBorrows = bs }) ---------------------------------------------------------------------- @@ -5880,7 +5984,7 @@ proveVarLLVMBlocks2 x ps psubst mb_bp mb_sh mb_bps -- assuming it is defined proveVarLLVMBlocks2 x ps psubst mb_bp mb_sh mb_bps | [nuMP| PExpr_PtrShape _ _ _ |] <- mb_sh - , [nuMP| Just mb_bp' |] <- fmap llvmBlockPtrShapeUnfold mb_bp + , [nuMP| Just mb_bp' |] <- fmap llvmBlockPtrShapeUnfold mb_bp = -- Recursively prove the required field permission and all the other block -- permissions @@ -6282,13 +6386,10 @@ proveVarAtomicImpl x ps mb_p = case mbMatch mb_p of partialSubstForceM (fmap llvmFieldOffset mb_fp) "proveVarPtrPerms" >>>= \off -> foldMapWithDefault implCatchM (proveVarAtomicImplUnfoldOrFail x ps mb_p) - (\(i,_) -> proveVarLLVMField x ps i off mb_fp) $ + (\i -> proveVarLLVMField x ps i off mb_fp) $ -- If there are any permissions that definitely contain off, use those, and -- otherwise iterate through all those that could contain off - let ixs_props = findMaybeIndices (llvmPermContainsOffset off) ps in - case filter (\(_,props) -> all bvPropHolds props) ixs_props of - [] -> ixs_props - ixs_props_hold -> ixs_props_hold + llvmPermIndicesForOffset ps True off [nuMP| Perm_LLVMArray mb_ap |] -> partialSubstForceM mb_ap "proveVarPtrPerms" >>>= \ap -> From ba0030bdd7b0fb78e3e90f7fe9d9f51acb71d9b6 Mon Sep 17 00:00:00 2001 From: Eddy Westbrook Date: Wed, 22 Sep 2021 12:02:46 -0700 Subject: [PATCH 53/98] wrote implElimLLVMBlockForOffset; rewrote proveVarLLVMField in terms of implGetLLVMPermForOffset --- .../src/Verifier/SAW/Heapster/Implication.hs | 422 +++++++----------- .../src/Verifier/SAW/Heapster/Permissions.hs | 33 ++ 2 files changed, 189 insertions(+), 266 deletions(-) diff --git a/heapster-saw/src/Verifier/SAW/Heapster/Implication.hs b/heapster-saw/src/Verifier/SAW/Heapster/Implication.hs index 28e122f853..20c4e1bb9a 100644 --- a/heapster-saw/src/Verifier/SAW/Heapster/Implication.hs +++ b/heapster-saw/src/Verifier/SAW/Heapster/Implication.hs @@ -4147,33 +4147,35 @@ implElimAppendIthLLVMBlock x ps i implElimAppendIthLLVMBlock _ _ _ = error "implElimAppendIthLLVMBlock: malformed inputs" --- | Prove a @memblock@ permission with shape @sh1 orsh sh2 orsh ... orsh shn@ --- from one with shape @shi@. -implIntroOrShapeMultiM :: (NuMatchingAny1 r, 1 <= w, KnownNat w) => - ExprVar (LLVMPointerType w) -> LLVMBlockPerm w -> - [PermExpr (LLVMShapeType w)] -> Int -> - ImplM vars s r (ps :> LLVMPointerType w) - (ps :> LLVMPointerType w) () --- Special case: if we take the or of a single shape, it is that shape itself, --- so we don't need to do anything -implIntroOrShapeMultiM _x _bp [_sh] 0 = return () -implIntroOrShapeMultiM x bp (sh1 : shs) 0 = - let sh2 = foldr1 PExpr_OrShape shs in - introOrLM x - (ValPerm_LLVMBlock $ bp { llvmBlockShape = sh1 }) - (ValPerm_LLVMBlock $ bp { llvmBlockShape = sh2 }) >>> - implSimplM Proxy (SImpl_IntroLLVMBlockOr - x (bp { llvmBlockShape = sh1 }) sh2) -implIntroOrShapeMultiM x bp (sh1 : shs) i = - implIntroOrShapeMultiM x bp shs (i-1) >>> - let sh2 = foldr1 PExpr_OrShape shs in - introOrRM x - (ValPerm_LLVMBlock $ bp { llvmBlockShape = sh1 }) - (ValPerm_LLVMBlock $ bp { llvmBlockShape = sh2 }) >>> - implSimplM Proxy (SImpl_IntroLLVMBlockOr - x (bp { llvmBlockShape = sh1 }) sh2) -implIntroOrShapeMultiM _ _ _ _ = error "implIntroOrShapeMultiM" +-- | Assume @x:p@ is on top of the stack, where @p@ is a @memblock@ permission +-- that contains the supplied offset @off@, and repeatedly eliminate this +-- @memblock@ permission until @p@ has been converted to a non-@memblock@ +-- permission @p'@ that contains @off@. Leave @p'@ on top of the stack, return +-- it as the return value, and recombine any other permissions that are yielded +-- by this elimination. +-- +-- The notion of "contains" is determined by the supplied @imprecise_p@ flag: a +-- 'True' makes this mean "could contain" in the sense of 'bvPropCouldHold', +-- while 'False' makes this mean "definitely contains" in the sense of +-- 'bvPropHolds'. +-- +-- If there are multiple ways to eliminate @p@ to a @p'@ that contains @off@ +-- (which is only possible when @imprecise_p@ is 'True'), return each of them, +-- using 'implCatchM' to combine the different computation paths. +-- +-- If no matches are found, fail using 'implFailVarM', citing the supplied +-- permission as the one we are trying to prove. +implElimLLVMBlockForOffset :: (1 <= w, KnownNat w, NuMatchingAny1 r) => + ExprVar (LLVMPointerType w) -> LLVMBlockPerm w -> + Bool -> PermExpr (BVType w) -> + Mb vars (ValuePerm (LLVMPointerType w)) -> + ImplM vars s r (ps :> LLVMPointerType w) + (ps :> LLVMPointerType w) + (AtomicPerm (LLVMPointerType w)) +implElimLLVMBlockForOffset x bp imprecise_p off mb_p = + implElimLLVMBlock x bp >>> getTopDistPerm x >>>= \(ValPerm_Conj ps) -> + implGetLLVMPermForOffset x ps imprecise_p True off mb_p -- | Assume @x:p1*...*pn@ is on top of the stack, and try to find a permission -- @pi@ that contains a given offset @off@. If a @pi@ is found that definitely @@ -4181,8 +4183,8 @@ implIntroOrShapeMultiM _ _ _ _ = error "implIntroOrShapeMultiM" -- the first 'Bool' flag is 'True', imprecise matches are allowed, which are -- permissions @pi@ that could contain @off@ in the sense of 'bvPropCouldHold', -- and all such imprecise matches are returned, using 'implCatchM' to try each --- possibility and fallback to the next one if it fails. If the selected --- permission @pi@ is a @memblock@ permission and the second 'Bool' flag is +-- possibility and fallback to the next one if it leads to a failure. If the +-- selected @pi@ is a @memblock@ permission and the second 'Bool' flag is -- 'True', it is then repeatedly eliminated in the sense of 'implElimLLVMBlock' -- until a non-@memblock@ permission containing @off@ results, and this -- permission is then used as the new @pi@. The resulting permission @pi@ is @@ -4205,13 +4207,39 @@ implGetLLVMPermForOffset x ps imprecise_p elim_blocks_p off mb_p = [] -> implFailVarM "implGetLLVMPermForOffset" x (ValPerm_Conj ps) mb_p ixs -> foldr1 implCatchM $ flip map ixs $ \i -> - implExtractConjM x ps i >>> implPopM x ps >>> + implGetConjM x ps i >>>= \ps' -> recombinePerm x (ValPerm_Conj ps') >>> case p!!i of Perm_LLVMBlock bp - | elim_blocks_p -> implElimLLVMBlockForOffset x bp off + | elim_blocks_p -> implElimLLVMBlockForOffset x bp imprecise_p off p_i -> return p_i -FIXME HERE NOWNOW: write implElimLLVMBlockForOffset + +-- | Prove a @memblock@ permission with shape @sh1 orsh sh2 orsh ... orsh shn@ +-- from one with shape @shi@. +implIntroOrShapeMultiM :: (NuMatchingAny1 r, 1 <= w, KnownNat w) => + ExprVar (LLVMPointerType w) -> LLVMBlockPerm w -> + [PermExpr (LLVMShapeType w)] -> Int -> + ImplM vars s r (ps :> LLVMPointerType w) + (ps :> LLVMPointerType w) () +-- Special case: if we take the or of a single shape, it is that shape itself, +-- so we don't need to do anything +implIntroOrShapeMultiM _x _bp [_sh] 0 = return () +implIntroOrShapeMultiM x bp (sh1 : shs) 0 = + let sh2 = foldr1 PExpr_OrShape shs in + introOrLM x + (ValPerm_LLVMBlock $ bp { llvmBlockShape = sh1 }) + (ValPerm_LLVMBlock $ bp { llvmBlockShape = sh2 }) >>> + implSimplM Proxy (SImpl_IntroLLVMBlockOr + x (bp { llvmBlockShape = sh1 }) sh2) +implIntroOrShapeMultiM x bp (sh1 : shs) i = + implIntroOrShapeMultiM x bp shs (i-1) >>> + let sh2 = foldr1 PExpr_OrShape shs in + introOrRM x + (ValPerm_LLVMBlock $ bp { llvmBlockShape = sh1 }) + (ValPerm_LLVMBlock $ bp { llvmBlockShape = sh2 }) >>> + implSimplM Proxy (SImpl_IntroLLVMBlockOr + x (bp { llvmBlockShape = sh1 }) sh2) +implIntroOrShapeMultiM _ _ _ _ = error "implIntroOrShapeMultiM" ---------------------------------------------------------------------- @@ -4893,234 +4921,97 @@ solveForPermListImpl ps_l mb_ps_r = -- * Proving Field Permissions ---------------------------------------------------------------------- --- | Prove an LLVM field permission @x:ptr((rw,off) |-> p)@ from permission @pi@ --- assuming that the the current permissions @x:(p1 * ... *pn)@ for @x@ are on --- the top of the stack, and ensuring that any remaining permissions for @x@ get --- popped back to the primary permissions for @x@ +-- | Prove an LLVM field permission @x:ptr((rw,off) |-> p)@ from permissions +-- @x:p1*...*pn@ on the top of the stack, and ensure that any remaining +-- permissions for @x@ get popped back to the primary permissions for @x@. This +-- function does not unfold named permissions in the @pi@s. proveVarLLVMField :: (1 <= w, KnownNat w, 1 <= sz, KnownNat sz, NuMatchingAny1 r) => - ExprVar (LLVMPointerType w) -> [AtomicPerm (LLVMPointerType w)] -> Int -> + ExprVar (LLVMPointerType w) -> [AtomicPerm (LLVMPointerType w)] -> PermExpr (BVType w) -> Mb vars (LLVMFieldPerm w sz) -> ImplM vars s r (ps :> LLVMPointerType w) (ps :> LLVMPointerType w) () -FIXME HERE NOWNOW: rewrite to use implGetLLVMPermForOffset, equalizeRWs, -and proveVarLifetimeFunctor - - - - - - - --- Special case: if the LHS is a memblock perm, unfold it and prove again -proveVarLLVMField x ps i _ mb_fp - | Perm_LLVMBlock _ <- ps!!i = - implElimPopIthLLVMBlock x ps i >>> - proveVarImplInt x (fmap (ValPerm_Conj1 . Perm_LLVMField) mb_fp) +proveVarLLVMField x ps off mb_fp = + implGetLLVMPermForOffset x ps True True off + (MbValPerm_LLVMField mb_fp) >>>= \p -> + proveVarLLVMFieldH x p off mb_fp -proveVarLLVMField x ps i off mb_fp = - (if i < length ps then pure () else - error "proveVarLLVMField: index too large") >>>= \() -> - implExtractConjM x ps i >>> - let ps_rem = deleteNth i ps in - implPopM x (ValPerm_Conj ps_rem) >>> - getPSubst >>>= \psubst -> - extractNeededLLVMFieldPerm x (ps!!i) off psubst mb_fp >>>= \(fp,maybe_p_rem) -> - (case maybe_p_rem of - Just p_rem -> - implPushM x (ValPerm_Conj ps_rem) >>> - implInsertConjM x p_rem ps_rem i >>> - implPopM x (ValPerm_Conj (take i ps_rem ++ [p_rem] ++ drop i ps_rem)) - Nothing -> implDropM x ValPerm_True) >>> - proveVarLLVMFieldFromField x fp off mb_fp - - --- | Prove an LLVM field permission from another one that is on the top of the --- stack, by casting the offset, changing the lifetime if needed, and proving --- the contents -proveVarLLVMFieldFromField :: +-- | Prove an LLVM field permission @mb_fp@ from an atomic permission @x:p@ on +-- the top of the stack, assuming that the offset of @mb_fp@ is @off@ and that +-- @p@ could (in the sense of 'bvPropCouldHold') contain the offset @off@ +proveVarLLVMFieldH :: (1 <= w, KnownNat w, 1 <= sz, KnownNat sz, NuMatchingAny1 r) => - ExprVar (LLVMPointerType w) -> LLVMFieldPerm w sz -> + ExprVar (LLVMPointerType w) -> AtomicPerm (LLVMPointerType w) -> PermExpr (BVType w) -> Mb vars (LLVMFieldPerm w sz) -> ImplM vars s r (ps :> LLVMPointerType w) (ps :> LLVMPointerType w) () -proveVarLLVMFieldFromField x fp off' mb_fp = - -- Step 1: make sure to have a variable for the contents - implElimLLVMFieldContentsM x fp >>>= \y -> - let fp' = fp { llvmFieldContents = ValPerm_Eq (PExpr_Var y) } in - - -- Step 2: cast the field offset to off' if necessary - (if bvEq (llvmFieldOffset fp') off' then - pure fp' - else - implTryProveBVProp x (BVProp_Eq (llvmFieldOffset fp') off') >>> - implSimplM Proxy (SImpl_CastLLVMFieldOffset x fp' off') >>> - pure (fp' { llvmFieldOffset = off' })) >>>= \fp'' -> - - -- Step 3: prove the contents - proveVarImplInt y (fmap llvmFieldContents mb_fp) >>> - partialSubstForceM (fmap llvmFieldContents mb_fp) - "proveVarLLVMFieldFromField" >>>= \p_y -> - let fp''' = fp'' { llvmFieldContents = p_y } in - introLLVMFieldContentsM x y fp''' >>> - - -- Step 4: change the lifetime if needed. This is done after proving the - -- contents, so that, if we need to split the lifetime, we don't split the - -- lifetime of a pointer permission with eq(y) permissions, as that would - -- require the pointer to be constant until the end of the new lifetime. - let (f, args) = fieldToLTFunc fp''' in - proveVarLifetimeFunctor x f args (llvmFieldLifetime fp''') (fmap - llvmFieldLifetime - mb_fp) - - --- | Extract an LLVM field permission from the given atomic permission, leaving --- as much of the original atomic permission as possible on the top of the stack --- (which could be none of it, i.e., @true@). At the end of this function, the --- top of the stack should look like --- --- > x:ptr((rw,off) -> p) * x:rem --- --- where @rem@ is the remainder of the input atomic permission, which is either --- a single atomic permission or @true@. The field permission and remaining --- atomic permission (if any) are the return values of this function. -extractNeededLLVMFieldPerm :: - (1 <= w, KnownNat w, 1 <= sz, KnownNat sz, NuMatchingAny1 r) => - ExprVar (LLVMPointerType w) -> AtomicPerm (LLVMPointerType w) -> - PermExpr (BVType w) -> PartialSubst vars -> Mb vars (LLVMFieldPerm w sz) -> - ImplM vars s r (ps :> LLVMPointerType w :> LLVMPointerType w) - (ps :> LLVMPointerType w) - (LLVMFieldPerm w sz, Maybe (AtomicPerm (LLVMPointerType w))) - --- If proving x:ptr((rw,off) |-> p) |- x:ptr((z,off') |-> p') for an RWModality --- variable z, set z = rw and recurse -extractNeededLLVMFieldPerm x p@(Perm_LLVMField fp) off' psubst mb_fp - | Just Refl <- testEquality (llvmFieldSize fp) (mbLift $ - fmap llvmFieldSize mb_fp) - , [nuMP| PExpr_Var z |] <- mbMatch $ fmap llvmFieldRW mb_fp - , Left memb <- mbNameBoundP z - , Nothing <- psubstLookup psubst memb = - setVarM memb (llvmFieldRW fp) >>> - extractNeededLLVMFieldPerm x p off' psubst - (fmap (\fp' -> fp' { llvmFieldRW = llvmFieldRW fp }) mb_fp) - --- If proving x:ptr((rw,off) |-> p) |- x:ptr((z,off') |-> p') where z is --- defined, substitute for z and recurse -extractNeededLLVMFieldPerm x p@(Perm_LLVMField fp) off' psubst mb_fp - | Just Refl <- testEquality (llvmFieldSize fp) (mbLift $ - fmap llvmFieldSize mb_fp) - , [nuMP| PExpr_Var z |] <- mbMatch $ fmap llvmFieldRW mb_fp - , Left memb <- mbNameBoundP z - , Just rw <- psubstLookup psubst memb = - extractNeededLLVMFieldPerm x p off' psubst - (fmap (\fp' -> fp' { llvmFieldRW = rw }) mb_fp) - --- If proving x:ptr((R,off) |-> p) |- x:ptr((R,off') |-> p'), just copy the read --- permission -extractNeededLLVMFieldPerm x (Perm_LLVMField fp) _ _ mb_fp - | Just Refl <- testEquality (llvmFieldSize fp) (mbLift $ - fmap llvmFieldSize mb_fp) - , PExpr_Read <- llvmFieldRW fp - , [nuMP| PExpr_Read |] <- mbMatch $ fmap llvmFieldRW mb_fp - = implCopyConjM x [Perm_LLVMField fp] 0 >>> - pure (fp, Just (Perm_LLVMField fp)) - --- Cannot prove x:ptr((rw,off) |-> p) |- x:ptr((W,off') |-> p') if rw is not W, --- so fail -extractNeededLLVMFieldPerm x ap@(Perm_LLVMField fp) _ _ mb_fp - | Just Refl <- testEquality (llvmFieldSize fp) (mbLift $ - fmap llvmFieldSize mb_fp) - , PExpr_Write /= llvmFieldRW fp - , [nuMP| PExpr_Write |] <- mbMatch $ fmap llvmFieldRW mb_fp - = implFailVarM "extractNeededLLVMFieldPerm" x (ValPerm_Conj1 $ ap) - (fmap (ValPerm_Conj1 . Perm_LLVMField) mb_fp) - --- If proving x:[l1]ptr((rw,off) |-> p) |- x:[l2]ptr((R,off') |-> p') for rw not --- equal to R (i.e., equal to W or to a variable), demote rw to R and copy it -extractNeededLLVMFieldPerm x (Perm_LLVMField fp) _ _ mb_fp - | Just Refl <- testEquality (llvmFieldSize fp) (mbLift $ - fmap llvmFieldSize mb_fp) - , PExpr_Read /= llvmFieldRW fp - , [nuMP| PExpr_Read |] <- mbMatch $ fmap llvmFieldRW mb_fp - = let fp' = fp in - implSimplM Proxy (SImpl_DemoteLLVMFieldRW x fp') >>> - let fp'' = fp' { llvmFieldRW = PExpr_Read } in - implCopyConjM x [Perm_LLVMField fp''] 0 >>> - pure (fp'', Just (Perm_LLVMField fp'')) - --- If proving x:ptr((rw,off) |-> p) |- x:ptr((rw,off') |-> p') for any other --- case, just push a true permission, because there is no remaining permission -extractNeededLLVMFieldPerm x (Perm_LLVMField fp) _ _ mb_fp - | Just Refl <- testEquality (llvmFieldSize fp) (mbLift $ - fmap llvmFieldSize mb_fp) - , mbLift (fmap ((llvmFieldRW fp ==) . llvmFieldRW) mb_fp) - = introConjM x >>> pure (fp, Nothing) - --- If proving x:[l]array(rw,off, p) such that --- off=i*stride+j and the array permission is copyable, copy cell i -extractNeededLLVMFieldPerm x (Perm_LLVMArray ap) off' _ mb_fp - | Just ix <- matchLLVMArrayIndex ap off' - , LLVMArrayField fp <- llvmArrayFieldWithOffset ap ix - , Just Refl <- testEquality (llvmFieldSize fp) (mbLift $ - fmap llvmFieldSize mb_fp) - , PExpr_Read <- llvmFieldRW fp - , permIsCopyable (llvmFieldContents fp) - , [nuMP| PExpr_Read |] <- mbMatch $ fmap llvmFieldRW mb_fp = - implLLVMArrayIndexCopy x ap ix >>> - pure (fp, Just (Perm_LLVMArray ap)) - --- If proving x:array(off, p) such --- that off=i*stride+j and the corresponding array field is of the right size in --- any other case, borrow that field -extractNeededLLVMFieldPerm x (Perm_LLVMArray ap) off' psubst mb_fp - | Just ix <- matchLLVMArrayField ap off' - , LLVMArrayField fp <- llvmArrayFieldWithOffset ap ix - , Just Refl <- testEquality (llvmFieldSize fp) (mbLift $ - fmap llvmFieldSize mb_fp) = - implLLVMArrayIndexBorrow x ap ix >>>= \(ap', _) -> - implSwapM x (ValPerm_Conj1 $ Perm_LLVMField fp) x (ValPerm_Conj1 $ - Perm_LLVMArray ap') >>> - extractNeededLLVMFieldPerm x (Perm_LLVMField fp) off' psubst mb_fp >>>= - \(fp', maybe_p_rem) -> - -- NOTE: it is safe to just drop the remaining permission on the stack, - -- because it is either Nothing (for a write) or a copy of the field - -- permission (for a read) - implDropM x (maybe ValPerm_True ValPerm_Conj1 maybe_p_rem) >>> - implSwapM x (ValPerm_Conj1 $ - Perm_LLVMArray ap') x (ValPerm_Conj1 $ Perm_LLVMField fp) >>> - pure (fp', Just (Perm_LLVMArray ap')) - --- If proving x:array(off, p) such --- that off=i*stride+j but the corresponding array field is of a smaller size, --- borrow a sub-array for the correct size and cast it to a field permission -extractNeededLLVMFieldPerm x (Perm_LLVMArray ap) off' _ mb_fp - | stride_bits <- llvmArrayStrideBits ap - , sz <- mbLift $ fmap llvmFieldSize mb_fp - , len <- bvInt (intValue sz `div` stride_bits) - , sub_ap <- ap { llvmArrayOffset = off', llvmArrayLen = len, - llvmArrayBorrows = [] } - , isJust $ llvmArrayIsOffsetArray ap sub_ap - , Just fp <- llvmArrayToField sz sub_ap - , ap' <- llvmArrayAddBorrow (llvmSubArrayBorrow ap sub_ap) ap = - implLLVMArrayBorrow x ap sub_ap >>> - implSwapM x (ValPerm_Conj1 $ - Perm_LLVMArray sub_ap) x (ValPerm_Conj1 $ - Perm_LLVMArray ap') >>> - implSimplM Proxy (SImpl_LLVMArrayToField x sub_ap sz) >>> - -- NOTE: extractNeededLLVMFieldPerm is responsible for setting the - -- rwmodality, so we include this proveEqCast for just it here - proveEqCast x (\rw -> ValPerm_Conj1 $ Perm_LLVMField $ - fp { llvmFieldRW = rw }) - (llvmFieldRW fp) (fmap llvmFieldRW mb_fp) >>> - implSwapM x (ValPerm_Conj1 $ - Perm_LLVMArray ap') x (ValPerm_Conj1 $ - Perm_LLVMField fp) >>> - pure (fp, Just (Perm_LLVMArray ap')) - - --- All other cases fail -extractNeededLLVMFieldPerm x ap _ _ mb_fp = - implFailVarM "extractNeededLLVMFieldPerm" x (ValPerm_Conj1 $ ap) - (fmap (ValPerm_Conj1 . Perm_LLVMField) mb_fp) + +-- If we have a field permission of the correct size on the left, use it to +-- prove the field permission on the right +proveVarLLVMFieldH x (Perm_LLVMField fp) off mb_fp + | bvEq (llvmFieldOffset fp) off + , Just Refl <- testEquality (exprLLVMTypeWidth fp) (mbExprLLVMTypeWidth + mb_fp) = + -- Step 1: make sure to have a variable for the contents + implElimLLVMFieldContentsM x fp >>>= \y -> + let fp' = fp { llvmFieldContents = ValPerm_Eq (PExpr_Var y) } in + + -- Step 2: prove the contents + proveVarImplInt y (fmap llvmFieldContents mb_fp) >>> + partialSubstForceM (fmap llvmFieldContents mb_fp) + "proveVarLLVMFieldFromField" >>>= \p_y -> + let fp'' = fp' { llvmFieldContents = p_y } in + introLLVMFieldContentsM x y fp'' >>> + + -- Step 3: change the lifetime if needed. This is done after proving the + -- contents, so that, if we need to split the lifetime, we don't split the + -- lifetime of a pointer permission with eq(y) permissions, as that would + -- require the pointer to be constant until the end of the new lifetime. + -- + -- FIXME: probably the right way to do this would be to first check if there + -- is going to be a borrow, and if so then recall the field permissions for + -- fp immediately before we do said borrow. Maybe this could be part of + -- proveVarLifetimeFunctor? + let (f, args) = fieldToLTFunc fp'' in + proveVarLifetimeFunctor x f args (llvmFieldLifetime fp'') + (fmap llvmFieldLifetime mb_fp) >>>= \l -> + let fp''' = fp { llvmFieldLifetime = l } in + + -- Step 4: equalize the read/write modalities. This is done after changing + -- the lifetime so that the original modality is recovered after any borrow + -- performed above is over. + equalizeRWs x (\rw -> fp''' { llvmFieldRW = rw }) (llvmFieldRW fp) + (mbLLVMFieldRW mb_fp) (SImpl_DemoteLLVMFieldRW x fp''') >>> + return () + +-- If we have a block permission on the left, eliminate it +proveVarLLVMFieldH x (Perm_LLVMBlock bp) off mb_fp = + implElimLLVMBlockForOffset x bp True off (MbLLVMField_Perm mb_fp) >>>= \p -> + proveVarLLVMFieldH x p off mb_fp + +-- If we have a copyable array permission on the left such that @off@ matches an +-- index into that array permission, copy the corresponding cell +proveVarLLVMFieldH x p@(Perm_LLVMArray ap) off mb_fp + | Just ix <- matchLLVMArrayIndex ap off + , cell <- llvmArrayIndexCell ix + , atomicPermIsCopyable p = + implLLVMArrayCellCopy x ap cell >>> + recombinePerm x (ValPerm_LLVMArray ap) >>> + proveVarLLVMFieldH x (ValPerm_LLVMBlock $ llvmArrayCellPerm ap cell) off mb_fp + +-- If we have a non-copyable array permission on the left such that @off@ +-- matches an index into that array permission, borrow the corresponding cell +proveVarLLVMFieldH x p@(Perm_LLVMArray ap) off mb_fp + | Just ix <- matchLLVMArrayIndex ap off + , cell <- llvmArrayIndexCell ix = + implLLVMArrayCellBorrow x ap cell >>> + recombinePerm x (ValPerm_LLVMArray $ + llvmArrayAddBorrow (FieldBorrow cell) ap) >>> + proveVarLLVMFieldH x (ValPerm_LLVMBlock $ + llvmArrayCellPerm ap cell) off mb_fp + +-- If none of the above cases match, then fail +proveVarLLVMFieldH x p _ mb_fp = + implFailVarM x (ValPerm_Conj1 p) (MbValPerm_LLVMField mb_fp) ---------------------------------------------------------------------- @@ -5129,7 +5020,8 @@ extractNeededLLVMFieldPerm x ap _ _ mb_fp = -- | Prove an LLVM array permission @ap@ from permissions @x:(p1 * ... *pn)@ on -- the top of the stack, ensuring that any remaining permissions for @x@ get --- popped back to the primary permissions for @x@ +-- popped back to the primary permissions for @x@. This function does not unfold +-- named permissions in the @pi@s. proveVarLLVMArray :: (1 <= w, KnownNat w, NuMatchingAny1 r) => ExprVar (LLVMPointerType w) -> Bool -> [AtomicPerm (LLVMPointerType w)] -> Mb vars (LLVMArrayPerm w) -> @@ -5175,13 +5067,11 @@ proveVarLLVMArrayH x first_p _ ps mb_ap = | llvmArrayStride ap_lhs == mbLLVMArrayStride mb_ap -> proveVarLLVMArray_FromArray x ps' ap_lhs mb_ap - -- Because we told implGetLLVMPermForOffset to eliminate block perms, the only - -- other possible case is a named permission, so try to unfold it - p -> - getAtomicPerms x >>>= \ps -> - implSwapInsertConjM x p ps 0 >>> - proveVarAtomicImplUnfoldOrFail x (p:ps) - (mbMapCl $(mkClosed [| Perm_LLVMArray |]) mb_ap) + -- Because we told implGetLLVMPermForOffset to eliminate block perms, there + -- should be no other cases that will work here, so fail + _ -> + implFailVarM "proveVarLLVMArrayH" x (ValPerm_Conj ps) + (MbValPerm_LLVMArray mb_ap) -- | Prove an array permission by proving its first cell and then its remaining @@ -5536,6 +5426,8 @@ proveVarLLVMBlock x ps mb_bp = do psubst <- getPSubst proveVarLLVMBlocks x ps psubst [mb_bp] +FIXME HERE NOWNOW: do we need to use implGetLLVMPermForOffset for +proveVarLLVMBlock? -- | Prove a conjunction of block and atomic permissions for @x@, assuming all -- of the permissions for @x@ are on the top of the stack and given by the @@ -6383,17 +6275,15 @@ proveVarAtomicImpl :: proveVarAtomicImpl x ps mb_p = case mbMatch mb_p of [nuMP| Perm_LLVMField mb_fp |] -> - partialSubstForceM (fmap llvmFieldOffset mb_fp) "proveVarPtrPerms" >>>= \off -> - foldMapWithDefault implCatchM + partialSubstForceM (mbLLVMFieldOffset mb_fp) "proveVarPtrPerms" >>>= \off -> + implCatchM + (proveVarLLVMField x ps off mb_fp) (proveVarAtomicImplUnfoldOrFail x ps mb_p) - (\i -> proveVarLLVMField x ps i off mb_fp) $ - -- If there are any permissions that definitely contain off, use those, and - -- otherwise iterate through all those that could contain off - llvmPermIndicesForOffset ps True off [nuMP| Perm_LLVMArray mb_ap |] -> - partialSubstForceM mb_ap "proveVarPtrPerms" >>>= \ap -> - proveVarLLVMArray x True ps ap + implCatchM + (proveVarLLVMArray x True ps mb_ap) + (proveVarAtomicImplUnfoldOrFail x ps mb_p) [nuMP| Perm_LLVMBlock mb_bp |] -> proveVarLLVMBlock x ps mb_bp diff --git a/heapster-saw/src/Verifier/SAW/Heapster/Permissions.hs b/heapster-saw/src/Verifier/SAW/Heapster/Permissions.hs index 53bd215349..44f6bb3206 100644 --- a/heapster-saw/src/Verifier/SAW/Heapster/Permissions.hs +++ b/heapster-saw/src/Verifier/SAW/Heapster/Permissions.hs @@ -635,6 +635,11 @@ bindingType _ = knownRepr exprLLVMTypeWidth :: KnownNat w => f (LLVMPointerType w) -> NatRepr w exprLLVMTypeWidth _ = knownNat +-- | Convenience function to get the bit width of an LLVM pointer type +mbExprLLVMTypeWidth :: KnownNat w => Mb ctx (f (LLVMPointerType w)) -> + NatRepr w +mbExprLLVMTypeWidth _ = knownNat + -- | Convenience function to get the bit width of an LLVM pointer type shapeLLVMTypeWidth :: KnownNat w => f (LLVMShapeType w) -> NatRepr w shapeLLVMTypeWidth _ = knownNat @@ -1515,6 +1520,16 @@ pattern ValPerm_LLVMField fp <- ValPerm_Conj [Perm_LLVMField fp] where ValPerm_LLVMField fp = ValPerm_Conj [Perm_LLVMField fp] +-- | The conjunction of exactly 1 field permission in a binding +pattern MbValPerm_LLVMField :: () => (a ~ LLVMPointerType w, 1 <= w, KnownNat w, + 1 <= sz, KnownNat sz) => + Mb ctx (LLVMFieldPerm w sz) -> + Mb ctx (ValuePerm a) +pattern MbValPerm_LLVMField mb_fp <- [nuP| ValPerm_LLVMField mb_fp |] + where + MbValPerm_LLVMField mb_fp = + mbMapCl $(mkClosed [| ValPerm_LLVMField |]) mb_fp + -- | The conjunction of exactly 1 array permission pattern ValPerm_LLVMArray :: () => (a ~ LLVMPointerType w, 1 <= w, KnownNat w) => LLVMArrayPerm w -> ValuePerm a @@ -1522,6 +1537,24 @@ pattern ValPerm_LLVMArray ap <- ValPerm_Conj [Perm_LLVMArray ap] where ValPerm_LLVMArray ap = ValPerm_Conj [Perm_LLVMArray ap] +-- | The conjunction of exactly 1 array permission +pattern MbValPerm_LLVMArray :: () => (a ~ LLVMPointerType w, 1 <= w, KnownNat w) => + Mb ctx (LLVMArrayPerm w) -> Mb ctx (ValuePerm a) +pattern MbValPerm_LLVMArray mb_ap <- [nuP| ValPerm_LLVMArray ap |] + where + MbValPerm_LLVMArray mb_ap = + mbMapCl $(mkClosed [| ValPerm_LLVMArray |]) mb_ap + +-- | The conjunction of exactly 1 array permission in a binding +pattern MbValPerm_LLVMField :: () => (a ~ LLVMPointerType w, 1 <= w, KnownNat w, + 1 <= sz, KnownNat sz) => + Mb ctx (LLVMFieldPerm w sz) -> + Mb ctx (ValuePerm a) +pattern MbValPerm_LLVMField mb_fp <- [nuP| ValPerm_LLVMField mb_fp |] + where + MbValPerm_LLVMField mb_fp = + mbMapCl $(mkClosed [| ValPerm_LLVMField |]) mb_fp + -- | The conjunction of exactly 1 block permission pattern ValPerm_LLVMBlock :: () => (a ~ LLVMPointerType w, 1 <= w, KnownNat w) => LLVMBlockPerm w -> ValuePerm a From 92f566afde2fda66dc04389d1bb9ce2a192e6ed4 Mon Sep 17 00:00:00 2001 From: Eddy Westbrook Date: Wed, 22 Sep 2021 17:28:52 -0700 Subject: [PATCH 54/98] trying to get the newly-writte Implication.hs to compile... --- .../src/Verifier/SAW/Heapster/Implication.hs | 305 +++++++++--------- .../src/Verifier/SAW/Heapster/Permissions.hs | 59 ++-- 2 files changed, 188 insertions(+), 176 deletions(-) diff --git a/heapster-saw/src/Verifier/SAW/Heapster/Implication.hs b/heapster-saw/src/Verifier/SAW/Heapster/Implication.hs index 20c4e1bb9a..a4dfbd51b5 100644 --- a/heapster-saw/src/Verifier/SAW/Heapster/Implication.hs +++ b/heapster-saw/src/Verifier/SAW/Heapster/Implication.hs @@ -678,6 +678,7 @@ data SimplImpl ps_in ps_out where ExprVar (LLVMPointerType w) -> LLVMArrayPerm w -> SimplImpl RNil (RNil :> LLVMPointerType w) + {- -- | Convert an array to a field of the same size with @true@ contents: -- -- > x:array(off,<(sz/stride/8),*stride,sh,[]) -o x:[l]ptr((rw,off) |-> true) @@ -687,6 +688,7 @@ data SimplImpl ps_in ps_out where (1 <= w, KnownNat w, 1 <= sz, KnownNat sz) => ExprVar (LLVMPointerType w) -> LLVMArrayPerm w -> NatRepr sz -> SimplImpl (RNil :> LLVMPointerType w) (RNil :> LLVMPointerType w) + -} -- | Prove an array of length 1 from a block of its same shape: -- @@ -1651,7 +1653,7 @@ simplImplIn (SImpl_LLVMArrayAppend x ap1 ap2) = case llvmArrayIsOffsetArray ap1 ap2 of Just len1 | bvEq len1 (llvmArrayLen ap1) - , llvmArrayFields ap1 == llvmArrayFields ap2 -> + , llvmArrayCellShape ap1 == llvmArrayCellShape ap2 -> distPerms2 x (ValPerm_Conj1 $ Perm_LLVMArray ap1) x (ValPerm_Conj1 $ Perm_LLVMArray ap2) _ -> error "simplImplIn: SImpl_LLVMArrayAppend: arrays cannot be appended" @@ -1662,8 +1664,10 @@ simplImplIn (SImpl_LLVMArrayRearrange x ap bs) = else error "simplImplIn: SImpl_LLVMArrayRearrange: malformed output borrows list" +{- simplImplIn (SImpl_LLVMArrayToField x ap _) = distPerms1 x (ValPerm_Conj1 $ Perm_LLVMArray ap) +-} simplImplIn (SImpl_LLVMArrayEmpty _ ap) = if bvIsZero (llvmArrayLen ap) then DistPermsNil else @@ -1765,7 +1769,7 @@ simplImplIn (SImpl_IntroLLVMBlockFromEq x bp y) = simplImplIn (SImpl_IntroLLVMBlockPtr x bp) = distPerms1 x $ ValPerm_LLVMBlock $ llvmBlockPtrShapeUnfold bp simplImplIn (SImpl_ElimLLVMBlockPtr x bp) = - distPerms1 x bp + distPerms1 x $ ValPerm_LLVMBlock bp simplImplIn (SImpl_IntroLLVMBlockField x fp) = distPerms1 x (ValPerm_Conj1 $ Perm_LLVMField fp) simplImplIn (SImpl_ElimLLVMBlockField x fp) = @@ -1942,7 +1946,7 @@ simplImplOut (SImpl_LLVMArrayAppend x ap1 ap2) = case llvmArrayIsOffsetArray ap1 ap2 of Just len1 | bvEq len1 (llvmArrayLen ap1) - , llvmArrayFields ap1 == llvmArrayFields ap2 + , llvmArrayCellShape ap1 == llvmArrayCellShape ap2 , ap1' <- ap1 { llvmArrayLen = bvAdd (llvmArrayLen ap1) (llvmArrayLen ap2) } -> distPerms1 x $ ValPerm_Conj1 $ Perm_LLVMArray $ @@ -1955,11 +1959,13 @@ simplImplOut (SImpl_LLVMArrayRearrange x ap bs) = else error "simplImplOut: SImpl_LLVMArrayRearrange: malformed output borrows list" +{- simplImplOut (SImpl_LLVMArrayToField x ap sz) = case llvmArrayToField sz ap of Just fp -> distPerms1 x (ValPerm_Conj1 $ Perm_LLVMField fp) Nothing -> error "simplImplOut: SImpl_LLVMArrayToField: malformed array permission" +-} simplImplOut (SImpl_LLVMArrayEmpty x ap) = if bvIsZero (llvmArrayLen ap) then @@ -1975,7 +1981,7 @@ simplImplOut (SImpl_LLVMArrayFromBlock x bp) = simplImplOut (SImpl_LLVMArrayCellCopy x ap cell) = if atomicPermIsCopyable (Perm_LLVMArray ap) then distPerms2 x (ValPerm_LLVMBlock $ llvmArrayCellPerm ap cell) - x (ValPerm__LLVMArray ap) + x (ValPerm_LLVMArray ap) else error "simplImplOut: SImpl_LLVMArrayCellCopy: array is not copyable" @@ -2074,7 +2080,10 @@ simplImplOut (SImpl_IntroLLVMBlockFromEq x bp _) = simplImplOut (SImpl_IntroLLVMBlockPtr x bp) = distPerms1 x $ ValPerm_LLVMBlock bp simplImplOut (SImpl_ElimLLVMBlockPtr x bp) = - distPerms1 x $ ValPerm_LLVMBlock llvmBlockPtrShapeUnfold bp + case llvmBlockPtrShapeUnfold bp of + Just bp' -> distPerms1 x $ ValPerm_LLVMBlock bp' + Nothing -> + error "simplImplOut: SImpl_ElimLLVMBlockPtr: unexpected block shape" simplImplOut (SImpl_IntroLLVMBlockField x fp) = distPerms1 x (ValPerm_Conj1 $ Perm_LLVMBlock $ llvmFieldPermToBlock fp) simplImplOut (SImpl_ElimLLVMBlockField x fp) = @@ -2378,9 +2387,9 @@ instance SubstVar PermVarSubst m => SImpl_LLVMArrayAppend <$> genSubst s x <*> genSubst s ap1 <*> genSubst s ap2 [nuMP| SImpl_LLVMArrayRearrange x ap bs |] -> SImpl_LLVMArrayRearrange <$> genSubst s x <*> genSubst s ap <*> genSubst s bs - [nuMP| SImpl_LLVMArrayToField x ap sz |] -> - SImpl_LLVMArrayToField <$> genSubst s x <*> genSubst s ap - <*> return (mbLift sz) + -- [nuMP| SImpl_LLVMArrayToField x ap sz |] -> + -- SImpl_LLVMArrayToField <$> genSubst s x <*> genSubst s ap + -- <*> return (mbLift sz) [nuMP| SImpl_LLVMArrayEmpty x ap |] -> SImpl_LLVMArrayEmpty <$> genSubst s x <*> genSubst s ap [nuMP| SImpl_LLVMArrayFromBlock x bp |] -> @@ -2860,8 +2869,8 @@ getPerm x = use (implStatePerms . varPerm x) -- | Look up the current permission for a given variable, assuming it has a -- conjunctive permissions, and return the conjuncts -getAtomicPerms :: ExprVar a -> ImplM vars s r ps ps (ValuePerm a) -getAtomicPerms x = getPerm >>= \case +getAtomicPerms :: ExprVar a -> ImplM vars s r ps ps [AtomicPerm a] +getAtomicPerms x = getPerm x >>= \case ValPerm_Conj ps -> return ps _ -> error "getAtomicPerms: non-conjunctive permission" @@ -3871,19 +3880,23 @@ implLLVMArrayCellReturn :: implLLVMArrayCellReturn x ap cell = implSimplM Proxy (SImpl_LLVMArrayCellReturn x ap cell) --- | Borrow a sub-array from an array as per 'SImpl_LLVMArrayBorrow', leaving --- the remainder of the larger array on the top of the stack and the borrowed --- sub-array just beneath it +-- | Borrow a sub-array from an array @ap@ using 'SImpl_LLVMArrayBorrow', +-- leaving the remainder of @ap@ on the top of the stack and the borrowed +-- sub-array just beneath it. Return the remainder of @ap@. implLLVMArrayBorrow :: (1 <= w, KnownNat w, NuMatchingAny1 r) => ExprVar (LLVMPointerType w) -> LLVMArrayPerm w -> LLVMArrayPerm w -> ImplM vars s r (ps :> LLVMPointerType w :> LLVMPointerType w) - (ps :> LLVMPointerType w) () + (ps :> LLVMPointerType w) (LLVMArrayPerm w) implLLVMArrayBorrow x ap sub_ap = implTryProveBVProps x (llvmArrayContainsArray ap sub_ap) >>> - implSimplM Proxy (SImpl_LLVMArrayBorrow x ap sub_ap) + implSimplM Proxy (SImpl_LLVMArrayBorrow x ap sub_ap) >>> + return (llvmArrayAddBorrow (llvmSubArrayBorrow ap sub_ap) $ + llvmArrayRemArrayBorrows ap sub_ap) --- | Copy a sub-array from an array as per 'SImpl_LLVMArrayCopy' +-- | Copy a sub-array from an array @ap@ as per 'SImpl_LLVMArrayCopy', leaving +-- @ap@ on the top of the stack and the borrowed sub-array just beneath +-- it. Return the remainder of @ap@ that is on top of the stack. implLLVMArrayCopy :: (1 <= w, KnownNat w, NuMatchingAny1 r) => ExprVar (LLVMPointerType w) -> LLVMArrayPerm w -> LLVMArrayPerm w -> @@ -3893,6 +3906,22 @@ implLLVMArrayCopy x ap sub_ap = implTryProveBVProps x (llvmArrayContainsArray ap sub_ap) >>> implSimplM Proxy (SImpl_LLVMArrayCopy x ap sub_ap) +-- | Copy or borrow a sub-array from an array @ap@, depending on whether @ap@ is +-- copyable, assuming @ap@ is on top of the stack. Leave the remainder of @ap@ +-- on top of the stack and the sub-array just below it. Return the remainder of +-- @ap@ that was left on top of the stack. +implLLVMArrayGet :: + (1 <= w, KnownNat w, NuMatchingAny1 r) => + ExprVar (LLVMPointerType w) -> LLVMArrayPerm w -> LLVMArrayPerm w -> + ImplM vars s r (ps :> LLVMPointerType w :> LLVMPointerType w) + (ps :> LLVMPointerType w) (LLVMArrayPerm w) +implLLVMArrayGet x ap sub_ap + | atomicPermIsCopyable (Perm_LLVMArray ap) = + implLLVMArrayCopy x ap sub_ap >>> return ap +implLLVMArrayGet x ap sub_ap = + implLLVMArrayBorrow x ap sub_ap + + -- | Return a borrowed sub-array to an array as per 'SImpl_LLVMArrayReturn', -- where the borrowed array permission is just below the top of the stack and -- the array it was borrowed from is on top of the stack. Return the new array @@ -3917,10 +3946,9 @@ implLLVMArrayBorrowBorrow :: ImplM vars s r (ps :> LLVMPointerType w :> LLVMPointerType w) (ps :> LLVMPointerType w) (ValuePerm (LLVMPointerType w)) implLLVMArrayBorrowBorrow x ap (FieldBorrow cell) = - implLLVMArrayCellBorrow x ap cell >>>= \(ap',field) -> - let fld_p = ValPerm_Conj1 $ llvmArrayFieldToAtomicPerm field in - implSwapM x fld_p x (ValPerm_LLVMArray ap') >>> - pure fld_p + implLLVMArrayCellBorrow x ap cell >>>= \(ap',bp) -> + implSwapM x (ValPerm_LLVMBlock bp) x (ValPerm_LLVMArray ap') >>> + return (ValPerm_LLVMBlock bp) implLLVMArrayBorrowBorrow x ap b@(RangeBorrow _) = let p = permForLLVMArrayBorrow ap b ValPerm_Conj1 (Perm_LLVMArray sub_ap) = p @@ -4046,8 +4074,7 @@ implElimLLVMBlock x bp@(LLVMBlockPerm { llvmBlockShape = implElimLLVMBlock x bp@(LLVMBlockPerm { llvmBlockShape = PExpr_PtrShape maybe_rw maybe_l sh }) | Just len <- llvmShapeLength sh = - let bp' = bp { llvmBlockLen = len, llvmBlockShape = sh } in - implSimplM Proxy (SImpl_ElimLLVMBlockPtr x maybe_rw maybe_l bp') + implSimplM Proxy (SImpl_ElimLLVMBlockPtr x bp) -- For a field shape, eliminate to a field permission {- @@ -4177,6 +4204,7 @@ implElimLLVMBlockForOffset x bp imprecise_p off mb_p = implElimLLVMBlock x bp >>> getTopDistPerm x >>>= \(ValPerm_Conj ps) -> implGetLLVMPermForOffset x ps imprecise_p True off mb_p + -- | Assume @x:p1*...*pn@ is on top of the stack, and try to find a permission -- @pi@ that contains a given offset @off@. If a @pi@ is found that definitely -- contains @off@, in the sense of 'bvPropHolds', it is selected. Otherwise, if @@ -4198,7 +4226,7 @@ implGetLLVMPermForOffset :: Bool -> {- ^ whether imprecise matches are allowed -} Bool -> {- ^ whether block permissions should be eliminated -} PermExpr (BVType w) -> {- ^ the offset we are looking for -} - Mb ctx (ValuePerm (LLVMPointerType w)) -> {- ^ the perm we want to prove -} + Mb vars (ValuePerm (LLVMPointerType w)) -> {- ^ the perm we want to prove -} ImplM vars s r (ps :> LLVMPointerType w) (ps :> LLVMPointerType w) (AtomicPerm (LLVMPointerType w)) @@ -4208,9 +4236,10 @@ implGetLLVMPermForOffset x ps imprecise_p elim_blocks_p off mb_p = ixs -> foldr1 implCatchM $ flip map ixs $ \i -> implGetConjM x ps i >>>= \ps' -> recombinePerm x (ValPerm_Conj ps') >>> - case p!!i of + case ps!!i of Perm_LLVMBlock bp - | elim_blocks_p -> implElimLLVMBlockForOffset x bp imprecise_p off + | elim_blocks_p -> + implElimLLVMBlockForOffset x bp imprecise_p off mb_p p_i -> return p_i @@ -4430,7 +4459,7 @@ recombinePermConj x x_ps (Perm_LLVMArray ap) | isJust (llvmArrayIsOffsetArray ap' ap) && elem (llvmSubArrayBorrow ap' ap) (llvmArrayBorrows ap') && llvmArrayStride ap' == llvmArrayStride ap && - llvmArrayFields ap' == llvmArrayFields ap -> + llvmArrayCellShape ap' == llvmArrayCellShape ap -> return (ap', i) _ -> Nothing) = implPushM x (ValPerm_Conj x_ps) >>> implExtractConjM x x_ps i >>> @@ -4682,21 +4711,21 @@ proveEqCast x f e mb_e = -- coerce permission @x:F(rw)@ to @x:F(mb_rw)@, instantiating existential -- variables in @mb_rw@ if necessary. Return the resulting instantiation of -- @mb_rw@. -equalizeRWs :: (1 <= w, KnownNat w, NuMatchingAny1 r) => - ExprVar a -> (PermExpr RWModality -> ValuePerm a) -> - PermExpr RWModality -> Mb ctx (PermExpr RWModality) -> - (PermExpr RWModality -> SimplImpl (RNil :> a) (RNil :> a)) -> - ImplM vars s r (ps :> a) (ps :> a) (PermExpr RWModality) +equalizeRWs :: NuMatchingAny1 r => ExprVar a -> + (PermExpr RWModalityType -> ValuePerm a) -> + PermExpr RWModalityType -> Mb vars (PermExpr RWModalityType) -> + SimplImpl (RNil :> a) (RNil :> a) -> + ImplM vars s r (ps :> a) (ps :> a) (PermExpr RWModalityType) equalizeRWs x f rw mb_rw impl = - getPSubst >>>= \psubst -> equalizeRWs' x f rw psubst mb_rw impl + getPSubst >>>= \psubst -> equalizeRWsH x f rw psubst mb_rw impl -- | The main implementation of 'equalizeRWs' -equalizeRWsH :: (1 <= w, KnownNat w, NuMatchingAny1 r) => - ExprVar a -> (PermExpr RWModality -> ValuePerm a) -> - PermExpr RWModality -> PartialSubst vars -> - Mb ctx (PermExpr RWModality) -> - (PermExpr RWModality -> SimplImpl (RNil :> a) (RNil :> a)) -> - ImplM vars s r (ps :> a) (ps :> a) (PermExpr RWModality) +equalizeRWsH :: NuMatchingAny1 r => ExprVar a -> + (PermExpr RWModalityType -> ValuePerm a) -> + PermExpr RWModalityType -> PartialSubst vars -> + Mb vars (PermExpr RWModalityType) -> + SimplImpl (RNil :> a) (RNil :> a) -> + ImplM vars s r (ps :> a) (ps :> a) (PermExpr RWModalityType) -- If rw and mb_rw are already equal, just return rw equalizeRWsH x f rw psubst mb_rw _ @@ -4706,8 +4735,7 @@ equalizeRWsH x f rw psubst mb_rw _ -- If mb_rw is read, weaken rw to read using the supplied rule equalizeRWsH x f rw psubst mb_rw impl | Just PExpr_Read <- partialSubst psubst mb_rw = - implSimplM Proxy (impl rw) >>> - return PExpr_Read + implSimplM Proxy impl >>> return PExpr_Read -- Otherwise, prove rw = mb_rw and cast f(rw) to f(mb_rw) equalizeRWsH x f rw psubst mb_rw _ = @@ -4933,7 +4961,7 @@ proveVarLLVMField :: proveVarLLVMField x ps off mb_fp = implGetLLVMPermForOffset x ps True True off - (MbValPerm_LLVMField mb_fp) >>>= \p -> + (mbValPerm_LLVMField mb_fp) >>>= \p -> proveVarLLVMFieldH x p off mb_fp -- | Prove an LLVM field permission @mb_fp@ from an atomic permission @x:p@ on @@ -4949,8 +4977,7 @@ proveVarLLVMFieldH :: -- prove the field permission on the right proveVarLLVMFieldH x (Perm_LLVMField fp) off mb_fp | bvEq (llvmFieldOffset fp) off - , Just Refl <- testEquality (exprLLVMTypeWidth fp) (mbExprLLVMTypeWidth - mb_fp) = + , Just Refl <- testEquality (llvmFieldSize fp) (mbLLVMFieldSize mb_fp) = -- Step 1: make sure to have a variable for the contents implElimLLVMFieldContentsM x fp >>>= \y -> let fp' = fp { llvmFieldContents = ValPerm_Eq (PExpr_Var y) } in @@ -4979,13 +5006,13 @@ proveVarLLVMFieldH x (Perm_LLVMField fp) off mb_fp -- Step 4: equalize the read/write modalities. This is done after changing -- the lifetime so that the original modality is recovered after any borrow -- performed above is over. - equalizeRWs x (\rw -> fp''' { llvmFieldRW = rw }) (llvmFieldRW fp) - (mbLLVMFieldRW mb_fp) (SImpl_DemoteLLVMFieldRW x fp''') >>> + equalizeRWs x (\rw -> ValPerm_LLVMField $ fp''' { llvmFieldRW = rw }) + (llvmFieldRW fp) (mbLLVMFieldRW mb_fp) (SImpl_DemoteLLVMFieldRW x fp''') >>> return () -- If we have a block permission on the left, eliminate it proveVarLLVMFieldH x (Perm_LLVMBlock bp) off mb_fp = - implElimLLVMBlockForOffset x bp True off (MbLLVMField_Perm mb_fp) >>>= \p -> + implElimLLVMBlockForOffset x bp True off (mbValPerm_LLVMField mb_fp) >>>= \p -> proveVarLLVMFieldH x p off mb_fp -- If we have a copyable array permission on the left such that @off@ matches an @@ -4996,7 +5023,7 @@ proveVarLLVMFieldH x p@(Perm_LLVMArray ap) off mb_fp , atomicPermIsCopyable p = implLLVMArrayCellCopy x ap cell >>> recombinePerm x (ValPerm_LLVMArray ap) >>> - proveVarLLVMFieldH x (ValPerm_LLVMBlock $ llvmArrayCellPerm ap cell) off mb_fp + proveVarLLVMFieldH x (Perm_LLVMBlock $ llvmArrayCellPerm ap cell) off mb_fp -- If we have a non-copyable array permission on the left such that @off@ -- matches an index into that array permission, borrow the corresponding cell @@ -5006,12 +5033,12 @@ proveVarLLVMFieldH x p@(Perm_LLVMArray ap) off mb_fp implLLVMArrayCellBorrow x ap cell >>> recombinePerm x (ValPerm_LLVMArray $ llvmArrayAddBorrow (FieldBorrow cell) ap) >>> - proveVarLLVMFieldH x (ValPerm_LLVMBlock $ - llvmArrayCellPerm ap cell) off mb_fp + proveVarLLVMFieldH x (Perm_LLVMBlock $ llvmArrayCellPerm ap cell) off mb_fp -- If none of the above cases match, then fail proveVarLLVMFieldH x p _ mb_fp = - implFailVarM x (ValPerm_Conj1 p) (MbValPerm_LLVMField mb_fp) + implFailVarM "proveVarLLVMField" x (ValPerm_Conj1 p) + (mbValPerm_LLVMField mb_fp) ---------------------------------------------------------------------- @@ -5032,14 +5059,13 @@ proveVarLLVMArray x first_p ps mb_ap = pretty "proveVarLLVMArray:" <+> permPretty i x <> colon <> align (sep [PP.group (permPretty i (ValPerm_Conj ps)), pretty "-o", - PP.group (permPretty i (ValPerm_Conj1 $ - Perm_LLVMArray ap))])) >>> + PP.group (permPretty i mb_ap)])) >>> getPSubst >>>= \psubst -> proveVarLLVMArrayH x first_p psubst ps mb_ap proveVarLLVMArrayH :: (1 <= w, KnownNat w, NuMatchingAny1 r) => ExprVar (LLVMPointerType w) -> - Bool -> [AtomicPerm (LLVMPointerType w)] -> PartialSubst vars -> + Bool -> PartialSubst vars -> [AtomicPerm (LLVMPointerType w)] -> Mb vars (LLVMArrayPerm w) -> ImplM vars s r (ps :> LLVMPointerType w) (ps :> LLVMPointerType w) () @@ -5047,13 +5073,16 @@ proveVarLLVMArrayH :: proveVarLLVMArrayH x first_p psubst ps mb_ap | Just len <- partialSubst psubst $ mbLLVMArrayLen mb_ap , bvIsZero len = + implPopM x (ValPerm_Conj ps) >>> partialSubstForceM mb_ap "proveVarLLVMArray: incomplete psubst" >>>= \ap -> implLLVMArrayEmpty x ap +-- Otherwise, look for any permission the could contain the offset of mb_ap proveVarLLVMArrayH x first_p _ ps mb_ap = partialSubstForceM (mbLLVMArrayOffset mb_ap) "proveVarLLVMArray: incomplete array offset" >>>= \off -> - implGetLLVMPermForOffset ps first_p True off >>>= \case + implGetLLVMPermForOffset x ps first_p True off + (mbValPerm_LLVMArray mb_ap) >>>= \case -- If ps are eliminated to a field permission for off, pop all the permissions -- for x and then prove the first cell of ap followed by the rest @@ -5065,13 +5094,13 @@ proveVarLLVMArrayH x first_p _ ps mb_ap = -- after popping the remaining permissions for x Perm_LLVMArray ap_lhs | llvmArrayStride ap_lhs == mbLLVMArrayStride mb_ap -> - proveVarLLVMArray_FromArray x ps' ap_lhs mb_ap + proveVarLLVMArray_FromArray x ap_lhs mb_ap >>>= \_ -> return () -- Because we told implGetLLVMPermForOffset to eliminate block perms, there -- should be no other cases that will work here, so fail _ -> implFailVarM "proveVarLLVMArrayH" x (ValPerm_Conj ps) - (MbValPerm_LLVMArray mb_ap) + (mbValPerm_LLVMArray mb_ap) -- | Prove an array permission by proving its first cell and then its remaining @@ -5084,9 +5113,9 @@ proveVarLLVMArray_FromHead x mb_ap = -- Prove the head permission and convert to an array let mb_bp = mbMapCl $(mkClosed [| llvmArrayPermHead |]) mb_ap mb_p = mbMapCl $(mkClosed [| ValPerm_LLVMBlock |]) mb_bp in - proveVarImplInt x mb_bp >>> + proveVarImplInt x (mbValPerm_LLVMBlock mb_bp) >>> partialSubstForceM mb_bp "proveVarLLVMArray: incomplete psubst" >>>= \bp_head -> - implSimplM Proxy (SImpl_LLVMArrayFromBlock x bp) >>> + implSimplM Proxy (SImpl_LLVMArrayFromBlock x bp_head) >>> let ap_head = case llvmBlockPermToArray1 bp_head of Just ap -> ap Nothing -> error "proveVarLLVMArray: unexpected form of head cell" in @@ -5102,7 +5131,7 @@ proveVarLLVMArray_FromHead x mb_ap = -- Otherwise, recursively prove the tail of mb_ap getAtomicPerms x >>>= \ps'' -> implPushM x (ValPerm_Conj ps'') >>> - let mb_ap_tail = mbMapCl $(mkClosed [| llvmArrayPermTailPerm |]) mb_ap in + let mb_ap_tail = mbMapCl $(mkClosed [| llvmArrayPermTail |]) mb_ap in proveVarLLVMArray x False ps'' mb_ap_tail >>> -- Append the head and the tail to get mb_ap @@ -5118,15 +5147,14 @@ proveVarLLVMArray_FromHead x mb_ap = -- proved. proveVarLLVMArray_FromArray :: (1 <= w, KnownNat w, NuMatchingAny1 r) => ExprVar (LLVMPointerType w) -> - LLVMArrayPerm w -> Mb ctx (LLVMArrayPerm w) -> + LLVMArrayPerm w -> Mb vars (LLVMArrayPerm w) -> ImplM vars s r (ps :> LLVMPointerType w) (ps :> LLVMPointerType w) (LLVMArrayPerm w) proveVarLLVMArray_FromArray x ap_lhs mb_ap = implTraceM (\info -> pretty "proveVarLLVMArray_FromArray:" <+> permPretty info x <> colon <> - align (sep [PP.group (permPretty info (ValPerm_Conj ps)) <> comma, - permPretty info (ValPerm_LLVMArray ap), + align (sep [permPretty info (ValPerm_LLVMArray ap_lhs), pretty "-o", PP.group (permPretty info mb_ap)])) >>> getAtomicPerms x >>>= \ps -> @@ -5136,6 +5164,7 @@ proveVarLLVMArray_FromArray x ap_lhs mb_ap = "proveVarLLVMArray: incomplete psubst" >>>= \len -> partialSubstForceM (mbLLVMArrayBorrows mb_ap) "proveVarLLVMArray: incomplete array offset" >>>= \bs -> + getAtomicPerms x >>>= \ps -> proveVarLLVMArray_FromArray1 x ps ap_lhs off len bs mb_ap @@ -5153,67 +5182,59 @@ proveVarLLVMArray_FromArray1 :: ImplM vars s r (ps :> LLVMPointerType w) (ps :> LLVMPointerType w) (LLVMArrayPerm w) -FIXME HERE NOWNOW: deal with ap_lhs having an earlier offset than off by -borrowing or copying it +-- If ap_lhs and mb_ap have the same offset and length, proceed to phase 2 +proveVarLLVMArray_FromArray1 x _ ap_lhs off len bs mb_ap + | bvEq off (llvmArrayOffset ap_lhs) + , bvEq len (llvmArrayLen ap_lhs) = + proveVarLLVMArray_FromArray2 x ap_lhs len bs mb_ap --- If ap could be longer than ap_lhs and there is an atomic permission for x +-- If ap could extend beyond ap_lhs and there is an atomic permission for x -- that starts at the end of ap_lhs, then use ap_lhs to prove the first portion -- of ap and then recursively prove the rest proveVarLLVMArray_FromArray1 x ps ap_lhs off len bs mb_ap - | bvCouldBeLt (llvmArrayLen ap_lhs) len - , len' <- llvmArrayOffset ap_lhs - , any (isLLVMAtomicPermWithOffset len') ps + | len' <- bvSub (llvmArrayLen ap_lhs) (bvSub off $ llvmArrayOffset ap_lhs) + , bvCouldBeLt len' len + , off' <- bvAdd off len' + , any (isLLVMAtomicPermWithOffset off') ps , (bs_first, bs_rest) <- partition (\b -> all bvPropCouldHold $ llvmArrayBorrowInArrayBase ap_lhs b) bs = + + -- If ap_lhs starts before ap, then borrow or copy the portion we are going + -- to use, and otherwise just use ap_lhs as is + (if bvEq (llvmArrayOffset ap_lhs) off then return ap_lhs else + (let ap_lhs' = ap_lhs { llvmArrayOffset = off, llvmArrayLen = len' } in + implLLVMArrayGet x ap_lhs ap_lhs' >>>= \ap_lhs'' -> + recombinePerm x (ValPerm_LLVMArray ap_lhs'') >>> + return ap_lhs')) >>>= \ap_lhs' -> + -- Recursively prove ap with length len' and borrows that could be in the -- first portion of ap - proveVarLLVMArray_FromArray1 x ps ap_lhs len' bs_first mb_ap >>>= \ap' -> + proveVarLLVMArray_FromArray2 x ap_lhs len' bs_first mb_ap >>>= \ap' -> -- Prove ap with the remaining offset, length, and borrows let ap_rest = ap' { llvmArrayLen = bvSub len len', - llvmArrayOffset = bvAdd (llvmArrayOffset ap) len', + llvmArrayOffset = bvAdd off len', llvmArrayBorrows = bs_rest } in mbVarsM ap_rest >>>= \mb_ap_rest -> getAtomicPerms x >>>= \ps' -> - proveVarLLVMArray x False ps' mb_ap >>>= \ap_rest' -> + proveVarLLVMArray x False ps' mb_ap_rest >>> -- Combine ap_first and ap_rest to get out ap - implLLVMArrayAppend x ap' ap_rest' >>> + implLLVMArrayAppend x ap' ap_rest >>> implLLVMArrayRearrange x (ap' { llvmArrayLen = len, llvmArrayBorrows = bs_first ++ bs_rest }) bs >>> return (ap' { llvmArrayLen = len, llvmArrayBorrows = bs }) --- If ap_lhs could be longer than ap, borrow or copy len bytes of ap_lhs and --- recurse -proveVarLLVMArray_FromArray1 x ps ap_lhs len bs mb_ap - | bvCouldBeLt len (llvmArrayLen ap_lhs) = - let ap_lhs' = ap_lhs { llvmArrayLen = len } in - (if atomicPermIsCopyable (Perm_LLVMArray ap) then - implLLVMArrayCopy x ap_lhs ap_lhs' >>> - recombinePerm x (ValPerm_Conj1 $ Perm_LLVMArray ap_lhs) - else - implLLVMArrayBorrow x ap_lhs ap_lhs' >>> - recombinePerm x (ValPerm_Conj1 $ Perm_LLVMArray $ - llvmArrayAddBorrow - (llvmSubArrayBorrow ap_lhs ap_lhs') ap_lhs)) >>> - getAtomicPerms x >>>= \ps' -> - proveVarLLVMArray_FromArray1 x ps' ap_lhs' len bs mb_ap - --- If ap_lhs and mb_ap have the same length, proceed to phase 2 -proveVarLLVMArray_FromArray1 x ps ap_lhs len bs mb_ap - | bvEq len (llvmArrayLen ap_lhs) = - proveVarLLVMArray_FromArray2 x ps ap_lhs bs mb_ap - --- If we get to this point, we can't prove mb_ap from ap_lhs, so fail -proveVarLLVMArray_FromArray1 x ps ap_lhs len bs mb_ap = - implFailVarM "proveVarLLVMArray_FromArray1" x - (ValPerm_Conj (Perm_LLVMArray ap_lhs:ps)) - (fmap (\ap -> ValPerm_LLVMArray $ ap { llvmArrayLen = len, - llvmArrayBorrows = bs }) mb_ap) +-- Otherwise, borrow or copy len bytes of ap_lhs and recurse +proveVarLLVMArray_FromArray1 x ps ap_lhs off len bs mb_ap = + let ap_lhs' = ap_lhs { llvmArrayOffset = off, llvmArrayLen = len } in + implLLVMArrayGet x ap_lhs ap_lhs' >>>= \ap_lhs'' -> + recombinePerm x (ValPerm_LLVMArray ap_lhs'') >>> + proveVarLLVMArray_FromArray2 x ap_lhs' len bs mb_ap -- | Prove an array permission @mb_ap@ with borrows set to the supplied list and @@ -5222,8 +5243,8 @@ proveVarLLVMArray_FromArray1 x ps ap_lhs len bs mb_ap = -- Return the resulting array permission that was proved. proveVarLLVMArray_FromArray2 :: (1 <= w, KnownNat w, NuMatchingAny1 r) => ExprVar (LLVMPointerType w) -> - [AtomicPerm (LLVMPointerType w)] -> LLVMArrayPerm w -> - [LLVMArrayBorrow w] -> Mb ctx (LLVMArrayPerm w) -> + LLVMArrayPerm w -> PermExpr (BVType w) -> [LLVMArrayBorrow w] -> + Mb vars (LLVMArrayPerm w) -> ImplM vars s r (ps :> LLVMPointerType w) (ps :> LLVMPointerType w) (LLVMArrayPerm w) @@ -5232,11 +5253,11 @@ proveVarLLVMArray_FromArray2 :: -- FIXME: when an array ap_ret is being borrowed from ap_lhs, this code requires -- all of it to be returned, with no borrows, even though it could be that ap -- allows some of ap_ret to be borrowed -proveVarLLVMArray_FromArray2 x ps ap_lhs bs mb_ap +proveVarLLVMArray_FromArray2 x ap_lhs len bs mb_ap | Just b <- find (flip notElem bs) (llvmArrayBorrows ap_lhs) = -- Prove the rest of ap with b borrowed - proveVarLLVMArray_FromArray2 x ps ap_lhs (b:bs) mb_ap >>>= \ap' -> + proveVarLLVMArray_FromArray2 x ap_lhs len (b:bs) mb_ap >>>= \ap' -> -- Prove the borrowed perm let p = permForLLVMArrayBorrow ap' b in @@ -5251,11 +5272,11 @@ proveVarLLVMArray_FromArray2 x ps ap_lhs bs mb_ap -- If there is a borrow in ap that is not in ap_lhs, borrow it from ap_lhs. Note -- the assymmetry with the previous case: we only add borrows if we definitely -- have to, but we remove borrows if we might have to. -proveVarLLVMArray_FromArray2 x ps ap_lhs len bs mb_ap +proveVarLLVMArray_FromArray2 x ap_lhs len bs mb_ap | Just b <- find (flip notElem (llvmArrayBorrows ap_lhs)) bs = -- Prove the rest of ap without b borrowed - proveVarLLVMArray_FromArray x ps ap_lhs (delete b bs) mb_ap >>>= \ap' -> + proveVarLLVMArray_FromArray2 x ap_lhs len (delete b bs) mb_ap >>>= \ap' -> -- Borrow the permission if that is possible; this will fail if ap has a -- borrow that is not actually in its range. Note that the borrow is always @@ -5268,16 +5289,16 @@ proveVarLLVMArray_FromArray2 x ps ap_lhs len bs mb_ap -- If we get here then ap_lhs and ap have the same borrows, offset, length, and -- stride, so equalize their modalities, prove the shape of mb_ap from that of -- ap_lhs, rearrange their borrows, and we are done -proveVarLLVMArray_FromArrayH x ps ap_lhs len bs mb_ap = +proveVarLLVMArray_FromArray2 x ap_lhs len bs mb_ap = -- Coerce the rw modality of ap_lhs to that of mb_ap, if possibe - equalizeRWs x (\rw -> ap_lhs { llvmArrayRW = rw }) + equalizeRWs x (\rw -> ValPerm_LLVMArray $ ap_lhs { llvmArrayRW = rw }) (llvmArrayRW ap_lhs) (mbLLVMArrayRW mb_ap) (SImpl_DemoteLLVMArrayRW x ap_lhs) >>>= \rw -> let ap_lhs' = ap_lhs { llvmArrayRW = rw } in -- Coerce the lifetime of ap_lhs to that of mb_ap, if possible let (f, args) = arrayToLTFunc ap_lhs' in - proveVarLifetimeFunctor x f args (llvmFieldLifetime ap_lhs) + proveVarLifetimeFunctor x f args (llvmArrayLifetime ap_lhs) (mbLLVMArrayLifetime mb_ap) >>>= \l -> let ap_lhs'' = ap_lhs' { llvmArrayLifetime = l } in @@ -5416,6 +5437,8 @@ proveNamedArg x npn args off memb psubst arg = case mbMatch arg of -- * Proving LLVM Block Permissions ---------------------------------------------------------------------- +-- FIXME HERE: maybe use implGetLLVMPermForOffset for proveVarLLVMBlock? + -- | Prove a @memblock@ permission from the conjunction of the supplied atomic -- permissions which are on the top of the stack proveVarLLVMBlock :: @@ -5426,9 +5449,6 @@ proveVarLLVMBlock x ps mb_bp = do psubst <- getPSubst proveVarLLVMBlocks x ps psubst [mb_bp] -FIXME HERE NOWNOW: do we need to use implGetLLVMPermForOffset for -proveVarLLVMBlock? - -- | Prove a conjunction of block and atomic permissions for @x@, assuming all -- of the permissions for @x@ are on the top of the stack and given by the -- second argument. The block permissions are the ones that we are currently @@ -5454,7 +5474,7 @@ proveVarLLVMBlocks :: [Mb vars (LLVMBlockPerm w)] -> ImplM vars s r (ps :> LLVMPointerType w) (ps :> LLVMPointerType w) () -proveVarLLVMBlocks x ps psubst mb_bps mb_ps = +proveVarLLVMBlocks x ps psubst mb_bps = -- This substitution is to only print the existential vars once, on the -- outside; also, substituting here ensures that we only traverse the -- permissions once @@ -5497,42 +5517,6 @@ proveVarLLVMBlocksExt2 x ps psubst mb_bps_ext mb_bps = (mbList mb_bps_ext ++ (map (extMb . extMb) mb_bps))) >>= \((_,e2),e1) -> pure (e1,e2) --- | Assume the first block permission is on top of the stack, and attempt to --- coerce its read-write modality to that of the second, leaving the resulting --- block permission on top of the stack. Return the resulting block permission. -equalizeBlockRWs :: (1 <= w, KnownNat w, NuMatchingAny1 r) => - ExprVar (LLVMPointerType w) -> LLVMBlockPerm w -> - Mb vars (LLVMBlockPerm w) -> - ImplM vars s r - (ps :> LLVMPointerType w) (ps :> LLVMPointerType w) - (LLVMBlockPerm w) -equalizeBlockRWs x bp mb_bp - | mbLift (fmap ((== llvmBlockRW bp) . llvmBlockRW) mb_bp) = - return bp -equalizeBlockRWs x bp mb_bp - | [nuMP| PExpr_Read |] <- mbMatch (fmap llvmBlockRW mb_bp) = - implSimplM Proxy (SImpl_DemoteLLVMBlockRW x bp) >>> - return (bp { llvmBlockRW = PExpr_Read }) -equalizeBlockRWs x bp mb_bp = - proveEqCast x (\rw -> ValPerm_LLVMBlock $ bp { llvmBlockRW = rw }) - (llvmBlockRW bp) (fmap llvmBlockRW mb_bp) >>> - return bp - --- | Assume the first block permission is on top of the stack, and attempt to --- coerce its lifetime to that of the second, leaving the resulting block --- permission on top of the stack. Return the resulting block permission. -equalizeBlockLifetimes :: (1 <= w, KnownNat w, NuMatchingAny1 r) => - ExprVar (LLVMPointerType w) -> LLVMBlockPerm w -> - Mb vars (LLVMBlockPerm w) -> - ImplM vars s r - (ps :> LLVMPointerType w) (ps :> LLVMPointerType w) - (LLVMBlockPerm w) -equalizeBlockLifetimes x bp mb_bp = - let (f, args) = blockToLTFunc bp' in - proveVarLifetimeFunctor x f args (llvmBlockLifetime bp) - (fmap llvmBlockLifetime mb_bp) >>>= \l -> - return (bp { llvmBlockLifetime = l }) - -- | Assume the first block permission is on top of the stack, and attempt to -- coerce its read-write modality and lifetime to those of the second, leaving -- the resulting block permission on top of the stack. Return the resulting @@ -5544,8 +5528,14 @@ equalizeBlockModalities :: (1 <= w, KnownNat w, NuMatchingAny1 r) => (ps :> LLVMPointerType w) (ps :> LLVMPointerType w) (LLVMBlockPerm w) equalizeBlockModalities x bp mb_bp = - equalizeBlockRWs x bp mb_bp >>>= \bp' -> - equalizeBlockLifetimes x bp' mb_bp + equalizeRWs x (\rw -> ValPerm_LLVMBlock $ bp { llvmBlockRW = rw }) + (llvmBlockRW bp) (mbLLVMBlockRW mb_bp) (SImpl_DemoteLLVMBlockRW x bp) + >>>= \rw -> + let bp' = bp { llvmBlockRW = rw } + (f, args) = blockToLTFunc bp' in + proveVarLifetimeFunctor x f args (llvmBlockLifetime bp) + (fmap llvmBlockLifetime mb_bp) >>>= \l -> + return (bp' { llvmBlockLifetime = l }) -- | Stage 1 of 'proveVarLLVMBlocks'. See that comments on that function. @@ -5876,7 +5866,8 @@ proveVarLLVMBlocks2 x ps psubst mb_bp mb_sh mb_bps -- assuming it is defined proveVarLLVMBlocks2 x ps psubst mb_bp mb_sh mb_bps | [nuMP| PExpr_PtrShape _ _ _ |] <- mb_sh - , [nuMP| Just mb_bp' |] <- fmap llvmBlockPtrShapeUnfold mb_bp = + , [nuP| Just mb_bp' |] <- mbMapCl $(mkClosed + [| llvmBlockPtrShapeUnfold |]) mb_bp = -- Recursively prove the required field permission and all the other block -- permissions @@ -5897,7 +5888,7 @@ proveVarLLVMBlocks2 x ps psubst mb_bp mb_sh mb_bps -- If proving a field shape, prove the remaining blocks and then prove the -- corresponding field permission -proveVarLLVMBlocks2 x ps psubst mb_bp mb_sh mb_bps mb_ps +proveVarLLVMBlocks2 x ps psubst mb_bp mb_sh mb_bps | [nuMP| PExpr_FieldShape (LLVMFieldShape mb_p) |] <- mb_sh , sz <- mbExprLLVMTypeWidth mb_p = @@ -5907,8 +5898,9 @@ proveVarLLVMBlocks2 x ps psubst mb_bp mb_sh mb_bps mb_ps -- Prove the corresponding field permission proveVarImplInt x (mbMapCl - $(mkClosed [| ValPerm_LLVMField . fromJust . - llvmBlockPermToField sz |]) mb_bp) >>> + ($(mkClosed [| \sz' -> ValPerm_LLVMField . fromJust . + llvmBlockPermToField sz' |]) + `clApply` toClosed sz) mb_bp) >>> getTopDistPerm x >>>= \(ValPerm_LLVMField fp) -> -- Finally, convert the field perm to a block and move it into position @@ -5918,7 +5910,7 @@ proveVarLLVMBlocks2 x ps psubst mb_bp mb_sh mb_bps mb_ps -- If proving a field shape, prove the remaining blocks and then prove the -- corresponding array permission -proveVarLLVMBlocks2 x ps psubst mb_bp mb_sh mb_bps mb_ps +proveVarLLVMBlocks2 x ps psubst mb_bp mb_sh mb_bps | [nuMP| PExpr_ArrayShape _ _ _ |] <- mb_sh = -- Recursively prove the remaining block permissions proveVarLLVMBlocks x ps psubst mb_bps >>> @@ -5931,7 +5923,8 @@ proveVarLLVMBlocks2 x ps psubst mb_bp mb_sh mb_bps mb_ps -- Finally, convert the array perm to a block and move it into position implSimplM Proxy (SImpl_IntroLLVMBlockArray x ap) >>> - implSwapInsertConjM x (Perm_LLVMBlock $ llvmArrayPermToBlock ap) ps' 0 + implSwapInsertConjM x (Perm_LLVMBlock $ fromJust $ + llvmArrayPermToBlock ap) ps' 0 -- If proving a sequence shape, prove the two shapes and combine them; this diff --git a/heapster-saw/src/Verifier/SAW/Heapster/Permissions.hs b/heapster-saw/src/Verifier/SAW/Heapster/Permissions.hs index 44f6bb3206..342a5995c8 100644 --- a/heapster-saw/src/Verifier/SAW/Heapster/Permissions.hs +++ b/heapster-saw/src/Verifier/SAW/Heapster/Permissions.hs @@ -1520,6 +1520,7 @@ pattern ValPerm_LLVMField fp <- ValPerm_Conj [Perm_LLVMField fp] where ValPerm_LLVMField fp = ValPerm_Conj [Perm_LLVMField fp] +{- FIXME: why doesn't this work? -- | The conjunction of exactly 1 field permission in a binding pattern MbValPerm_LLVMField :: () => (a ~ LLVMPointerType w, 1 <= w, KnownNat w, 1 <= sz, KnownNat sz) => @@ -1529,6 +1530,13 @@ pattern MbValPerm_LLVMField mb_fp <- [nuP| ValPerm_LLVMField mb_fp |] where MbValPerm_LLVMField mb_fp = mbMapCl $(mkClosed [| ValPerm_LLVMField |]) mb_fp +-} + +-- | Build a 'ValPerm_LLVMField' in a binding +mbValPerm_LLVMField :: (1 <= w, KnownNat w, 1 <= sz, KnownNat sz) => + Mb ctx (LLVMFieldPerm w sz) -> + Mb ctx (ValuePerm (LLVMPointerType w)) +mbValPerm_LLVMField = mbMapCl $(mkClosed [| ValPerm_LLVMField |]) -- | The conjunction of exactly 1 array permission pattern ValPerm_LLVMArray :: () => (a ~ LLVMPointerType w, 1 <= w, KnownNat w) => @@ -1537,23 +1545,20 @@ pattern ValPerm_LLVMArray ap <- ValPerm_Conj [Perm_LLVMArray ap] where ValPerm_LLVMArray ap = ValPerm_Conj [Perm_LLVMArray ap] +{- FIXME: why doesn't this work? -- | The conjunction of exactly 1 array permission pattern MbValPerm_LLVMArray :: () => (a ~ LLVMPointerType w, 1 <= w, KnownNat w) => Mb ctx (LLVMArrayPerm w) -> Mb ctx (ValuePerm a) -pattern MbValPerm_LLVMArray mb_ap <- [nuP| ValPerm_LLVMArray ap |] +pattern MbValPerm_LLVMArray mb_ap <- [nuP| ValPerm_LLVMArray mb_ap |] where MbValPerm_LLVMArray mb_ap = mbMapCl $(mkClosed [| ValPerm_LLVMArray |]) mb_ap +-} --- | The conjunction of exactly 1 array permission in a binding -pattern MbValPerm_LLVMField :: () => (a ~ LLVMPointerType w, 1 <= w, KnownNat w, - 1 <= sz, KnownNat sz) => - Mb ctx (LLVMFieldPerm w sz) -> - Mb ctx (ValuePerm a) -pattern MbValPerm_LLVMField mb_fp <- [nuP| ValPerm_LLVMField mb_fp |] - where - MbValPerm_LLVMField mb_fp = - mbMapCl $(mkClosed [| ValPerm_LLVMField |]) mb_fp +-- | Build a 'ValPerm_LLVMArray' in a binding +mbValPerm_LLVMArray :: (1 <= w, KnownNat w) => Mb ctx (LLVMArrayPerm w) -> + Mb ctx (ValuePerm (LLVMPointerType w)) +mbValPerm_LLVMArray = mbMapCl $(mkClosed [| ValPerm_LLVMArray |]) -- | The conjunction of exactly 1 block permission pattern ValPerm_LLVMBlock :: () => (a ~ LLVMPointerType w, 1 <= w, KnownNat w) => @@ -1562,6 +1567,11 @@ pattern ValPerm_LLVMBlock bp <- ValPerm_Conj [Perm_LLVMBlock bp] where ValPerm_LLVMBlock bp = ValPerm_Conj [Perm_LLVMBlock bp] +-- | Build a 'ValPerm_LLVMBlock' in a binding +mbValPerm_LLVMBlock :: (1 <= w, KnownNat w) => Mb ctx (LLVMBlockPerm w) -> + Mb ctx (ValuePerm (LLVMPointerType w)) +mbValPerm_LLVMBlock = mbMapCl $(mkClosed [| ValPerm_LLVMBlock |]) + -- | The conjunction of exactly 1 block shape permission pattern ValPerm_LLVMBlockShape :: () => (a ~ LLVMBlockType w, b ~ LLVMShapeType w, 1 <= w, KnownNat w) => @@ -1659,6 +1669,19 @@ data LLVMFieldPerm w sz = llvmFieldSize :: KnownNat sz => LLVMFieldPerm w sz -> NatRepr sz llvmFieldSize _ = knownNat +-- | Helper to get a 'NatRepr' for the size of an 'LLVMFieldPerm' in a binding +mbLLVMFieldSize :: KnownNat sz => Mb ctx (LLVMFieldPerm w sz) -> NatRepr sz +mbLLVMFieldSize _ = knownNat + +-- | Get the rw-modality-in-binding of a field permission in binding +mbLLVMFieldRW :: Mb ctx (LLVMFieldPerm w sz) -> Mb ctx (PermExpr RWModalityType) +mbLLVMFieldRW = mbMapCl $(mkClosed [| llvmFieldRW |]) + +-- | Get the offset-in-binding of a field permission in binding +mbLLVMFieldOffset :: Mb ctx (LLVMFieldPerm w sz) -> Mb ctx (PermExpr (BVType w)) +mbLLVMFieldOffset = mbMapCl $(mkClosed [| llvmFieldOffset |]) + + -- | Helper type to represent byte offsets -- -- > stride * ix + off @@ -1758,13 +1781,9 @@ data LLVMBlockPerm w = } deriving Eq --- | Convenience function for building a single llvmblock permission -mkLLVMBlockPerm :: (1 <= w, KnownNat w) => - PermExpr RWModalityType -> PermExpr LifetimeType -> - PermExpr (BVType w) -> PermExpr (BVType w) -> - PermExpr (LLVMShapeType w) -> ValuePerm (LLVMPointerType w) -mkLLVMBlockPerm rw l off len sh = - ValPerm_Conj1 $ Perm_LLVMBlock $ LLVMBlockPerm rw l off len sh +-- | Get the rw-modality-in-binding of a block permission in binding +mbLLVMBlockRW :: Mb ctx (LLVMBlockPerm w) -> Mb ctx (PermExpr RWModalityType) +mbLLVMBlockRW = mbMapCl $(mkClosed [| llvmBlockRW |]) -- | An LLVM shape for a single pointer field of unknown size data LLVMFieldShape w = @@ -3350,7 +3369,7 @@ llvmArrayCellPerm ap cell = -- | Get the permission for the first cell of an array permission llvmArrayPermHead :: (1 <= w, KnownNat w) => LLVMArrayPerm w -> LLVMBlockPerm w -llvmArrayPermHead ap = llvmArrayCellPerm (bvInt 0) +llvmArrayPermHead ap = llvmArrayCellPerm ap (bvInt 0) -- | Get the permission for all of an array permission after the first cell llvmArrayPermTail :: (1 <= w, KnownNat w) => LLVMArrayPerm w -> LLVMArrayPerm w @@ -3953,8 +3972,8 @@ llvmArrayIndexInArray ap ix = -- | Test if a cell is in an array permission and is not currently being -- borrowed -llvmArrayCellInArray :: (1 <= w, KnownNat w) => PermExpr (BVType w) -> - BVRange w -> [BVProp w] +llvmArrayCellInArray :: (1 <= w, KnownNat w) => + LLVMArrayPerm w -> PermExpr (BVType w) -> [BVProp w] llvmArrayCellInArray ap cell = llvmArrayBorrowInArray ap (FieldBorrow cell) -- | Test if all cell numbers in a 'BVRange' are in an array permission and are From a48ee2112be8c74c4b868c4e61aed150419ae704 Mon Sep 17 00:00:00 2001 From: Eddy Westbrook Date: Thu, 23 Sep 2021 06:38:32 -0700 Subject: [PATCH 55/98] finally got Implication.hs to compile --- .../src/Verifier/SAW/Heapster/Implication.hs | 33 ++++++++++--------- 1 file changed, 17 insertions(+), 16 deletions(-) diff --git a/heapster-saw/src/Verifier/SAW/Heapster/Implication.hs b/heapster-saw/src/Verifier/SAW/Heapster/Implication.hs index a4dfbd51b5..5e7f1fc3bb 100644 --- a/heapster-saw/src/Verifier/SAW/Heapster/Implication.hs +++ b/heapster-saw/src/Verifier/SAW/Heapster/Implication.hs @@ -1767,7 +1767,9 @@ simplImplIn (SImpl_IntroLLVMBlockFromEq x bp y) = bp { llvmBlockShape = PExpr_EqShape $ PExpr_Var y }) y (ValPerm_Conj1 $ Perm_LLVMBlockShape $ llvmBlockShape bp) simplImplIn (SImpl_IntroLLVMBlockPtr x bp) = - distPerms1 x $ ValPerm_LLVMBlock $ llvmBlockPtrShapeUnfold bp + case llvmBlockPtrShapeUnfold bp of + Just bp' -> distPerms1 x $ ValPerm_LLVMBlock bp' + Nothing -> error "simplImplIn: SImpl_IntroLLVMBlockPtr: malformed block shape" simplImplIn (SImpl_ElimLLVMBlockPtr x bp) = distPerms1 x $ ValPerm_LLVMBlock bp simplImplIn (SImpl_IntroLLVMBlockField x fp) = @@ -4071,9 +4073,8 @@ implElimLLVMBlock x bp@(LLVMBlockPerm { llvmBlockShape = implSimplM Proxy (SImpl_IntroLLVMBlockFromEq x bp' y) -- For [l]ptrsh(rw,sh), eliminate to a pointer to a memblock with shape sh -implElimLLVMBlock x bp@(LLVMBlockPerm { llvmBlockShape = - PExpr_PtrShape maybe_rw maybe_l sh }) - | Just len <- llvmShapeLength sh = +implElimLLVMBlock x bp@(LLVMBlockPerm { llvmBlockShape = PExpr_PtrShape _ _ _ }) + | isJust (llvmBlockPtrShapeUnfold bp) = implSimplM Proxy (SImpl_ElimLLVMBlockPtr x bp) -- For a field shape, eliminate to a field permission @@ -4221,6 +4222,7 @@ implElimLLVMBlockForOffset x bp imprecise_p off mb_p = -- permissions for @x@. If no matches are found, fail using 'implFailVarM', -- citing the supplied permission as the one we are trying to prove. implGetLLVMPermForOffset :: + (1 <= w, KnownNat w, NuMatchingAny1 r) => ExprVar (LLVMPointerType w) -> {- ^ the variable @x@ -} [AtomicPerm (LLVMPointerType w)] -> {- ^ the permissions held for @x@ -} Bool -> {- ^ whether imprecise matches are allowed -} @@ -4728,17 +4730,17 @@ equalizeRWsH :: NuMatchingAny1 r => ExprVar a -> ImplM vars s r (ps :> a) (ps :> a) (PermExpr RWModalityType) -- If rw and mb_rw are already equal, just return rw -equalizeRWsH x f rw psubst mb_rw _ +equalizeRWsH _ _ rw psubst mb_rw _ | Just rw' <- partialSubst psubst mb_rw , rw == rw' = return rw -- If mb_rw is read, weaken rw to read using the supplied rule -equalizeRWsH x f rw psubst mb_rw impl +equalizeRWsH _ _ _ psubst mb_rw impl | Just PExpr_Read <- partialSubst psubst mb_rw = implSimplM Proxy impl >>> return PExpr_Read -- Otherwise, prove rw = mb_rw and cast f(rw) to f(mb_rw) -equalizeRWsH x f rw psubst mb_rw _ = +equalizeRWsH x f rw _ mb_rw _ = proveEqCast x f rw mb_rw >>> partialSubstForceM mb_rw "equalizeRWs: incomplete psubst" @@ -5027,7 +5029,7 @@ proveVarLLVMFieldH x p@(Perm_LLVMArray ap) off mb_fp -- If we have a non-copyable array permission on the left such that @off@ -- matches an index into that array permission, borrow the corresponding cell -proveVarLLVMFieldH x p@(Perm_LLVMArray ap) off mb_fp +proveVarLLVMFieldH x (Perm_LLVMArray ap) off mb_fp | Just ix <- matchLLVMArrayIndex ap off , cell <- llvmArrayIndexCell ix = implLLVMArrayCellBorrow x ap cell >>> @@ -5070,7 +5072,7 @@ proveVarLLVMArrayH :: ImplM vars s r (ps :> LLVMPointerType w) (ps :> LLVMPointerType w) () -- Special case: if the length is 0, prove an empty array -proveVarLLVMArrayH x first_p psubst ps mb_ap +proveVarLLVMArrayH x _ psubst ps mb_ap | Just len <- partialSubst psubst $ mbLLVMArrayLen mb_ap , bvIsZero len = implPopM x (ValPerm_Conj ps) >>> @@ -5111,8 +5113,7 @@ proveVarLLVMArray_FromHead :: ImplM vars s r (ps :> LLVMPointerType w) ps () proveVarLLVMArray_FromHead x mb_ap = -- Prove the head permission and convert to an array - let mb_bp = mbMapCl $(mkClosed [| llvmArrayPermHead |]) mb_ap - mb_p = mbMapCl $(mkClosed [| ValPerm_LLVMBlock |]) mb_bp in + let mb_bp = mbMapCl $(mkClosed [| llvmArrayPermHead |]) mb_ap in proveVarImplInt x (mbValPerm_LLVMBlock mb_bp) >>> partialSubstForceM mb_bp "proveVarLLVMArray: incomplete psubst" >>>= \bp_head -> implSimplM Proxy (SImpl_LLVMArrayFromBlock x bp_head) >>> @@ -5164,7 +5165,6 @@ proveVarLLVMArray_FromArray x ap_lhs mb_ap = "proveVarLLVMArray: incomplete psubst" >>>= \len -> partialSubstForceM (mbLLVMArrayBorrows mb_ap) "proveVarLLVMArray: incomplete array offset" >>>= \bs -> - getAtomicPerms x >>>= \ps -> proveVarLLVMArray_FromArray1 x ps ap_lhs off len bs mb_ap @@ -5178,7 +5178,7 @@ proveVarLLVMArray_FromArray1 :: (1 <= w, KnownNat w, NuMatchingAny1 r) => ExprVar (LLVMPointerType w) -> [AtomicPerm (LLVMPointerType w)] -> LLVMArrayPerm w -> PermExpr (BVType w) -> PermExpr (BVType w) -> [LLVMArrayBorrow w] -> - Mb ctx (LLVMArrayPerm w) -> + Mb vars (LLVMArrayPerm w) -> ImplM vars s r (ps :> LLVMPointerType w) (ps :> LLVMPointerType w) (LLVMArrayPerm w) @@ -5211,7 +5211,7 @@ proveVarLLVMArray_FromArray1 x ps ap_lhs off len bs mb_ap -- Recursively prove ap with length len' and borrows that could be in the -- first portion of ap - proveVarLLVMArray_FromArray2 x ap_lhs len' bs_first mb_ap >>>= \ap' -> + proveVarLLVMArray_FromArray2 x ap_lhs' len' bs_first mb_ap >>>= \ap' -> -- Prove ap with the remaining offset, length, and borrows let ap_rest = ap' { llvmArrayLen = bvSub len len', @@ -5219,6 +5219,7 @@ proveVarLLVMArray_FromArray1 x ps ap_lhs off len bs mb_ap llvmArrayBorrows = bs_rest } in mbVarsM ap_rest >>>= \mb_ap_rest -> getAtomicPerms x >>>= \ps' -> + implPushM x (ValPerm_Conj ps') >>> proveVarLLVMArray x False ps' mb_ap_rest >>> -- Combine ap_first and ap_rest to get out ap @@ -5230,7 +5231,7 @@ proveVarLLVMArray_FromArray1 x ps ap_lhs off len bs mb_ap -- Otherwise, borrow or copy len bytes of ap_lhs and recurse -proveVarLLVMArray_FromArray1 x ps ap_lhs off len bs mb_ap = +proveVarLLVMArray_FromArray1 x _ ap_lhs off len bs mb_ap = let ap_lhs' = ap_lhs { llvmArrayOffset = off, llvmArrayLen = len } in implLLVMArrayGet x ap_lhs ap_lhs' >>>= \ap_lhs'' -> recombinePerm x (ValPerm_LLVMArray ap_lhs'') >>> @@ -5289,7 +5290,7 @@ proveVarLLVMArray_FromArray2 x ap_lhs len bs mb_ap -- If we get here then ap_lhs and ap have the same borrows, offset, length, and -- stride, so equalize their modalities, prove the shape of mb_ap from that of -- ap_lhs, rearrange their borrows, and we are done -proveVarLLVMArray_FromArray2 x ap_lhs len bs mb_ap = +proveVarLLVMArray_FromArray2 x ap_lhs _ bs mb_ap = -- Coerce the rw modality of ap_lhs to that of mb_ap, if possibe equalizeRWs x (\rw -> ValPerm_LLVMArray $ ap_lhs { llvmArrayRW = rw }) (llvmArrayRW ap_lhs) (mbLLVMArrayRW mb_ap) From d40f6ff70724e44a136002113092d2662154e380 Mon Sep 17 00:00:00 2001 From: Eddy Westbrook Date: Thu, 23 Sep 2021 06:40:48 -0700 Subject: [PATCH 56/98] added support for the new LOwnedPermArray constructor --- heapster-saw/src/Verifier/SAW/Heapster/RustTypes.hs | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/heapster-saw/src/Verifier/SAW/Heapster/RustTypes.hs b/heapster-saw/src/Verifier/SAW/Heapster/RustTypes.hs index 10a5e05b75..a5ac66d24a 100644 --- a/heapster-saw/src/Verifier/SAW/Heapster/RustTypes.hs +++ b/heapster-saw/src/Verifier/SAW/Heapster/RustTypes.hs @@ -1038,6 +1038,15 @@ abstractMbLOPsModalities mb_lops = case mbMatch mb_lops of LOwnedPermField e (fp { llvmFieldRW = PExpr_Var rw, llvmFieldLifetime = PExpr_Var l })) mb_e mb_fp) + [nuMP| lops :>: LOwnedPermArray mb_e mb_ap |] -> + liftA2 (mbMap2 (:>:)) + (abstractMbLOPsModalities lops) + (SomeTypedMb (CruCtxCons (CruCtxCons CruCtxNil RWModalityRepr) LifetimeRepr) $ + nuMulti (MNil :>: Proxy :>: Proxy) $ \(_ :>: rw :>: l) -> + mbMap2 (\e ap -> + LOwnedPermArray e (ap { llvmArrayRW = PExpr_Var rw, + llvmArrayLifetime = PExpr_Var l })) + mb_e mb_ap) [nuMP| lops :>: LOwnedPermBlock mb_e mb_bp |] -> liftA2 (mbMap2 (:>:)) (abstractMbLOPsModalities lops) From a9e4b71d2537b9e1d6df9ad2dcf5ae11af1ced0d Mon Sep 17 00:00:00 2001 From: Eddy Westbrook Date: Thu, 23 Sep 2021 07:07:19 -0700 Subject: [PATCH 57/98] small tweak to avoid warning --- heapster-saw/src/Verifier/SAW/Heapster/RustTypes.hs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/heapster-saw/src/Verifier/SAW/Heapster/RustTypes.hs b/heapster-saw/src/Verifier/SAW/Heapster/RustTypes.hs index a5ac66d24a..86e944900f 100644 --- a/heapster-saw/src/Verifier/SAW/Heapster/RustTypes.hs +++ b/heapster-saw/src/Verifier/SAW/Heapster/RustTypes.hs @@ -1038,15 +1038,15 @@ abstractMbLOPsModalities mb_lops = case mbMatch mb_lops of LOwnedPermField e (fp { llvmFieldRW = PExpr_Var rw, llvmFieldLifetime = PExpr_Var l })) mb_e mb_fp) - [nuMP| lops :>: LOwnedPermArray mb_e mb_ap |] -> + [nuMP| lops :>: LOwnedPermArray mb_e mb_arrp |] -> liftA2 (mbMap2 (:>:)) (abstractMbLOPsModalities lops) (SomeTypedMb (CruCtxCons (CruCtxCons CruCtxNil RWModalityRepr) LifetimeRepr) $ nuMulti (MNil :>: Proxy :>: Proxy) $ \(_ :>: rw :>: l) -> - mbMap2 (\e ap -> - LOwnedPermArray e (ap { llvmArrayRW = PExpr_Var rw, - llvmArrayLifetime = PExpr_Var l })) - mb_e mb_ap) + mbMap2 (\e arrp -> + LOwnedPermArray e (arrp { llvmArrayRW = PExpr_Var rw, + llvmArrayLifetime = PExpr_Var l })) + mb_e mb_arrp) [nuMP| lops :>: LOwnedPermBlock mb_e mb_bp |] -> liftA2 (mbMap2 (:>:)) (abstractMbLOPsModalities lops) From d5f2079c69ecd8b34f528cadd2b5a371ae9bdd8e Mon Sep 17 00:00:00 2001 From: Eddy Westbrook Date: Thu, 23 Sep 2021 07:07:40 -0700 Subject: [PATCH 58/98] updated parser and type-checker for the new array permissions --- .../src/Verifier/SAW/Heapster/Parser.y | 12 ++--- .../src/Verifier/SAW/Heapster/TypeChecker.hs | 45 ++++++++++--------- .../src/Verifier/SAW/Heapster/UntypedAST.hs | 4 +- 3 files changed, 30 insertions(+), 31 deletions(-) diff --git a/heapster-saw/src/Verifier/SAW/Heapster/Parser.y b/heapster-saw/src/Verifier/SAW/Heapster/Parser.y index 643b9fcefc..aef9139552 100644 --- a/heapster-saw/src/Verifier/SAW/Heapster/Parser.y +++ b/heapster-saw/src/Verifier/SAW/Heapster/Parser.y @@ -134,8 +134,8 @@ expr :: { AstExpr } | expr '+' expr { ExAdd (pos $2) $1 $3 } | expr '*' expr { ExMul (pos $2) $1 $3 } | 'struct' '(' list(expr) ')' { ExStruct (pos $1) $3 } - | 'array' '(' expr ',' '<' expr ',' '*' expr ',' '[' list(llvmFieldPermArray) ']' ')' - { ExArray (pos $1) $3 $6 $9 $12 } + | lifetime 'array' '(' expr ',' expr ',' '<' expr ',' '*' expr ',' expr ')' + { ExArray (pos $2) $1 $4 $6 $9 $12 $14 } | 'llvmword' '(' expr ')' { ExLlvmWord (pos $1) $3 } | 'llvmfunptr' '{' expr ',' expr '}' '(' funPerm ')' { ExLlvmFunPtr (pos $1) $3 $5 $8 } @@ -160,8 +160,8 @@ expr :: { AstExpr } | lifetime 'ptrsh' '(' expr ')' { ExPtrSh (pos $2) $1 Nothing $4 } | 'fieldsh' '(' expr ',' expr ')' { ExFieldSh (pos $1) (Just $3) $5 } | 'fieldsh' '(' expr ')' { ExFieldSh (pos $1) Nothing $3 } - | 'arraysh' '(' expr ',' expr ',' '[' list(shape) ']' ')' - { ExArraySh (pos $1) $3 $5 $8 } + | 'arraysh' '(' expr ',' expr ',' expr ')' + { ExArraySh (pos $1) $3 $5 $7 } | 'exsh' IDENT ':' type '.' expr { ExExSh (pos $1) (locThing $2) $4 $6 } -- Value Permissions @@ -195,10 +195,6 @@ expr :: { AstExpr } frameEntry :: { (AstExpr, Natural) } : expr ':' NAT { ($1, locThing $3) } -shape :: { (Maybe AstExpr, AstExpr) } - : expr { (Nothing, $1) } - | '(' expr ',' expr ')' { (Just $2, $4) } - identArgs :: { Maybe [AstExpr] } : { Nothing } | '<' list(expr) '>' { Just $2 } diff --git a/heapster-saw/src/Verifier/SAW/Heapster/TypeChecker.hs b/heapster-saw/src/Verifier/SAW/Heapster/TypeChecker.hs index 872509124f..5e3275f2da 100644 --- a/heapster-saw/src/Verifier/SAW/Heapster/TypeChecker.hs +++ b/heapster-saw/src/Verifier/SAW/Heapster/TypeChecker.hs @@ -431,11 +431,11 @@ tcLLVMShape (ExPtrSh _ maybe_l maybe_rw sh) = <*> traverse tcKExpr maybe_rw <*> tcKExpr sh tcLLVMShape (ExFieldSh _ w fld) = PExpr_FieldShape <$> tcLLVMFieldShape_ w fld -tcLLVMShape (ExArraySh _ len stride flds) = +tcLLVMShape (ExArraySh _ len stride sh) = PExpr_ArrayShape <$> tcKExpr len <*> (Bytes . fromIntegral <$> tcNatural stride) - <*> traverse (uncurry tcLLVMFieldShape_) flds + <*> tcKExpr sh tcLLVMShape e = tcError (pos e) "Expected shape" -- | Field and array helper for 'tcLLVMShape' @@ -524,11 +524,23 @@ tcAtomicPerm (StructRepr tys) e = tcStructAtomic tys e tcAtomicPerm LifetimeRepr e = tcLifetimeAtomic e tcAtomicPerm _ e = tcError (pos e) "Expected perm" +-- | Build a field permission using an 'LLVMFieldShape' +fieldPermFromShape :: (KnownNat w, 1 <= w) => PermExpr RWModalityType -> + PermExpr LifetimeType -> PermExpr (BVType w) -> + LLVMFieldShape w -> AtomicPerm (LLVMPointerType w) +fieldPermFromShape rw l off (LLVMFieldShape p) = + Perm_LLVMField $ LLVMFieldPerm rw l off p + -- | Check an LLVM pointer atomic permission expression tcPointerAtomic :: (KnownNat w, 1 <= w) => AstExpr -> Tc (AtomicPerm (LLVMPointerType w)) -tcPointerAtomic (ExPtr p l rw off sz c) = - llvmArrayFieldToAtomicPerm <$> tcArrayFieldPerm (ArrayPerm p l rw off sz c) -tcPointerAtomic (ExArray _ x y z w) = Perm_LLVMArray <$> tcArrayAtomic x y z w +tcPointerAtomic (ExPtr _ l rw off sz c) = + fieldPermFromShape + <$> tcKExpr rw + <*> tcOptLifetime l + <*> tcKExpr off + <*> tcLLVMFieldShape_ sz c +tcPointerAtomic (ExArray _ l rw off len stride sh) = + Perm_LLVMArray <$> tcArrayAtomic l rw off len stride sh tcPointerAtomic (ExMemblock _ l rw off len sh) = Perm_LLVMBlock <$> tcMemblock l rw off len sh tcPointerAtomic (ExFree _ x ) = Perm_LLVMFree <$> tcKExpr x tcPointerAtomic (ExLlvmFunPtr _ n w f) = tcFunPtrAtomic n w f @@ -564,27 +576,18 @@ tcMemblock l rw off len sh = -- | Check an atomic array permission literal tcArrayAtomic :: - (KnownNat w, 1 <= w) => AstExpr -> AstExpr -> AstExpr -> [ArrayPerm] -> Tc (LLVMArrayPerm w) -tcArrayAtomic off len stride fields = + (KnownNat w, 1 <= w) => Maybe AstExpr -> AstExpr -> AstExpr -> AstExpr -> + AstExpr -> AstExpr -> Tc (LLVMArrayPerm w) +tcArrayAtomic l rw off len stride sh = LLVMArrayPerm - <$> tcKExpr off + <$> tcKExpr rw + <*> tcOptLifetime l + <*> tcKExpr off <*> tcKExpr len <*> (Bytes . fromIntegral <$> tcNatural stride) - <*> traverse tcArrayFieldPerm fields + <*> tcKExpr sh <*> pure [] --- | Check a single field of an array permission -tcArrayFieldPerm :: forall w. (KnownNat w, 1 <= w) => ArrayPerm -> Tc (LLVMArrayField w) -tcArrayFieldPerm (ArrayPerm _ l rw off sz c) = - do llvmFieldLifetime <- tcOptLifetime l - llvmFieldRW <- tcExpr RWModalityRepr rw - llvmFieldOffset <- tcKExpr off :: Tc (PermExpr (BVType w)) - Some (Pair w LeqProof) <- maybe (pure (Some (Pair (knownNat :: NatRepr w) LeqProof))) - tcPositive sz - withKnownNat w do - llvmFieldContents <- withKnownNat w (tcValPerm (LLVMPointerRepr w) c) - pure (LLVMArrayField LLVMFieldPerm{..}) - -- | Check a frame permission literal tcFrameAtomic :: (KnownNat w, 1 <= w) => AstExpr -> Tc (AtomicPerm (LLVMFrameType w)) tcFrameAtomic (ExLlvmFrame _ xs) = diff --git a/heapster-saw/src/Verifier/SAW/Heapster/UntypedAST.hs b/heapster-saw/src/Verifier/SAW/Heapster/UntypedAST.hs index b7d2a7962b..e87b38a845 100644 --- a/heapster-saw/src/Verifier/SAW/Heapster/UntypedAST.hs +++ b/heapster-saw/src/Verifier/SAW/Heapster/UntypedAST.hs @@ -61,7 +61,7 @@ data AstExpr | ExExSh Pos String AstType AstExpr -- ^ existentially quantified shape | ExFieldSh Pos (Maybe AstExpr) AstExpr -- ^ field shape | ExPtrSh Pos (Maybe AstExpr) (Maybe AstExpr) AstExpr -- ^ pointer shape - | ExArraySh Pos AstExpr AstExpr AstExpr -- array shape + | ExArraySh Pos AstExpr AstExpr AstExpr -- ^ array shape | ExEqual Pos AstExpr AstExpr -- ^ equal bitvector proposition | ExNotEqual Pos AstExpr AstExpr -- ^ not-equal bitvector proposition @@ -77,7 +77,7 @@ data AstExpr | ExPtr Pos (Maybe AstExpr) AstExpr AstExpr (Maybe AstExpr) AstExpr -- ^ pointer permission | ExMemblock Pos (Maybe AstExpr) AstExpr AstExpr AstExpr AstExpr -- ^ memblock permission | ExLlvmFunPtr Pos AstExpr AstExpr AstFunPerm -- ^ function pointer permission - | ExArray Pos (Maybe AstExpr) AstExpr AstExpr AstExpr AstExpr AstExpr -- array permission + | ExArray Pos (Maybe AstExpr) AstExpr AstExpr AstExpr AstExpr AstExpr -- ^ array permission deriving Show -- | Returns outermost position From da5b7a08572ccf5bbb4612c81384da0674232010 Mon Sep 17 00:00:00 2001 From: Eddy Westbrook Date: Thu, 23 Sep 2021 07:12:23 -0700 Subject: [PATCH 59/98] whoops, fixed some compilation errors in Widening.hs that were obscured by other files --- heapster-saw/src/Verifier/SAW/Heapster/Widening.hs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/heapster-saw/src/Verifier/SAW/Heapster/Widening.hs b/heapster-saw/src/Verifier/SAW/Heapster/Widening.hs index ed69fe5a24..01d9bd8bd4 100644 --- a/heapster-saw/src/Verifier/SAW/Heapster/Widening.hs +++ b/heapster-saw/src/Verifier/SAW/Heapster/Widening.hs @@ -401,7 +401,7 @@ widenExpr' _ (PExpr_FieldShape (LLVMFieldShape p1)) (PExpr_FieldShape widenExpr' _ (PExpr_ArrayShape len1 stride1 sh1) (PExpr_ArrayShape len2 stride2 sh2) | bvEq len1 len2 && stride1 == stride2 = - PExpr_ArrayShape len1 stride1 <$> widenExpr sh1 sh2 + PExpr_ArrayShape len1 stride1 <$> widenExpr knownRepr sh1 sh2 -- FIXME: there should be some check that the first shapes have the same length, -- though this is more complex if they might have free variables...? @@ -542,14 +542,15 @@ widenAtomicPerms' tp (Perm_LLVMArray ap1 : ps1) ps2 = substEqVars wnmap (llvmArrayRW ap1) == substEqVars wnmap (llvmArrayRW ap2) && substEqVars wnmap (llvmArrayLifetime ap1) - == substEqVars wnmap (llvmArrayLifetime ap2) && + == substEqVars wnmap (llvmArrayLifetime ap2) _ -> False) ps2 of Just i | Perm_LLVMArray ap2 <- ps2!!i -> -- NOTE: at this point, ap1 and ap2 are equal except for perhaps their -- borrows and shapes, so we just filter out the borrows in ap1 that are -- also in ap2 and widen the shapes - widen (llvmArrayCellShape ap1) (llvmArrayCellShape ap2) >>= \sh -> + widenExpr knownRepr (llvmArrayCellShape ap1) (llvmArrayCellShape ap2) + >>= \sh -> (Perm_LLVMArray (ap1 { llvmArrayCellShape = sh, llvmArrayBorrows = filter (flip elem (llvmArrayBorrows ap2)) From f855caeee1e646912bb42346abfb72bdc3b66826 Mon Sep 17 00:00:00 2001 From: Eddy Westbrook Date: Thu, 23 Sep 2021 07:17:36 -0700 Subject: [PATCH 60/98] fixed typo in comment --- heapster-saw/src/Verifier/SAW/Heapster/Permissions.hs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/heapster-saw/src/Verifier/SAW/Heapster/Permissions.hs b/heapster-saw/src/Verifier/SAW/Heapster/Permissions.hs index 342a5995c8..b3b00470d5 100644 --- a/heapster-saw/src/Verifier/SAW/Heapster/Permissions.hs +++ b/heapster-saw/src/Verifier/SAW/Heapster/Permissions.hs @@ -4123,7 +4123,7 @@ llvmArrayPermDivide ap len = filter (not . borrow_in_first) (llvmArrayBorrows ap) }) --- | Create a list of field permissions the cover @N@ bytes: +-- | Create a list of field permissions that cover @N@ bytes: -- -- > ptr((W,0) |-> true, (W,M) |-> true, (W,2*M) |-> true, -- > ..., (W, (i-1)*M, 8*(sz-(i-1)*M)) |-> true) From 6490c7e39881ee2fb4b5321c34d4ac68d560ac71 Mon Sep 17 00:00:00 2001 From: Eddy Westbrook Date: Thu, 23 Sep 2021 07:19:58 -0700 Subject: [PATCH 61/98] removed comments --- heapster-saw/src/Verifier/SAW/Heapster/Implication.hs | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/heapster-saw/src/Verifier/SAW/Heapster/Implication.hs b/heapster-saw/src/Verifier/SAW/Heapster/Implication.hs index 5e7f1fc3bb..7b82d48a04 100644 --- a/heapster-saw/src/Verifier/SAW/Heapster/Implication.hs +++ b/heapster-saw/src/Verifier/SAW/Heapster/Implication.hs @@ -66,17 +66,6 @@ import Verifier.SAW.Heapster.GenMonad import GHC.Stack -{- -FIXME HERE NOW: -- ArrayShape and Perm_LLVMArray: flds -> sh -- llvmArrayFields -> llvmArrayCellShape -- rework LLVMArrayIndex: call number + offset -- matchLLVMArrayField -> matchLLVMArrayIndex -- remove LLVMArrayField -- remove borrows -- replace array rules with array shape rules --} - ---------------------------------------------------------------------- -- * Equality Proofs ---------------------------------------------------------------------- From f3995e289c7fd826c3dfa715e81c0b1d0bf34218 Mon Sep 17 00:00:00 2001 From: Eddy Westbrook Date: Thu, 23 Sep 2021 07:20:35 -0700 Subject: [PATCH 62/98] removed a use of the now outdated LLVMArrayField type --- heapster-saw/src/Verifier/SAW/Heapster/TypedCrucible.hs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/heapster-saw/src/Verifier/SAW/Heapster/TypedCrucible.hs b/heapster-saw/src/Verifier/SAW/Heapster/TypedCrucible.hs index d1b7d19c5b..0f0b006d97 100644 --- a/heapster-saw/src/Verifier/SAW/Heapster/TypedCrucible.hs +++ b/heapster-saw/src/Verifier/SAW/Heapster/TypedCrucible.hs @@ -3280,10 +3280,11 @@ tcEmitLLVMStmt arch ctx loc (LLVM_MemClear _ (ptr :: Reg ctx (LLVMPointerType wp -- For each field perm, prove it and write 0 to it (forM_ @_ @_ @_ @() flds $ \case - LLVMArrayField fp -> + Perm_LLVMField fp -> stmtProvePerm tptr (emptyMb $ ValPerm_Conj1 $ Perm_LLVMField fp) >>> emitTypedLLVMStore arch Nothing loc tptr fp (PExpr_LLVMWord (bvInt 0)) DistPermsNil >>> - stmtRecombinePerms) >>> + stmtRecombinePerms + _ -> error "Unexpected return value from llvmFieldsOfSize") >>> -- Return a fresh unit variable dbgNames >>= \names -> From 29281ef91aae9a83ed18fa102436cfc1c019ddcf Mon Sep 17 00:00:00 2001 From: Eddy Westbrook Date: Thu, 23 Sep 2021 12:00:41 -0700 Subject: [PATCH 63/98] fixed error message --- heapster-saw/src/Verifier/SAW/Heapster/Implication.hs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/heapster-saw/src/Verifier/SAW/Heapster/Implication.hs b/heapster-saw/src/Verifier/SAW/Heapster/Implication.hs index 7b82d48a04..037c8879b1 100644 --- a/heapster-saw/src/Verifier/SAW/Heapster/Implication.hs +++ b/heapster-saw/src/Verifier/SAW/Heapster/Implication.hs @@ -1967,7 +1967,7 @@ simplImplOut (SImpl_LLVMArrayEmpty x ap) = simplImplOut (SImpl_LLVMArrayFromBlock x bp) = case llvmBlockPermToArray1 bp of Just ap -> distPerms1 x $ ValPerm_LLVMArray ap - _ -> error "simplImplOut: SImpl_LLVMArrayOneCell: block perm with non-static length" + _ -> error "simplImplOut: SImpl_LLVMArrayFromBlock: block perm with non-static length" simplImplOut (SImpl_LLVMArrayCellCopy x ap cell) = if atomicPermIsCopyable (Perm_LLVMArray ap) then From 41a10b36a1866addfca5998fc5a7a930e496948c Mon Sep 17 00:00:00 2001 From: Eddy Westbrook Date: Thu, 23 Sep 2021 12:00:56 -0700 Subject: [PATCH 64/98] udpated SAWTranslation.hs to compile with the new approach to array permissions --- .../Verifier/SAW/Heapster/SAWTranslation.hs | 274 +++++++----------- 1 file changed, 106 insertions(+), 168 deletions(-) diff --git a/heapster-saw/src/Verifier/SAW/Heapster/SAWTranslation.hs b/heapster-saw/src/Verifier/SAW/Heapster/SAWTranslation.hs index d0c8546427..15b1e8fade 100644 --- a/heapster-saw/src/Verifier/SAW/Heapster/SAWTranslation.hs +++ b/heapster-saw/src/Verifier/SAW/Heapster/SAWTranslation.hs @@ -840,11 +840,11 @@ instance TransInfo info => [nuMP| PExpr_PtrShape _ _ sh |] -> translate sh [nuMP| PExpr_FieldShape fsh |] -> ETrans_Term <$> tupleOfTypes <$> translate fsh - [nuMP| PExpr_ArrayShape mb_len _ mb_fshs |] -> + [nuMP| PExpr_ArrayShape mb_len _ mb_sh |] -> do let w = natVal4 mb_len let w_term = natOpenTerm w len_term <- translate1 mb_len - elem_tp <- tupleOfTypes <$> concat <$> translate mb_fshs + elem_tp <- translate1 mb_sh return $ ETrans_Term $ applyOpenTermMulti (globalOpenTerm "Prelude.BVVec") [w_term, len_term, elem_tp] @@ -1030,26 +1030,21 @@ bvRangeTransLen :: BVRangeTrans ctx w -> ExprTrans (BVType w) bvRangeTransLen (BVRangeTrans _ _ len) = len -- | The translation of an LLVM array permission is a SAW term of @BVVec@ type, --- along with a type translation for its fields and proof terms stating that all --- of the borrows are in the array. Note that the type translation for the --- fields is always a 'tupleTypeTrans', i.e., has at most one SAW type. +-- along with a type translation for its cell type and proof terms stating that +-- all of the borrows are in the array. Note that the type translation for the +-- cell type is always a 'tupleTypeTrans', i.e., has at most one SAW type. data LLVMArrayPermTrans ctx w = LLVMArrayPermTrans { llvmArrayTransPerm :: Mb ctx (LLVMArrayPerm w), llvmArrayTransLen :: OpenTerm, - llvmArrayTransFields :: TypeTrans [AtomicPermTrans ctx (LLVMPointerType w)], + llvmArrayTransCell :: TypeTrans (AtomicPermTrans ctx (LLVMPointerType w)), -- llvmArrayTransBorrows :: [LLVMArrayBorrowTrans ctx w], llvmArrayTransTerm :: OpenTerm } --- | The translation of an LLVM array index is the translation of the cell --- number plus the field number (which is statically known) -data LLVMArrayIndexTrans ctx w = - LLVMArrayIndexTrans (Mb ctx (PermExpr (BVType w))) OpenTerm Int +-- | Get the SAW type of the cells of the translation of an array permission +llvmArrayTransCellType :: LLVMArrayPermTrans ctx w -> OpenTerm +llvmArrayTransCellType = typeTransType1 . llvmArrayTransCell --- | Get back the 'LLVMArrayIndex' from an 'LLVMArrayIndexTrans' -llvmArrayIndexUnTrans :: LLVMArrayIndexTrans ctx w -> Mb ctx (LLVMArrayIndex w) -llvmArrayIndexUnTrans (LLVMArrayIndexTrans mb_i _ j) = - fmap (flip LLVMArrayIndex j) mb_i -- | The translation of an 'LLVMArrayBorrow' is an element / proof of the -- translation of the the 'BVProp' returned by 'llvmArrayBorrowInArrayBase' @@ -1278,8 +1273,8 @@ instance ExtPermTrans AtomicPermTrans where APTrans_BVProp $ extPermTrans prop_trans instance ExtPermTrans LLVMArrayPermTrans where - extPermTrans (LLVMArrayPermTrans ap len flds {- bs -} t) = - LLVMArrayPermTrans (extMb ap) len (fmap (map extPermTrans) flds) + extPermTrans (LLVMArrayPermTrans ap len sh {- bs -} t) = + LLVMArrayPermTrans (extMb ap) len (fmap extPermTrans sh) {- (map extPermTrans bs) -} t {- @@ -1313,9 +1308,9 @@ offsetLLVMAtomicPermTrans mb_off ptrans offsetLLVMAtomicPermTrans mb_off (APTrans_LLVMField fld ptrans) = Just $ APTrans_LLVMField (mbMap2 offsetLLVMFieldPerm mb_off fld) ptrans offsetLLVMAtomicPermTrans mb_off (APTrans_LLVMArray - (LLVMArrayPermTrans ap len flds {- bs -} t)) = + (LLVMArrayPermTrans ap len sh {- bs -} t)) = Just $ APTrans_LLVMArray $ - LLVMArrayPermTrans (mbMap2 offsetLLVMArrayPerm mb_off ap) len flds {- bs -} t + LLVMArrayPermTrans (mbMap2 offsetLLVMArrayPerm mb_off ap) len sh {- bs -} t offsetLLVMAtomicPermTrans mb_off (APTrans_LLVMBlock mb_bp t) = Just $ APTrans_LLVMBlock (mbMap2 (\off bp -> @@ -1356,11 +1351,6 @@ offsetPermTrans mb_off = case mbMatch mb_off of [nuMP| NoPermOffset |] -> id [nuMP| LLVMPermOffset off |] -> offsetLLVMPermTrans off --- | Get the SAW type of the cells (= lists of fields) of the translation of an --- LLVM array permission -llvmArrayTransCellType :: LLVMArrayPermTrans ctx w -> OpenTerm -llvmArrayTransCellType = typeTransType1 . llvmArrayTransFields - {- -- | Add a borrow to an LLVM array permission translation llvmArrayTransAddBorrow :: LLVMArrayBorrowTrans ctx w -> @@ -1398,100 +1388,42 @@ llvmArrayTransRemBorrow b_trans arr_trans = (llvmArrayTransBorrows arr_trans) } -} --- | Read an array cell (= list of fields) of the translation of an LLVM array --- permission at a given index, given proofs of the propositions that the index --- is in the array as returned by 'llvmArrayIndexInArray'. Note that the first --- proposition should always be that the cell number is <= the array length. +-- | Read an array cell of the translation of an LLVM array permission at a +-- given index, given proofs of the propositions that the index is in the array +-- as returned by 'llvmArrayIndexInArray'. Note that the first proposition +-- should always be that the cell number is <= the array length. getLLVMArrayTransCell :: (1 <= w, KnownNat w) => LLVMArrayPermTrans ctx w -> - LLVMArrayIndexTrans ctx w -> [BVPropTrans ctx w] -> - [AtomicPermTrans ctx (LLVMPointerType w)] -getLLVMArrayTransCell arr_trans ix@(LLVMArrayIndexTrans _ i_trans _) - (BVPropTrans _ in_rng_term:_) = + Mb ctx (PermExpr (BVType w)) -> OpenTerm -> + [BVPropTrans ctx w] -> + AtomicPermTrans ctx (LLVMPointerType w) +getLLVMArrayTransCell arr_trans mb_cell cell_tm (BVPropTrans _ in_rng_pf:_) = let w = fromInteger $ natVal arr_trans in - mapMaybe (offsetLLVMAtomicPermTrans $ - mbMap2 (\ap ix' -> - bvAdd (llvmArrayOffset ap) (llvmArrayIndexByteOffset ap ix')) - (llvmArrayTransPerm arr_trans) (llvmArrayIndexUnTrans ix)) $ - typeTransF (llvmArrayTransFields arr_trans) + fromJust $ + offsetLLVMAtomicPermTrans (mbMap2 llvmArrayCellToAbsOffset + (llvmArrayTransPerm arr_trans) mb_cell) $ + typeTransF (llvmArrayTransCell arr_trans) [applyOpenTermMulti (globalOpenTerm "Prelude.atBVVec") [natOpenTerm w, llvmArrayTransLen arr_trans, llvmArrayTransCellType arr_trans, llvmArrayTransTerm arr_trans, - i_trans, in_rng_term]] -getLLVMArrayTransCell _ _ [] = - error "getLLVMArrayTransCell: first proposition is not a BVProp" + cell_tm, in_rng_pf]] +getLLVMArrayTransCell _ _ _ _ = + error "getLLVMArrayTransCell: malformed arguments" -{- --- | Write an array cell (= list of fields) of the translation of an LLVM array --- permission at a given index, given proofs of the propositions that the index --- is in the array + +-- | Write an array cell of the translation of an LLVM array permission at a +-- given index setLLVMArrayTransCell :: (1 <= w, KnownNat w) => LLVMArrayPermTrans ctx w -> - LLVMArrayIndexTrans ctx w -> [BVPropTrans ctx w] -> - [AtomicPermTrans ctx (LLVMPointerType w)] -> + OpenTerm -> AtomicPermTrans ctx (LLVMPointerType w) -> LLVMArrayPermTrans ctx w -setLLVMArrayTransCell arr_trans (LLVMArrayIndexTrans _ i_trans _) - (BVPropTrans _ in_rng_term:_) cell = +setLLVMArrayTransCell arr_trans cell_tm cell_value = let w = fromInteger $ natVal arr_trans in arr_trans { llvmArrayTransTerm = applyOpenTermMulti (globalOpenTerm "Prelude.updBVVec") [natOpenTerm w, llvmArrayTransLen arr_trans, llvmArrayTransCellType arr_trans, llvmArrayTransTerm arr_trans, - i_trans, in_rng_term, transTupleTerm cell] } --} - --- | Adjust an array cell (= list of fields) of the translation of an LLVM array --- permission at a given index by applying a function to it -adjustLLVMArrayTransCell :: (1 <= w, KnownNat w) => LLVMArrayPermTrans ctx w -> - OpenTerm -> LLVMArrayIndexTrans ctx w -> - LLVMArrayPermTrans ctx w -adjustLLVMArrayTransCell arr_trans f_trm (LLVMArrayIndexTrans _ i_trans _) = - let w = fromInteger $ natVal arr_trans in - arr_trans { - llvmArrayTransTerm = - applyOpenTermMulti (globalOpenTerm "Prelude.adjustBVVec") - [natOpenTerm w, llvmArrayTransLen arr_trans, - llvmArrayTransCellType arr_trans, llvmArrayTransTerm arr_trans, - f_trm, i_trans] } - --- | Read a field (= element of a cell) of the translation of an LLVM array --- permission at a given index, given proofs of the propositions that the index --- is in the array -getLLVMArrayTransField :: (1 <= w, KnownNat w) => LLVMArrayPermTrans ctx w -> - LLVMArrayIndexTrans ctx w -> [BVPropTrans ctx w] -> - AtomicPermTrans ctx (LLVMPointerType w) -getLLVMArrayTransField arr_trans ix_trans@(LLVMArrayIndexTrans - _ _ j) prop_transs = - let cell = getLLVMArrayTransCell arr_trans ix_trans prop_transs in - if j < length cell then cell !! j else - error "getLLVMArrayTransField: index too large" - --- | Write a field (= element of a cell) of the translation of an LLVM array --- permission at a given index -setLLVMArrayTransField :: (1 <= w, KnownNat w) => LLVMArrayPermTrans ctx w -> - LLVMArrayIndexTrans ctx w -> - AtomicPermTrans ctx (LLVMPointerType w) -> - LLVMArrayPermTrans ctx w -setLLVMArrayTransField arr_trans ix_trans fld = - let LLVMArrayIndexTrans _ _ j = ix_trans in - let f_trm = - lambdaTrans "fld" (llvmArrayTransFields arr_trans) - (transTupleTerm . replaceNth j fld) in - adjustLLVMArrayTransCell arr_trans f_trm ix_trans + cell_tm, transTerm1 cell_value] } -{- --- | Write a field (= element of a cell) of the translation of an LLVM array --- permission at a given index, given proofs of the propositions that the index --- is in the array -setLLVMArrayTransField :: (1 <= w, KnownNat w) => LLVMArrayPermTrans ctx w -> - LLVMArrayIndexTrans ctx w -> [BVPropTrans ctx w] -> - AtomicPermTrans ctx (LLVMPointerType w) -> - LLVMArrayPermTrans ctx w -setLLVMArrayTransField arr_trans ix_trans@(LLVMArrayIndexTrans - _ _ j) prop_transs fld' = - let flds = getLLVMArrayTransCell arr_trans ix_trans prop_transs in - setLLVMArrayTransCell arr_trans ix_trans prop_transs - (replaceNth j fld' flds) --} -- | Read a slice (= a sub-array) of the translation of an LLVM array permission -- for the supplied 'BVRange', given the translation of the sub-array permission @@ -1661,11 +1593,6 @@ instance (1 <= w, KnownNat w, TransInfo info) => len_tm <- translate len return $ BVRangeTrans rng off_tm len_tm -instance (1 <= w, KnownNat w, TransInfo info) => - Translate info ctx (LLVMArrayIndex w) (LLVMArrayIndexTrans ctx w) where - translate (mbMatch -> [nuMP| LLVMArrayIndex mb_i mb_j |]) = - LLVMArrayIndexTrans mb_i <$> translate1 mb_i <*> return (mbLift mb_j) - -- [| p :: ValuePerm |] = type of the impl translation of reg with perms p instance TransInfo info => Translate info ctx (ValuePerm a) (TypeTrans (PermTrans ctx a)) where @@ -1769,11 +1696,10 @@ translateLLVMArrayPerm :: (1 <= w, KnownNat w, TransInfo info) => translateLLVMArrayPerm mb_ap = do let w = natVal2 mb_ap let w_term = natOpenTerm w - let mb_len = fmap llvmArrayLen mb_ap - let mb_flds = fmap llvmArrayFields mb_ap - flds_trans <- tupleTypeTrans <$> listTypeTrans <$> translate mb_flds - len_term <- translate1 mb_len - let elem_tp = typeTransType1 flds_trans + sh_trans <- translate $ mbMapCl $(mkClosed [| Perm_LLVMBlock . + llvmArrayPermHead |]) mb_ap + let elem_tp = typeTransType1 sh_trans + len_term <- translate1 $ mbLLVMArrayLen mb_ap {- bs_trans <- listTypeTrans <$> mapM (translateLLVMArrayBorrow ap) (mbList bs) -} @@ -1782,7 +1708,7 @@ translateLLVMArrayPerm mb_ap = [w_term, len_term, elem_tp] return (w_term, len_term, elem_tp, mkTypeTrans1 arr_tp ({- flip $ -} - LLVMArrayPermTrans mb_ap len_term flds_trans) + LLVMArrayPermTrans mb_ap len_term sh_trans) {- <*> bs_trans -} ) instance (1 <= w, KnownNat w, TransInfo info) => @@ -1825,12 +1751,6 @@ instance TransInfo info => (PermTransCtx ctx ps)) where translate = translate . mbDistPermsToValuePerms . fmap unTypeDistPerms -instance (TransInfo info, 1 <= w, KnownNat w) => - Translate info ctx (LLVMArrayField w) (TypeTrans - (AtomicPermTrans ctx - (LLVMPointerType w))) where - translate = translate . fmap llvmArrayFieldToAtomicPerm - -- LOwnedPerms translate to a single tuple type, because lowned permissions -- translate to functions with one argument and one return value @@ -2444,6 +2364,13 @@ translateSimplImpl (ps0 :: Proxy ps0) mb_simpl m = case mbMatch mb_simpl of ptrans']) m + [nuMP| SImpl_DemoteLLVMArrayRW _ _ |] -> + do ttrans <- translateSimplImplOutHead mb_simpl + withPermStackM id + (\(pctx :>: ptrans) -> + pctx :>: typeTransF ttrans (transTerms ptrans)) + m + [nuMP| SImpl_LLVMArrayCopy _ mb_ap mb_sub_ap |] -> do let _w = natVal2 mb_ap sub_ap_tp_trans <- translate mb_sub_ap @@ -2543,7 +2470,7 @@ translateSimplImpl (ps0 :: Proxy ps0) mb_simpl m = case mbMatch mb_simpl of LLVMArrayPermTrans { llvmArrayTransPerm = mb_ap_out , llvmArrayTransLen = bvAddOpenTerm w len1 len2 - , llvmArrayTransFields = llvmArrayTransFields array_trans1 + , llvmArrayTransCell = llvmArrayTransCell array_trans1 , llvmArrayTransTerm = applyOpenTermMulti (globalOpenTerm "Prelude.appendBVVec") [natOpenTerm w, len1, len2, llvmArrayTransTerm array_trans1, @@ -2558,11 +2485,13 @@ translateSimplImpl (ps0 :: Proxy ps0) mb_simpl m = case mbMatch mb_simpl of (\(pctx :>: ptrans) -> pctx :>: typeTransF ttrans [transTerm1 ptrans]) m +{- [nuMP| SImpl_LLVMArrayToField _ _ _ |] -> do ttrans <- translateSimplImplOutHead mb_simpl withPermStackM id (\(pctx :>: _) -> pctx :>: typeTransF ttrans []) m +-} [nuMP| SImpl_LLVMArrayEmpty x mb_ap |] -> do (w_term, _, elem_tp, ap_tp_trans) <- translateLLVMArrayPerm mb_ap @@ -2575,101 +2504,110 @@ translateSimplImpl (ps0 :: Proxy ps0) mb_simpl m = case mbMatch mb_simpl of PTrans_Conj [APTrans_LLVMArray $ typeTransF ap_tp_trans [arr_term]]) m - [nuMP| SImpl_LLVMArrayOneCell _ mb_ap |] -> - do (w_term, len_term, elem_tp, ap_tp_trans) <- translateLLVMArrayPerm mb_ap + [nuMP| SImpl_LLVMArrayFromBlock _ _ |] -> + do mb_ap <- + case mbSimplImplOut mb_simpl of + [nuP| DistPermsCons _ _ (ValPerm_LLVMArray mb_ap) |] -> return mb_ap + _ -> error ("translateSimplImpl: SImpl_LLVMArrayFromBlock: " + ++ "unexpected form of output permission") + (w_term, len_term, elem_tp, ap_tp_trans) <- translateLLVMArrayPerm mb_ap withPermStackM id - (\(pctx :>: ptrans_flds) -> + (\(pctx :>: ptrans_cell) -> let arr_term = - applyOpenTermMulti (globalOpenTerm "Prelude.repeatBVVec") - [w_term, len_term, elem_tp, transTupleTerm ptrans_flds] in + applyOpenTermMulti (globalOpenTerm "Prelude.singletonBVVec") + [w_term, len_term, elem_tp, transTerm1 ptrans_cell] in pctx :>: PTrans_Conj [APTrans_LLVMArray $ typeTransF ap_tp_trans [arr_term]]) m - [nuMP| SImpl_LLVMArrayIndexCopy _ _ mb_ix |] -> + [nuMP| SImpl_LLVMArrayCellCopy _ _ mb_cell |] -> do (_ :>: ptrans_array :>: ptrans_props) <- itiPermStack <$> ask let arr_trans = unPTransLLVMArray - "translateSimplImpl: SImpl_LLVMArrayIndexCopy" ptrans_array + "translateSimplImpl: SImpl_LLVMArrayCellCopy" ptrans_array let prop_transs = unPTransBVProps - "translateSimplImpl: SImpl_LLVMArrayIndexCopy" ptrans_props - ix_trans <- translate mb_ix - let fld_ptrans = getLLVMArrayTransField arr_trans ix_trans prop_transs + "translateSimplImpl: SImpl_LLVMArrayCellCopy" ptrans_props + cell_tm <- translate1 mb_cell + let cell_ptrans = + getLLVMArrayTransCell arr_trans mb_cell cell_tm prop_transs withPermStackM id (\(pctx :>: _ :>: _) -> - pctx :>: PTrans_Conj [fld_ptrans] :>: ptrans_array) + pctx :>: PTrans_Conj [cell_ptrans] :>: ptrans_array) m - [nuMP| SImpl_LLVMArrayIndexBorrow _ mb_ap mb_ix |] -> + [nuMP| SImpl_LLVMArrayCellBorrow _ mb_ap mb_cell |] -> do (_ :>: ptrans_array :>: ptrans_props) <- itiPermStack <$> ask let arr_trans = unPTransLLVMArray - "translateSimplImpl: SImpl_LLVMArrayIndexBorrow" ptrans_array + "translateSimplImpl: SImpl_LLVMArrayCellBorrow" ptrans_array let prop_transs = unPTransBVProps - "translateSimplImpl: SImpl_LLVMArrayIndexBorrow" ptrans_props - ix_trans <- translate mb_ix - let fld_ptrans = getLLVMArrayTransField arr_trans ix_trans prop_transs + "translateSimplImpl: SImpl_LLVMArrayCellBorrow" ptrans_props + cell_tm <- translate1 mb_cell + let cell_ptrans = + getLLVMArrayTransCell arr_trans mb_cell cell_tm prop_transs {- let b = LLVMArrayBorrowTrans (fmap FieldBorrow ix) prop_transs -} let arr_trans' = arr_trans { llvmArrayTransPerm = - mbMap2 (\ap ix -> - llvmArrayAddBorrow (FieldBorrow ix) ap) - mb_ap mb_ix } + mbMap2 (\ap cell -> + llvmArrayAddBorrow (FieldBorrow cell) ap) + mb_ap mb_cell } withPermStackM id (\(pctx :>: _ :>: _) -> - pctx :>: PTrans_Conj [fld_ptrans] :>: + pctx :>: PTrans_Conj [cell_ptrans] :>: PTrans_Conj [APTrans_LLVMArray arr_trans']) m - [nuMP| SImpl_LLVMArrayIndexReturn _ mb_ap mb_ix |] -> - do (_ :>: ptrans_fld :>: ptrans_array) <- itiPermStack <$> ask - let aptrans_fld = case ptrans_fld of - PTrans_Conj [ap] -> ap - _ -> error ("translateSimplImpl: SImpl_LLVMArrayIndexReturn: " + [nuMP| SImpl_LLVMArrayCellReturn _ mb_ap mb_cell |] -> + do (_ :>: ptrans_cell :>: ptrans_array) <- itiPermStack <$> ask + let aptrans_cell = case ptrans_cell of + PTrans_Conj [aptrans] -> aptrans + _ -> error ("translateSimplImpl: SImpl_LLVMArrayCellReturn: " ++ "found non-field perm where field perm was expected") let arr_trans = unPTransLLVMArray - "translateSimplImpl: SImpl_LLVMArrayIndexCopy" ptrans_array - {- let b_trans = llvmArrayTransFindBorrow (fmap FieldBorrow ix) arr_trans -} - ix_trans <- translate mb_ix + "translateSimplImpl: SImpl_LLVMArrayCellCopy" ptrans_array + {- let b_trans = llvmArrayTransFindBorrow (fmap FieldBorrow cell) arr_trans -} + cell_tm <- translate1 mb_cell let arr_trans' = - (setLLVMArrayTransField arr_trans ix_trans - {- (llvmArrayBorrowTransProps b_trans) -} aptrans_fld) + (setLLVMArrayTransCell arr_trans cell_tm + {- (llvmArrayBorrowTransProps b_trans) -} aptrans_cell) { llvmArrayTransPerm = - mbMap2 (\ap ix -> - llvmArrayRemBorrow (FieldBorrow ix) ap) mb_ap mb_ix } + mbMap2 (\ap cell -> + llvmArrayRemBorrow (FieldBorrow cell) ap) mb_ap mb_cell } withPermStackM RL.tail (\(pctx :>: _ :>: _) -> pctx :>: PTrans_Conj [APTrans_LLVMArray arr_trans']) m - [nuMP| SImpl_LLVMArrayContents _ ap flds' impl |] -> + [nuMP| SImpl_LLVMArrayContents _ mb_ap mb_sh impl |] -> do p_out_trans <- translateSimplImplOutHead mb_simpl - (w_term, len_term, elem_tp, _) <- translateLLVMArrayPerm ap - flds_in_trans <- - fmap tupleTypeTrans $ translate $ - fmap (ValPerm_Conj . map llvmArrayFieldToAtomicPerm . llvmArrayFields) ap - flds_out_trans <- - fmap tupleTypeTrans $ translate $ - fmap (ValPerm_Conj . map llvmArrayFieldToAtomicPerm) flds' + (w_term, len_term, elem_tp, _) <- translateLLVMArrayPerm mb_ap + cell_in_trans <- + translate $ mbMapCl $(mkClosed [| ValPerm_LLVMBlock . + llvmArrayPermHead |]) mb_ap + cell_out_trans <- + translate $ mbMap2 (\ap sh -> ValPerm_LLVMBlock $ llvmArrayPermHead $ + ap { llvmArrayCellShape = sh }) + mb_ap mb_sh impl_tm <- -- FIXME: this code just fabricates a pretend LLVM value for the - -- arbitrary field of the array, which seems like a hack + -- arbitrary cell of the array that is used to substitute for the + -- variable bound by the LocalPermImpl, which seems like a hack... inExtTransM ETrans_LLVM $ - translateCurryLocalPermImpl "Error mapping array field permissions:" + translateCurryLocalPermImpl "Error mapping array cell permissions:" (mbCombine RL.typeCtxProxies impl) MNil MNil - (fmap ((MNil :>:) . extPermTrans) flds_in_trans) (MNil :>: Member_Base) - (fmap ((MNil :>:) . extPermTrans) flds_out_trans) + (fmap ((MNil :>:) . extPermTrans) cell_in_trans) (MNil :>: Member_Base) + (fmap ((MNil :>:) . extPermTrans) cell_out_trans) -- Build the computation that maps impl_tm over the input array using the -- mapBVVecM monadic combinator ptrans_arr <- getTopPermM let arr_out_comp_tm = applyOpenTermMulti (globalOpenTerm "Prelude.mapBVVecM") - [elem_tp, typeTransType1 flds_out_trans, impl_tm, + [elem_tp, typeTransType1 cell_out_trans, impl_tm, w_term, len_term, transTerm1 ptrans_arr] -- Now use bindM to bind the result of arr_out_comp_tm in the remaining -- computation @@ -2974,14 +2912,14 @@ translateSimplImpl (ps0 :: Proxy ps0) mb_simpl m = case mbMatch mb_simpl of pctx :>: typeTransF ttrans [transTerm1 ptrans]) m - [nuMP| SImpl_IntroLLVMBlockPtr _ _ _ _ |] -> + [nuMP| SImpl_IntroLLVMBlockPtr _ _ |] -> do ttrans <- translateSimplImplOutHead mb_simpl withPermStackM id (\(pctx :>: ptrans) -> pctx :>: typeTransF ttrans (transTerms ptrans)) m - [nuMP| SImpl_ElimLLVMBlockPtr _ _ _ _ |] -> + [nuMP| SImpl_ElimLLVMBlockPtr _ _ |] -> do ttrans <- translateSimplImplOutHead mb_simpl withPermStackM id (\(pctx :>: ptrans) -> @@ -2995,7 +2933,7 @@ translateSimplImpl (ps0 :: Proxy ps0) mb_simpl m = case mbMatch mb_simpl of pctx :>: typeTransF ttrans [transTupleTerm ptrans]) m - [nuMP| SImpl_ElimLLVMBlockField _ _ _ |] -> + [nuMP| SImpl_ElimLLVMBlockField _ _ |] -> do ttrans <- translateSimplImplOutHead mb_simpl withPermStackM id (\(pctx :>: ptrans) -> From 36ee84727bf72bf6760c56746d1398685567fb49 Mon Sep 17 00:00:00 2001 From: Eddy Westbrook Date: Thu, 23 Sep 2021 12:19:15 -0700 Subject: [PATCH 65/98] changed updBVVec to not require a proof that the index is in the array --- saw-core/prelude/Prelude.sawcore | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/saw-core/prelude/Prelude.sawcore b/saw-core/prelude/Prelude.sawcore index ed8827b56a..916c108cf0 100644 --- a/saw-core/prelude/Prelude.sawcore +++ b/saw-core/prelude/Prelude.sawcore @@ -1695,13 +1695,14 @@ axiom gen_at_BVVec : (n : Nat) -> (len : Vec n Bool) -> (a : sort 0) -> (x : BVVec n len a) -> Eq (BVVec n len a) (genBVVec n len a (atBVVec n len a x)) x; --- Update the value at a specific index in a BVVec +-- Update the value at a specific index in a BVVec if it is in range, otherwise +-- do nothing updBVVec : (n : Nat) -> (len : Vec n Bool) -> (a : sort 0) -> BVVec n len a -> (ix : Vec n Bool) -> - is_bvult n ix len -> a -> BVVec n len a; -updBVVec n len a v ix pf elem = - genBVVec n len a (\ (i:Vec n Bool) (_:is_bvult n i len) -> - ite a (bvEq n i ix) elem (atBVVec n len a v ix pf)); + a -> BVVec n len a; +updBVVec n len a v ix elem = + genBVVec n len a (\ (i:Vec n Bool) (pf:is_bvult n i len) -> + ite a (bvEq n i ix) elem (atBVVec n len a v i pf)); -- Adjust the value at a specific index in a BVVec by applying a function adjustBVVec : (n : Nat) -> (len : Vec n Bool) -> (a : sort 0) -> From f2ce290a686900ac24b3c0be8b10acc0fab0a0e4 Mon Sep 17 00:00:00 2001 From: Eddy Westbrook Date: Thu, 23 Sep 2021 12:19:57 -0700 Subject: [PATCH 66/98] updated IRTTranslation.hs to support the new form of the array permission --- .../Verifier/SAW/Heapster/IRTTranslation.hs | 24 +++++++------------ 1 file changed, 9 insertions(+), 15 deletions(-) diff --git a/heapster-saw/src/Verifier/SAW/Heapster/IRTTranslation.hs b/heapster-saw/src/Verifier/SAW/Heapster/IRTTranslation.hs index 9602a78805..f7b9e6a236 100644 --- a/heapster-saw/src/Verifier/SAW/Heapster/IRTTranslation.hs +++ b/heapster-saw/src/Verifier/SAW/Heapster/IRTTranslation.hs @@ -102,7 +102,7 @@ instance ContainsIRTRecName (PermExpr a) where containsIRTRecName n args containsIRTRecName n (PExpr_PtrShape _ _ sh) = containsIRTRecName n sh containsIRTRecName n (PExpr_FieldShape fsh) = containsIRTRecName n fsh - containsIRTRecName n (PExpr_ArrayShape _ _ fshs) = containsIRTRecName n fshs + containsIRTRecName n (PExpr_ArrayShape _ _ sh) = containsIRTRecName n sh containsIRTRecName n (PExpr_SeqShape sh1 sh2) = containsIRTRecName n sh1 || containsIRTRecName n sh2 containsIRTRecName n (PExpr_OrShape sh1 sh2) = @@ -141,7 +141,7 @@ instance ContainsIRTRecName (RAssign ValuePerm tps) where instance ContainsIRTRecName (AtomicPerm a) where containsIRTRecName n (Perm_LLVMField fp) = containsIRTRecName n fp containsIRTRecName n (Perm_LLVMArray arrp) = - containsIRTRecName n (llvmArrayFields arrp) + containsIRTRecName n (llvmArrayCellShape arrp) containsIRTRecName n (Perm_LLVMBlock bp) = containsIRTRecName n (llvmBlockShape bp) containsIRTRecName _ (Perm_LLVMFree _) = False @@ -160,9 +160,6 @@ instance ContainsIRTRecName (AtomicPerm a) where containsIRTRecName _ (Perm_Fun _) = False containsIRTRecName _ (Perm_BVProp _) = False -instance ContainsIRTRecName (LLVMArrayField w) where - containsIRTRecName n (LLVMArrayField fp) = containsIRTRecName n fp - instance ContainsIRTRecName (LLVMFieldPerm w sz) where containsIRTRecName n fp = containsIRTRecName n $ llvmFieldContents fp @@ -401,8 +398,7 @@ instance IRTTyVars (AtomicPerm a) where [nuMP| Perm_LLVMField fld |] -> irtTyVars (fmap llvmFieldContents fld) [nuMP| Perm_LLVMArray mb_ap |] -> - irtTyVars $ fmap (fmap llvmArrayFieldToAtomicPerm . llvmArrayFields) - mb_ap + irtTyVars $ mbLLVMArrayCellShape mb_ap [nuMP| Perm_LLVMBlock bp |] -> irtTyVars (fmap llvmBlockShape bp) [nuMP| Perm_LLVMFree _ |] -> return ([], IRTVarsNil) @@ -461,7 +457,7 @@ instance IRTTyVars (PermExpr (LLVMShapeType w)) where [nuMP| PExpr_EqShape _ |] -> return ([], IRTVarsNil) [nuMP| PExpr_PtrShape _ _ sh |] -> irtTyVars sh [nuMP| PExpr_FieldShape fsh |] -> irtTyVars fsh - [nuMP| PExpr_ArrayShape _ _ fshs |] -> irtTyVars fshs + [nuMP| PExpr_ArrayShape _ _ sh |] -> irtTyVars sh [nuMP| PExpr_SeqShape sh1 sh2 |] -> do (tps1, ixs1) <- irtTyVars sh1 (tps2, ixs2) <- irtTyVars sh2 @@ -648,10 +644,8 @@ instance IRTDescs (AtomicPerm a) where do let w = natVal2 mb_ap w_term = natOpenTerm w len_term <- translate1 (fmap llvmArrayLen mb_ap) - let mb_flds = fmap (fmap llvmArrayFieldToAtomicPerm . llvmArrayFields) - mb_ap - xs_term <- irtDesc mb_flds ixs - irtCtor "Prelude.IRT_BVVec" [w_term, len_term, xs_term] + sh_desc_term <- irtDesc (mbLLVMArrayCellShape mb_ap) ixs + irtCtor "Prelude.IRT_BVVec" [w_term, len_term, sh_desc_term] ([nuMP| Perm_LLVMBlock bp |], _) -> irtDescs (fmap llvmBlockShape bp) ixs ([nuMP| Perm_LLVMFree _ |], _) -> return [] @@ -692,12 +686,12 @@ instance IRTDescs (PermExpr (LLVMShapeType w)) where irtDescs sh ixs ([nuMP| PExpr_FieldShape fsh |], _) -> irtDescs fsh ixs - ([nuMP| PExpr_ArrayShape mb_len _ mb_fshs |], _) -> + ([nuMP| PExpr_ArrayShape mb_len _ mb_sh |], _) -> do let w = natVal4 mb_len w_term = natOpenTerm w len_term <- translate1 mb_len - xs_term <- irtDesc mb_fshs ixs - irtCtor "Prelude.IRT_BVVec" [w_term, len_term, xs_term] + sh_desc_term <- irtDesc mb_sh ixs + irtCtor "Prelude.IRT_BVVec" [w_term, len_term, sh_desc_term] ([nuMP| PExpr_SeqShape sh1 sh2 |], IRTVarsAppend ixs1 ixs2) -> do x1 <- irtDesc sh1 ixs1 x2 <- irtDesc sh2 ixs2 From 0460dce57afcbe2db26a1f4620d44bb2ff1b9d49 Mon Sep 17 00:00:00 2001 From: Eddy Westbrook Date: Thu, 23 Sep 2021 12:20:14 -0700 Subject: [PATCH 67/98] updated the arrays.saw example to use the new form of array permission --- heapster-saw/examples/arrays.saw | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/heapster-saw/examples/arrays.saw b/heapster-saw/examples/arrays.saw index 1a12837847..d5543838cd 100644 --- a/heapster-saw/examples/arrays.saw +++ b/heapster-saw/examples/arrays.saw @@ -4,7 +4,7 @@ env <- heapster_init_env_from_file "arrays.sawcore" "arrays.bc"; heapster_define_perm env "int64" " " "llvmptr 64" "exists x:bv 64.eq(llvmword(x))"; heapster_define_perm env "int8" " " "llvmptr 8" "exists x:bv 8.eq(llvmword(x))"; -heapster_define_perm env "int64array" "len:bv 64" "llvmptr 64" "array(0, int64<>])"; +heapster_define_perm env "int64array" "len:bv 64" "llvmptr 64" "array(W,0,))"; heapster_typecheck_fun env "contains0_rec_" "(len:bv 64).arg0:eq(llvmword(len)), arg1:int64array, arg2:int64<> -o arg0:true, arg1:int64array, arg2:true, ret:int64<>"; @@ -23,6 +23,6 @@ heapster_typecheck_fun env "zero_array_from" "(len:bv 64, off:bv 64).arg0:int64a heapster_join_point_hint env "filter_and_sum_pos" []; heapster_typecheck_fun env "filter_and_sum_pos" "(len:bv 64).arg0:int64array, arg1:eq(llvmword(len)) -o arg0:int64array, arg1:true, ret:int64<>"; -heapster_typecheck_fun env "sum_2d" "(l1:bv 64,l2:bv 64).arg0:array(0, array(0, exists z:bv 64.eq(llvmword(z))])]), arg1:eq(llvmword(l1)), arg2:eq(llvmword(l2)) -o arg0:array(0, array(0, exists z:bv 64.eq(llvmword(z))])]), arg1:true, arg2:true, ret:int64<>"; +heapster_typecheck_fun env "sum_2d" "(l1:bv 64,l2:bv 64).arg0:array(W,0,))), arg1:eq(llvmword(l1)), arg2:eq(llvmword(l2)) -o arg0:arraysh(l2,*8,fieldsh(int64<>)), arg1:true, arg2:true, ret:int64<>"; heapster_export_coq env "arrays_gen.v"; From 81c5977f69d509ec90e848a5bc0051ec56a13608 Mon Sep 17 00:00:00 2001 From: Eddy Westbrook Date: Thu, 23 Sep 2021 15:42:43 -0700 Subject: [PATCH 68/98] whoops, fixed a bug in proveVarLLVMField; also added some extra debugging information --- .../src/Verifier/SAW/Heapster/Implication.hs | 16 +++++++++------- .../src/Verifier/SAW/Heapster/Permissions.hs | 5 +++++ 2 files changed, 14 insertions(+), 7 deletions(-) diff --git a/heapster-saw/src/Verifier/SAW/Heapster/Implication.hs b/heapster-saw/src/Verifier/SAW/Heapster/Implication.hs index 037c8879b1..57e909e728 100644 --- a/heapster-saw/src/Verifier/SAW/Heapster/Implication.hs +++ b/heapster-saw/src/Verifier/SAW/Heapster/Implication.hs @@ -3461,7 +3461,8 @@ implProveEqPerms (DistPermsCons ps' x p@(ValPerm_Eq _)) = implProveEqPerms _ = error "implProveEqPerms: non-equality permission" -- | Cast a proof of @x:p@ to one of @x:p'@ using a proof that @p=p'@ -implCastPermM :: NuMatchingAny1 r => ExprVar a -> SomeEqProof (ValuePerm a) -> +implCastPermM :: HasCallStack => NuMatchingAny1 r => ExprVar a -> + SomeEqProof (ValuePerm a) -> ImplM vars s r (ps :> a) (ps :> a) () implCastPermM x some_eqp | UnSomeEqProof eqp <- unSomeEqProof some_eqp = @@ -3469,7 +3470,7 @@ implCastPermM x some_eqp implSimplM Proxy (SImpl_CastPerm x eqp) -- | Cast a permission somewhere in the stack using an equality proof -implCastStackElemM :: NuMatchingAny1 r => Member ps a -> +implCastStackElemM :: HasCallStack => NuMatchingAny1 r => Member ps a -> SomeEqProof (ValuePerm a) -> ImplM vars s r ps ps () implCastStackElemM memb some_eqp = getDistPerms >>>= \all_perms -> @@ -3480,7 +3481,8 @@ implCastStackElemM memb some_eqp = implMoveDownM ps0 (ps1 :>: px) x MNil -- | Cast all of the permissions on the stack using 'implCastPermM' -implCastStackM :: NuMatchingAny1 r => SomeEqProof (ValuePerms ps) -> +implCastStackM :: HasCallStack => NuMatchingAny1 r => + SomeEqProof (ValuePerms ps) -> ImplM vars s r ps ps () implCastStackM some_eqp = getDistPerms >>>= \perms -> @@ -4974,8 +4976,8 @@ proveVarLLVMFieldH x (Perm_LLVMField fp) off mb_fp let fp' = fp { llvmFieldContents = ValPerm_Eq (PExpr_Var y) } in -- Step 2: prove the contents - proveVarImplInt y (fmap llvmFieldContents mb_fp) >>> - partialSubstForceM (fmap llvmFieldContents mb_fp) + proveVarImplInt y (mbLLVMFieldContents mb_fp) >>> + partialSubstForceM (mbLLVMFieldContents mb_fp) "proveVarLLVMFieldFromField" >>>= \p_y -> let fp'' = fp' { llvmFieldContents = p_y } in introLLVMFieldContentsM x y fp'' >>> @@ -4992,7 +4994,7 @@ proveVarLLVMFieldH x (Perm_LLVMField fp) off mb_fp let (f, args) = fieldToLTFunc fp'' in proveVarLifetimeFunctor x f args (llvmFieldLifetime fp'') (fmap llvmFieldLifetime mb_fp) >>>= \l -> - let fp''' = fp { llvmFieldLifetime = l } in + let fp''' = fp'' { llvmFieldLifetime = l } in -- Step 4: equalize the read/write modalities. This is done after changing -- the lifetime so that the original modality is recovered after any borrow @@ -6242,7 +6244,7 @@ proveVarAtomicImplUnfoldOrFail x ps mb_ap = proveVarImplUnfoldLeft x p_l mb_p_r (Just i) -- Otherwise, we fail - _ -> implFailVarM "proveVarAtomicImpl" x p_l mb_p_r + _ -> implFailVarM "proveVarAtomicImplUnfoldOrFail" x p_l mb_p_r -- | Prove @x:(p1 * ... * pn) |- x:p@ for some atomic permission @p@, assuming diff --git a/heapster-saw/src/Verifier/SAW/Heapster/Permissions.hs b/heapster-saw/src/Verifier/SAW/Heapster/Permissions.hs index b3b00470d5..a1af0c4375 100644 --- a/heapster-saw/src/Verifier/SAW/Heapster/Permissions.hs +++ b/heapster-saw/src/Verifier/SAW/Heapster/Permissions.hs @@ -1681,6 +1681,11 @@ mbLLVMFieldRW = mbMapCl $(mkClosed [| llvmFieldRW |]) mbLLVMFieldOffset :: Mb ctx (LLVMFieldPerm w sz) -> Mb ctx (PermExpr (BVType w)) mbLLVMFieldOffset = mbMapCl $(mkClosed [| llvmFieldOffset |]) +-- | Get the contents-in-binding of a field permission in binding +mbLLVMFieldContents :: Mb ctx (LLVMFieldPerm w sz) -> + Mb ctx (ValuePerm (LLVMPointerType sz)) +mbLLVMFieldContents = mbMapCl $(mkClosed [| llvmFieldContents |]) + -- | Helper type to represent byte offsets -- From dd65f94fbf2b9f6106aeaed6e9cff0cb191a2805 Mon Sep 17 00:00:00 2001 From: Eddy Westbrook Date: Thu, 23 Sep 2021 17:38:29 -0700 Subject: [PATCH 69/98] incorporated unfolding into implGetLLVMPermForOffset; fixed llvmPermIndicesForOffset, which was implemented incorrectly; added some debugging info --- .../src/Verifier/SAW/Heapster/Implication.hs | 125 +++++++++++------- .../src/Verifier/SAW/Heapster/Permissions.hs | 8 +- 2 files changed, 83 insertions(+), 50 deletions(-) diff --git a/heapster-saw/src/Verifier/SAW/Heapster/Implication.hs b/heapster-saw/src/Verifier/SAW/Heapster/Implication.hs index 57e909e728..92845760e6 100644 --- a/heapster-saw/src/Verifier/SAW/Heapster/Implication.hs +++ b/heapster-saw/src/Verifier/SAW/Heapster/Implication.hs @@ -4225,7 +4225,15 @@ implGetLLVMPermForOffset :: implGetLLVMPermForOffset x ps imprecise_p elim_blocks_p off mb_p = case llvmPermIndicesForOffset ps imprecise_p off of - [] -> implFailVarM "implGetLLVMPermForOffset" x (ValPerm_Conj ps) mb_p + -- If we didn't find any matches, try to unfold on the left + [] -> + implUnfoldOrFail x ps mb_p >>>= \_ -> + elimOrsExistsNamesM x >>>= \p'' -> + (case p'' of + ValPerm_Conj ps' -> + implGetLLVMPermForOffset x ps' imprecise_p elim_blocks_p off mb_p + -- FIXME: handle eq perms here + _ -> implFailVarM "implGetLLVMPermForOffset" x (ValPerm_Conj ps) mb_p) ixs -> foldr1 implCatchM $ flip map ixs $ \i -> implGetConjM x ps i >>>= \ps' -> recombinePerm x (ValPerm_Conj ps') >>> @@ -4953,6 +4961,12 @@ proveVarLLVMField :: ImplM vars s r (ps :> LLVMPointerType w) (ps :> LLVMPointerType w) () proveVarLLVMField x ps off mb_fp = + implTraceM (\i -> + pretty "proveVarLLVMField:" <+> permPretty i x <> colon <> + align (sep [PP.group (permPretty i (ValPerm_Conj ps)), + pretty "-o", + PP.group (permPretty i mb_fp + <+> pretty "@" <+> permPretty i off)])) >>> implGetLLVMPermForOffset x ps True True off (mbValPerm_LLVMField mb_fp) >>>= \p -> proveVarLLVMFieldH x p off mb_fp @@ -4978,7 +4992,7 @@ proveVarLLVMFieldH x (Perm_LLVMField fp) off mb_fp -- Step 2: prove the contents proveVarImplInt y (mbLLVMFieldContents mb_fp) >>> partialSubstForceM (mbLLVMFieldContents mb_fp) - "proveVarLLVMFieldFromField" >>>= \p_y -> + "proveVarLLVMFieldH" >>>= \p_y -> let fp'' = fp' { llvmFieldContents = p_y } in introLLVMFieldContentsM x y fp'' >>> @@ -5030,7 +5044,7 @@ proveVarLLVMFieldH x (Perm_LLVMArray ap) off mb_fp -- If none of the above cases match, then fail proveVarLLVMFieldH x p _ mb_fp = - implFailVarM "proveVarLLVMField" x (ValPerm_Conj1 p) + implFailVarM "proveVarLLVMFieldH" x (ValPerm_Conj1 p) (mbValPerm_LLVMField mb_fp) @@ -6162,39 +6176,74 @@ proveVarLLVMBlocks2 x ps _ mb_bp _ mb_bps = -- * Proving and Eliminating Recursive Permissions ---------------------------------------------------------------------- --- | Prove @x:p1 |- x:p2@ by unfolding a foldable named permission in @p1@ and --- then recursively proving @x:p2@ from the resulting permissions. If an 'Int' --- @i@ is supplied, then @p1@ is a conjunctive permission whose @i@th conjunct --- is the named permisison to be unfolded; otherwise @p1@ itself is the named --- permission to be unfolded. Assume that @x:p1@ is on top of the stack. -proveVarImplUnfoldLeft :: NuMatchingAny1 r => ExprVar a -> ValuePerm a -> - Mb vars (ValuePerm a) -> - Maybe Int -> ImplM vars s r (ps :> a) (ps :> a) () - -proveVarImplUnfoldLeft x (ValPerm_Named npn args off) mb_p Nothing +-- | Assuming @x:p1@ is on top of the stack, unfold a foldable named permission +-- in @p1@. If an 'Int' @i@ is supplied, then @p1@ is a conjunctive permission +-- whose @i@th conjunct is the named permisison to be unfolded; otherwise @p1@ +-- itself is the named permission to be unfolded. Leave the resulting unfolded +-- permission on top of the stack, recombining any additional permissions (in +-- the former case, where a single conjunct is unfolded) back into the primary +-- permissions of @x@, and return that unfolded permission. +implUnfoldLeft :: NuMatchingAny1 r => ExprVar a -> ValuePerm a -> + Maybe Int -> ImplM vars s r (ps :> a) (ps :> a) (ValuePerm a) +implUnfoldLeft x (ValPerm_Named npn args off) Nothing | TrueRepr <- nameCanFoldRepr npn = (case namedPermNameSort npn of RecursiveSortRepr _ _ -> implSetRecRecurseLeftM _ -> pure ()) >>> implUnfoldNamedM x npn args off >>>= \p' -> - implPopM x p' >>> - proveVarImplInt x mb_p - -proveVarImplUnfoldLeft x (ValPerm_Conj ps) mb_p (Just i) + return p' +implUnfoldLeft x (ValPerm_Conj ps) (Just i) | i < length ps , Perm_NamedConj npn args off <- ps!!i , TrueRepr <- nameCanFoldRepr npn = (case namedPermNameSort npn of RecursiveSortRepr _ _ -> implSetRecRecurseLeftM _ -> pure ()) >>> - implExtractConjM x ps i >>> implPopM x (ValPerm_Conj $ deleteNth i ps) >>> + implExtractConjM x ps i >>> + recombinePerm x (ValPerm_Conj $ deleteNth i ps) >>> implNamedFromConjM x npn args off >>> implUnfoldNamedM x npn args off >>>= \p' -> - recombinePerm x p' >>> - proveVarImplInt x mb_p + return p' +implUnfoldLeft _ _ _ = error ("implUnfoldLeft: malformed inputs") + + +-- | Assume that @x:(p1 * ... * pn)@ is on top of the stack, and try to find +-- some @pi@ that can be unfolded. If successful, recombine the remaining @pj@ +-- to the primary permission for @x@, unfold @pi@, leave it on top of the stack, +-- and return its unfolded permission. Otherwise fail using 'implFailVarM', +-- citing the supplied permission in binding as the one we were trying to prove. +implUnfoldOrFail :: NuMatchingAny1 r => ExprVar a -> [AtomicPerm a] -> + Mb vars (ValuePerm a) -> + ImplM vars s r (ps :> a) (ps :> a) (ValuePerm a) +implUnfoldOrFail x ps mb_p = + let p_l = ValPerm_Conj ps in + use implStateRecRecurseFlag >>= \flag -> + case () of + -- We can always unfold a defined name on the left + _ | Just i <- findIndex isDefinedConjPerm ps -> + implUnfoldLeft x p_l (Just i) -proveVarImplUnfoldLeft _ _ _ _ = - error ("proveVarImplUnfoldLeft: malformed inputs") + -- If flag allows it, we can unfold a recursive name on the left + _ | Just i <- findIndex isRecursiveConjPerm ps + , flag /= RecRight -> + implUnfoldLeft x p_l (Just i) + + -- Otherwise, we fail + _ -> implFailVarM "implUnfoldOrFail" x p_l mb_p + + +-- | Prove @x:p1 |- x:p2@ by unfolding a foldable named permission in @p1@ and +-- then recursively proving @x:p2@ from the resulting permissions. If an 'Int' +-- @i@ is supplied, then @p1@ is a conjunctive permission whose @i@th conjunct +-- is the named permisison to be unfolded; otherwise @p1@ itself is the named +-- permission to be unfolded. Assume that @x:p1@ is on top of the stack. +proveVarImplUnfoldLeft :: NuMatchingAny1 r => ExprVar a -> ValuePerm a -> + Mb vars (ValuePerm a) -> + Maybe Int -> ImplM vars s r (ps :> a) (ps :> a) () + +proveVarImplUnfoldLeft x p mb_p maybe_i = + implUnfoldLeft x p maybe_i >>>= \p' -> recombinePerm x p' >>> + proveVarImplInt x mb_p -- | Prove @x:p1 |- x:P\@off@ where @P@ is foldable by first proving the @@ -6230,21 +6279,9 @@ proveVarAtomicImplUnfoldOrFail :: NuMatchingAny1 r => ExprVar a -> [AtomicPerm a] -> Mb vars (AtomicPerm a) -> ImplM vars s r (ps :> a) (ps :> a) () proveVarAtomicImplUnfoldOrFail x ps mb_ap = - do let p_l = ValPerm_Conj ps - mb_p_r = fmap ValPerm_Conj1 mb_ap - flag <- use implStateRecRecurseFlag - case () of - -- We can always unfold a defined name on the left - _ | Just i <- findIndex isDefinedConjPerm ps -> - proveVarImplUnfoldLeft x p_l mb_p_r (Just i) - - -- If flag allows it, we can unfold a recursive name on the left - _ | Just i <- findIndex isRecursiveConjPerm ps - , flag /= RecRight -> - proveVarImplUnfoldLeft x p_l mb_p_r (Just i) - - -- Otherwise, we fail - _ -> implFailVarM "proveVarAtomicImplUnfoldOrFail" x p_l mb_p_r + let mb_p = mbValPerm_Conj1 mb_ap in + implUnfoldOrFail x ps mb_p >>>= \p' -> recombinePerm x p' >>> + proveVarImplInt x mb_p -- | Prove @x:(p1 * ... * pn) |- x:p@ for some atomic permission @p@, assuming @@ -6261,17 +6298,9 @@ proveVarAtomicImpl x ps mb_p = case mbMatch mb_p of [nuMP| Perm_LLVMField mb_fp |] -> partialSubstForceM (mbLLVMFieldOffset mb_fp) "proveVarPtrPerms" >>>= \off -> - implCatchM - (proveVarLLVMField x ps off mb_fp) - (proveVarAtomicImplUnfoldOrFail x ps mb_p) - - [nuMP| Perm_LLVMArray mb_ap |] -> - implCatchM - (proveVarLLVMArray x True ps mb_ap) - (proveVarAtomicImplUnfoldOrFail x ps mb_p) - - [nuMP| Perm_LLVMBlock mb_bp |] -> - proveVarLLVMBlock x ps mb_bp + proveVarLLVMField x ps off mb_fp + [nuMP| Perm_LLVMArray mb_ap |] -> proveVarLLVMArray x True ps mb_ap + [nuMP| Perm_LLVMBlock mb_bp |] -> proveVarLLVMBlock x ps mb_bp [nuMP| Perm_LLVMFree mb_e |] -> partialSubstForceM mb_e "proveVarAtomicImpl" >>>= \e -> diff --git a/heapster-saw/src/Verifier/SAW/Heapster/Permissions.hs b/heapster-saw/src/Verifier/SAW/Heapster/Permissions.hs index a1af0c4375..4b4f7c470c 100644 --- a/heapster-saw/src/Verifier/SAW/Heapster/Permissions.hs +++ b/heapster-saw/src/Verifier/SAW/Heapster/Permissions.hs @@ -1512,6 +1512,10 @@ pattern ValPerm_True = ValPerm_Conj [] pattern ValPerm_Conj1 :: AtomicPerm a -> ValuePerm a pattern ValPerm_Conj1 p = ValPerm_Conj [p] +-- | The conjunction of exactly 1 atomic permission in a binding +mbValPerm_Conj1 :: Mb ctx (AtomicPerm a) -> Mb ctx (ValuePerm a) +mbValPerm_Conj1 = mbMapCl $(mkClosed [| ValPerm_Conj1 |]) + -- | The conjunction of exactly 1 field permission pattern ValPerm_LLVMField :: () => (a ~ LLVMPointerType w, 1 <= w, KnownNat w, 1 <= sz, KnownNat sz) => @@ -4064,8 +4068,8 @@ llvmPermIndicesForOffset :: (1 <= w, KnownNat w) => PermExpr (BVType w) -> [Int] llvmPermIndicesForOffset ps imprecise_p off = let ixs_props = findMaybeIndices (llvmPermContainsOffset off) ps in - case findIndex (\(_,(_,holds)) -> holds) ixs_props of - Just i -> [i] + case find (\(_,(_,holds)) -> holds) ixs_props of + Just (i,_) -> [i] Nothing | imprecise_p -> map fst ixs_props Nothing -> [] From 8bd37597060ce6408fe41e3193ee7bf69a4fd0fd Mon Sep 17 00:00:00 2001 From: Eddy Westbrook Date: Fri, 24 Sep 2021 06:30:26 -0700 Subject: [PATCH 70/98] whoops, should not have commented out the cases for eliminating blocks with field or array shape --- .../src/Verifier/SAW/Heapster/Implication.hs | 19 +++++++------------ 1 file changed, 7 insertions(+), 12 deletions(-) diff --git a/heapster-saw/src/Verifier/SAW/Heapster/Implication.hs b/heapster-saw/src/Verifier/SAW/Heapster/Implication.hs index 92845760e6..0585f159de 100644 --- a/heapster-saw/src/Verifier/SAW/Heapster/Implication.hs +++ b/heapster-saw/src/Verifier/SAW/Heapster/Implication.hs @@ -4069,22 +4069,17 @@ implElimLLVMBlock x bp@(LLVMBlockPerm { llvmBlockShape = PExpr_PtrShape _ _ _ }) implSimplM Proxy (SImpl_ElimLLVMBlockPtr x bp) -- For a field shape, eliminate to a field permission -{- -implElimLLVMBlock x (LLVMBlockPerm { llvmBlockShape = - PExpr_FieldShape (LLVMFieldShape p) - , ..}) = - implSimplM Proxy (SImpl_ElimLLVMBlockField x - (LLVMFieldPerm { llvmFieldRW = llvmBlockRW, - llvmFieldLifetime = llvmBlockLifetime, - llvmFieldOffset = llvmBlockOffset, - llvmFieldContents = p }) - llvmBlockLen) +implElimLLVMBlock x bp@(LLVMBlockPerm + { llvmBlockShape = + PExpr_FieldShape (LLVMFieldShape p) }) = + implSimplM Proxy (SImpl_ElimLLVMBlockField x $ fromJust $ + llvmBlockPermToField (exprLLVMTypeWidth p) bp) -- For an array shape, eliminate to an array permission implElimLLVMBlock x bp@(LLVMBlockPerm { llvmBlockShape = PExpr_ArrayShape _ _ _ }) = - implSimplM Proxy (SImpl_ElimLLVMBlockArray x $ llvmArrayBlockToArrayPerm bp) --} + implSimplM Proxy (SImpl_ElimLLVMBlockArray x $ fromJust $ + llvmBlockPermToArray bp) -- Special case: for shape sh1;emptysh where the natural length of sh1 is the -- same as the length of the block permission, eliminate the emptysh, converting From 14f576f8482979bce2f950a71ed6a1c28f4ea3e2 Mon Sep 17 00:00:00 2001 From: Eddy Westbrook Date: Fri, 24 Sep 2021 06:36:44 -0700 Subject: [PATCH 71/98] changed typeTransF to a helper function that prints more debug info on error --- heapster-saw/src/Verifier/SAW/Heapster/SAWTranslation.hs | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/heapster-saw/src/Verifier/SAW/Heapster/SAWTranslation.hs b/heapster-saw/src/Verifier/SAW/Heapster/SAWTranslation.hs index 15b1e8fade..6642e03a38 100644 --- a/heapster-saw/src/Verifier/SAW/Heapster/SAWTranslation.hs +++ b/heapster-saw/src/Verifier/SAW/Heapster/SAWTranslation.hs @@ -106,7 +106,14 @@ nlPrettyCallStack = ("\n" ++) . prettyCallStack -- construct in Haskell. data TypeTrans tr = TypeTrans { typeTransTypes :: [OpenTerm], - typeTransF :: [OpenTerm] -> tr } + typeTransFun :: [OpenTerm] -> tr } + +-- | Apply the 'typeTransFun' of a 'TypeTrans' with the call stack +typeTransF :: HasCallStack => TypeTrans tr -> [OpenTerm] -> tr +typeTransF (TypeTrans tps f) ts | length tps == length ts = f ts +typeTransF (TypeTrans tps _) ts = + error ("Type translation expected " ++ show (length tps) ++ + " arguments, but got " ++ show (length ts)) instance Functor TypeTrans where fmap f (TypeTrans ts tp_f) = TypeTrans ts (f . tp_f) From 8215901364e9673bb940b382d36c2d7bb3c081a3 Mon Sep 17 00:00:00 2001 From: Eddy Westbrook Date: Fri, 24 Sep 2021 06:44:04 -0700 Subject: [PATCH 72/98] whoops, fixed the translation of SImpl_ElimLLVMBlockField --- heapster-saw/src/Verifier/SAW/Heapster/SAWTranslation.hs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/heapster-saw/src/Verifier/SAW/Heapster/SAWTranslation.hs b/heapster-saw/src/Verifier/SAW/Heapster/SAWTranslation.hs index 6642e03a38..6d9a7bf6c9 100644 --- a/heapster-saw/src/Verifier/SAW/Heapster/SAWTranslation.hs +++ b/heapster-saw/src/Verifier/SAW/Heapster/SAWTranslation.hs @@ -2944,7 +2944,7 @@ translateSimplImpl (ps0 :: Proxy ps0) mb_simpl m = case mbMatch mb_simpl of do ttrans <- translateSimplImplOutHead mb_simpl withPermStackM id (\(pctx :>: ptrans) -> - pctx :>: typeTransF ttrans [transTerm1 ptrans]) + pctx :>: typeTransF (tupleTypeTrans ttrans) [transTerm1 ptrans]) m [nuMP| SImpl_IntroLLVMBlockArray _ _ |] -> From 33b2997206e71816aecfcc99b59207db50c29499 Mon Sep 17 00:00:00 2001 From: Eddy Westbrook Date: Fri, 24 Sep 2021 06:46:29 -0700 Subject: [PATCH 73/98] updated the linked_list example to use the new array permission --- heapster-saw/examples/linked_list.saw | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/heapster-saw/examples/linked_list.saw b/heapster-saw/examples/linked_list.saw index 24460e8247..9f7390c5cb 100644 --- a/heapster-saw/examples/linked_list.saw +++ b/heapster-saw/examples/linked_list.saw @@ -6,7 +6,7 @@ heapster_define_recursive_perm env "List" "X:perm(llvmptr 64), l:lifetime, rw:rw heapster_typecheck_fun env "is_elem" "(x:bv 64).arg0:eq(llvmword(x)), arg1:List<(exists y:(bv 64).eq(llvmword(y))),always,R> -o arg0:true, arg1:true, ret:exists z:(bv 64).eq(llvmword(z))"; -heapster_assume_fun env "malloc" "(sz:bv 64).arg0:eq(llvmword(8*sz)) -o arg0:true, ret:array(0, true])" "mallocSpec"; +heapster_assume_fun env "malloc" "(sz:bv 64).arg0:eq(llvmword(8*sz)) -o arg0:true, ret:array(W,0, -o arg0:true, arg1:true, ret:exists x:(bv 64).eq(llvmword(x))"; From a19d3e7078ceb281e874faa8de595ba1858d942d Mon Sep 17 00:00:00 2001 From: Eddy Westbrook Date: Fri, 24 Sep 2021 06:53:04 -0700 Subject: [PATCH 74/98] whoops, used the wrong variant of implGetConjM in one of the proveVarLLVMBlocks1 cases; also added more debug info to some of the lower-level implication prover combinators --- heapster-saw/src/Verifier/SAW/Heapster/Implication.hs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/heapster-saw/src/Verifier/SAW/Heapster/Implication.hs b/heapster-saw/src/Verifier/SAW/Heapster/Implication.hs index 0585f159de..782d88cb2e 100644 --- a/heapster-saw/src/Verifier/SAW/Heapster/Implication.hs +++ b/heapster-saw/src/Verifier/SAW/Heapster/Implication.hs @@ -3261,23 +3261,23 @@ implTryProveBVProps x (prop:props) = implInsertConjM x (Perm_BVProp prop) (map Perm_BVProp props) 0 -- | Drop a permission from the top of the stack -implDropM :: NuMatchingAny1 r => ExprVar a -> ValuePerm a -> +implDropM :: HasCallStack => NuMatchingAny1 r => ExprVar a -> ValuePerm a -> ImplM vars s r ps (ps :> a) () implDropM x p = implSimplM Proxy (SImpl_Drop x p) -- | Copy a permission on the top of the stack, assuming it is copyable -implCopyM :: NuMatchingAny1 r => ExprVar a -> ValuePerm a -> +implCopyM :: HasCallStack => NuMatchingAny1 r => ExprVar a -> ValuePerm a -> ImplM vars s r (ps :> a :> a) (ps :> a) () implCopyM x p = implSimplM Proxy (SImpl_Copy x p) -- | Push a copyable permission using 'implPushM', copy that permission, and -- then pop it back to the variable permission for @x@ -implPushCopyM :: NuMatchingAny1 r => ExprVar a -> ValuePerm a -> +implPushCopyM :: HasCallStack => NuMatchingAny1 r => ExprVar a -> ValuePerm a -> ImplM vars s r (ps :> a) ps () implPushCopyM x p = implPushM x p >>> implCopyM x p >>> implPopM x p -- | Swap the top two permissions on the top of the stack -implSwapM :: NuMatchingAny1 r => ExprVar a -> ValuePerm a -> +implSwapM :: HasCallStack => NuMatchingAny1 r => ExprVar a -> ValuePerm a -> ExprVar b -> ValuePerm b -> ImplM vars s r (ps :> b :> a) (ps :> a :> b) () implSwapM x p1 y p2 = implSimplM Proxy (SImpl_Swap x p1 y p2) @@ -5565,7 +5565,7 @@ proveVarLLVMBlocks1 x ps psubst (mb_bp:mb_bps) , Perm_LLVMBlock bp <- ps!!i = -- Copy or extract the memblock perm we chose to the top of the stack - implGetConjM x ps i >>>= \ps' -> + implGetSwapConjM x ps i >>>= \ps' -> -- Make the input block have the required modalities equalizeBlockModalities x bp mb_bp >>>= \bp' -> From 4285452a99947bce9fb9d9fc5a7f56ca82adec23 Mon Sep 17 00:00:00 2001 From: Eddy Westbrook Date: Fri, 24 Sep 2021 07:05:09 -0700 Subject: [PATCH 75/98] updated the parsing for array shapes to more closely match the conventions for array permissions --- heapster-saw/src/Verifier/SAW/Heapster/Parser.y | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/heapster-saw/src/Verifier/SAW/Heapster/Parser.y b/heapster-saw/src/Verifier/SAW/Heapster/Parser.y index aef9139552..b9b6d57cb5 100644 --- a/heapster-saw/src/Verifier/SAW/Heapster/Parser.y +++ b/heapster-saw/src/Verifier/SAW/Heapster/Parser.y @@ -160,8 +160,8 @@ expr :: { AstExpr } | lifetime 'ptrsh' '(' expr ')' { ExPtrSh (pos $2) $1 Nothing $4 } | 'fieldsh' '(' expr ',' expr ')' { ExFieldSh (pos $1) (Just $3) $5 } | 'fieldsh' '(' expr ')' { ExFieldSh (pos $1) Nothing $3 } - | 'arraysh' '(' expr ',' expr ',' expr ')' - { ExArraySh (pos $1) $3 $5 $7 } + | 'arraysh' '(' '<' expr ',' '*' expr ',' expr ')' + { ExArraySh (pos $1) $4 $7 $9 } | 'exsh' IDENT ':' type '.' expr { ExExSh (pos $1) (locThing $2) $4 $6 } -- Value Permissions From 64f2518319db95ad17355556ae3e61143868b6bc Mon Sep 17 00:00:00 2001 From: Eddy Westbrook Date: Fri, 24 Sep 2021 07:20:49 -0700 Subject: [PATCH 76/98] clarified the fact that the cell type translation of an array permission translation is really the translation of the memblock permission to the first cell of the array, and fixed a translation bug related to this issue --- .../src/Verifier/SAW/Heapster/SAWTranslation.hs | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/heapster-saw/src/Verifier/SAW/Heapster/SAWTranslation.hs b/heapster-saw/src/Verifier/SAW/Heapster/SAWTranslation.hs index 6d9a7bf6c9..9b3cc36949 100644 --- a/heapster-saw/src/Verifier/SAW/Heapster/SAWTranslation.hs +++ b/heapster-saw/src/Verifier/SAW/Heapster/SAWTranslation.hs @@ -1037,20 +1037,20 @@ bvRangeTransLen :: BVRangeTrans ctx w -> ExprTrans (BVType w) bvRangeTransLen (BVRangeTrans _ _ len) = len -- | The translation of an LLVM array permission is a SAW term of @BVVec@ type, --- along with a type translation for its cell type and proof terms stating that --- all of the borrows are in the array. Note that the type translation for the --- cell type is always a 'tupleTypeTrans', i.e., has at most one SAW type. +-- along with a SAW term for its length as a bitvector and the type translation +-- for a @memblock@ permission to its head cell, which can be offset to get a +-- @memblock@ permission for any of its cells. data LLVMArrayPermTrans ctx w = LLVMArrayPermTrans { llvmArrayTransPerm :: Mb ctx (LLVMArrayPerm w), llvmArrayTransLen :: OpenTerm, - llvmArrayTransCell :: TypeTrans (AtomicPermTrans ctx (LLVMPointerType w)), + llvmArrayTransHeadCell :: TypeTrans (AtomicPermTrans ctx (LLVMPointerType w)), -- llvmArrayTransBorrows :: [LLVMArrayBorrowTrans ctx w], llvmArrayTransTerm :: OpenTerm } -- | Get the SAW type of the cells of the translation of an array permission llvmArrayTransCellType :: LLVMArrayPermTrans ctx w -> OpenTerm -llvmArrayTransCellType = typeTransType1 . llvmArrayTransCell +llvmArrayTransCellType = typeTransType1 . llvmArrayTransHeadCell -- | The translation of an 'LLVMArrayBorrow' is an element / proof of the @@ -1406,9 +1406,9 @@ getLLVMArrayTransCell :: (1 <= w, KnownNat w) => LLVMArrayPermTrans ctx w -> getLLVMArrayTransCell arr_trans mb_cell cell_tm (BVPropTrans _ in_rng_pf:_) = let w = fromInteger $ natVal arr_trans in fromJust $ - offsetLLVMAtomicPermTrans (mbMap2 llvmArrayCellToAbsOffset + offsetLLVMAtomicPermTrans (mbMap2 llvmArrayCellToOffset (llvmArrayTransPerm arr_trans) mb_cell) $ - typeTransF (llvmArrayTransCell arr_trans) + typeTransF (llvmArrayTransHeadCell arr_trans) [applyOpenTermMulti (globalOpenTerm "Prelude.atBVVec") [natOpenTerm w, llvmArrayTransLen arr_trans, llvmArrayTransCellType arr_trans, llvmArrayTransTerm arr_trans, @@ -2477,7 +2477,7 @@ translateSimplImpl (ps0 :: Proxy ps0) mb_simpl m = case mbMatch mb_simpl of LLVMArrayPermTrans { llvmArrayTransPerm = mb_ap_out , llvmArrayTransLen = bvAddOpenTerm w len1 len2 - , llvmArrayTransCell = llvmArrayTransCell array_trans1 + , llvmArrayTransHeadCell = llvmArrayTransHeadCell array_trans1 , llvmArrayTransTerm = applyOpenTermMulti (globalOpenTerm "Prelude.appendBVVec") [natOpenTerm w, len1, len2, llvmArrayTransTerm array_trans1, From 4fb4add9af8bd3fa5b47ec2c42096d89cc763259 Mon Sep 17 00:00:00 2001 From: Eddy Westbrook Date: Fri, 24 Sep 2021 07:39:29 -0700 Subject: [PATCH 77/98] fixed a bug in the SImpl_ElimLLVMBlockArray: that rule should only work when the input block permission has the same size as the resulting array shape --- .../src/Verifier/SAW/Heapster/Implication.hs | 43 +++++++++++-------- .../src/Verifier/SAW/Heapster/Permissions.hs | 6 ++- 2 files changed, 29 insertions(+), 20 deletions(-) diff --git a/heapster-saw/src/Verifier/SAW/Heapster/Implication.hs b/heapster-saw/src/Verifier/SAW/Heapster/Implication.hs index 782d88cb2e..44e30e4310 100644 --- a/heapster-saw/src/Verifier/SAW/Heapster/Implication.hs +++ b/heapster-saw/src/Verifier/SAW/Heapster/Implication.hs @@ -894,7 +894,7 @@ data SimplImpl ps_in ps_out where -- | Eliminate any @memblock@ permission to an array of bytes: -- -- > x:memblock(rw,l,off,len,emptysh) - -- > -o x:array(off, true]) + -- > -o x:[l]array(rw,off, ExprVar (LLVMPointerType w) -> LLVMBlockPerm w -> SimplImpl (RNil :> LLVMPointerType w) (RNil :> LLVMPointerType w) @@ -993,11 +993,13 @@ data SimplImpl ps_in ps_out where (1 <= w, KnownNat w) => ExprVar (LLVMPointerType w) -> LLVMArrayPerm w -> SimplImpl (RNil :> LLVMPointerType w) (RNil :> LLVMPointerType w) - -- | Eliminate a block of array shape to the corresponding array permission: + -- | Eliminate a block of array shape to the corresponding array permission, + -- assuming that the length of the block equals that of the array: -- - -- > x:memblock(...) -o x:array(...) + -- > x:[l]memblock(rw,off,stride*len,arraysh( -o x:[l]array(rw,off, ExprVar (LLVMPointerType w) -> LLVMArrayPerm w -> + (1 <= w, KnownNat w) => ExprVar (LLVMPointerType w) -> LLVMBlockPerm w -> SimplImpl (RNil :> LLVMPointerType w) (RNil :> LLVMPointerType w) -- | Prove a block of shape @sh1;sh2@ from blocks of shape @sh1@ and @sh2@, @@ -1767,11 +1769,8 @@ simplImplIn (SImpl_ElimLLVMBlockField x fp) = distPerms1 x (ValPerm_Conj1 $ Perm_LLVMBlock $ llvmFieldPermToBlock fp) simplImplIn (SImpl_IntroLLVMBlockArray x ap) = distPerms1 x (ValPerm_Conj1 $ Perm_LLVMArray ap) -simplImplIn (SImpl_ElimLLVMBlockArray x ap) = - case llvmAtomicPermToBlock (Perm_LLVMArray ap) of - Just bp -> distPerms1 x (ValPerm_Conj1 $ Perm_LLVMBlock bp) - Nothing -> - error "simplImplIn: SImpl_ElimLLVMBlockArray: malformed array permission" +simplImplIn (SImpl_ElimLLVMBlockArray x bp) = + distPerms1 x (ValPerm_Conj1 $ Perm_LLVMBlock bp) simplImplIn (SImpl_IntroLLVMBlockSeq x bp1 len2 sh2) = distPerms2 x (ValPerm_Conj1 $ Perm_LLVMBlock bp1) @@ -2084,8 +2083,11 @@ simplImplOut (SImpl_IntroLLVMBlockArray x ap) = Just bp -> distPerms1 x (ValPerm_Conj1 $ Perm_LLVMBlock bp) Nothing -> error "simplImplOut: SImpl_IntroLLVMBlockArray: malformed array permission" -simplImplOut (SImpl_ElimLLVMBlockArray x ap) = - distPerms1 x (ValPerm_Conj1 $ Perm_LLVMArray ap) +simplImplOut (SImpl_ElimLLVMBlockArray x bp) = + case llvmBlockPermToArray bp of + Just ap -> distPerms1 x (ValPerm_Conj1 $ Perm_LLVMArray ap) + Nothing -> + error "simplImplIn: SImpl_ElimLLVMBlockArray: malformed input permission" simplImplOut (SImpl_IntroLLVMBlockSeq x bp1 len2 sh2) = distPerms1 x (ValPerm_Conj1 $ Perm_LLVMBlock $ bp1 { llvmBlockLen = bvAdd (llvmBlockLen bp1) len2, @@ -2470,8 +2472,8 @@ instance SubstVar PermVarSubst m => SImpl_ElimLLVMBlockField <$> genSubst s x <*> genSubst s fp [nuMP| SImpl_IntroLLVMBlockArray x fp |] -> SImpl_IntroLLVMBlockArray <$> genSubst s x <*> genSubst s fp - [nuMP| SImpl_ElimLLVMBlockArray x fp |] -> - SImpl_ElimLLVMBlockArray <$> genSubst s x <*> genSubst s fp + [nuMP| SImpl_ElimLLVMBlockArray x bp |] -> + SImpl_ElimLLVMBlockArray <$> genSubst s x <*> genSubst s bp [nuMP| SImpl_IntroLLVMBlockSeq x bp1 len2 sh2 |] -> SImpl_IntroLLVMBlockSeq <$> genSubst s x <*> genSubst s bp1 <*> genSubst s len2 <*> genSubst s sh2 @@ -4075,11 +4077,16 @@ implElimLLVMBlock x bp@(LLVMBlockPerm implSimplM Proxy (SImpl_ElimLLVMBlockField x $ fromJust $ llvmBlockPermToField (exprLLVMTypeWidth p) bp) --- For an array shape, eliminate to an array permission -implElimLLVMBlock x bp@(LLVMBlockPerm { llvmBlockShape = - PExpr_ArrayShape _ _ _ }) = - implSimplM Proxy (SImpl_ElimLLVMBlockArray x $ fromJust $ - llvmBlockPermToArray bp) +-- For an array shape of the right length, eliminate to an array permission +implElimLLVMBlock x bp + | isJust (llvmBlockPermToArray bp) = + implSimplM Proxy (SImpl_ElimLLVMBlockArray x bp) + +-- FIXME: if we match an array shape here, its stride*length must be greater +-- than the length of bp, so we should truncate it +-- +-- implElimLLVMBlock x bp@(LLVMBlockPerm { llvmBlockShape = +-- PExpr_ArrayShape _ _ _ }) = -- Special case: for shape sh1;emptysh where the natural length of sh1 is the -- same as the length of the block permission, eliminate the emptysh, converting diff --git a/heapster-saw/src/Verifier/SAW/Heapster/Permissions.hs b/heapster-saw/src/Verifier/SAW/Heapster/Permissions.hs index 4b4f7c470c..7b34d35408 100644 --- a/heapster-saw/src/Verifier/SAW/Heapster/Permissions.hs +++ b/heapster-saw/src/Verifier/SAW/Heapster/Permissions.hs @@ -3334,11 +3334,13 @@ llvmArrayPermToBlock ap (llvmArrayCellShape ap) } llvmArrayPermToBlock _ = Nothing --- | Convert a block permission with array shape to an array permission +-- | Convert a block permission with array shape to an array permission, +-- assuming the length of the block permission equals the size of the array llvmBlockPermToArray :: (1 <= w, KnownNat w) => LLVMBlockPerm w -> Maybe (LLVMArrayPerm w) llvmBlockPermToArray bp - | PExpr_ArrayShape len stride sh <- llvmBlockShape bp = + | PExpr_ArrayShape len stride sh <- llvmBlockShape bp + , bvEq (bvMult stride len) (llvmBlockLen bp) = Just $ LLVMArrayPerm { llvmArrayRW = llvmBlockRW bp, llvmArrayLifetime = llvmBlockLifetime bp, From b1fdfd84091c0fabb8d1d9a517c08923653ef747 Mon Sep 17 00:00:00 2001 From: Eddy Westbrook Date: Fri, 24 Sep 2021 07:49:32 -0700 Subject: [PATCH 78/98] updated the generated Coq files --- .../coq/generated/CryptolToCoq/CryptolPrimitivesForSAWCore.v | 3 +++ saw-core-coq/coq/generated/CryptolToCoq/SAWCorePrelude.v | 4 ++-- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/saw-core-coq/coq/generated/CryptolToCoq/CryptolPrimitivesForSAWCore.v b/saw-core-coq/coq/generated/CryptolToCoq/CryptolPrimitivesForSAWCore.v index 3e1306614c..9b48c62f22 100644 --- a/saw-core-coq/coq/generated/CryptolToCoq/CryptolPrimitivesForSAWCore.v +++ b/saw-core-coq/coq/generated/CryptolToCoq/CryptolPrimitivesForSAWCore.v @@ -528,6 +528,9 @@ Definition ecSDiv : forall (n : @Num), @seq n (@SAWCoreScaffolding.Bool) -> @seq Definition ecSMod : forall (n : @Num), @seq n (@SAWCoreScaffolding.Bool) -> @seq n (@SAWCoreScaffolding.Bool) -> @seq n (@SAWCoreScaffolding.Bool) := fun (n : @Num) => CryptolPrimitivesForSAWCore.Num_rect (fun (n1 : @Num) => @seq n1 (@SAWCoreScaffolding.Bool) -> @seq n1 (@SAWCoreScaffolding.Bool) -> @seq n1 (@SAWCoreScaffolding.Bool)) (@SAWCorePrelude.Nat__rec (fun (n1 : @SAWCoreScaffolding.Nat) => @SAWCoreVectorsAsCoqVectors.Vec n1 (@SAWCoreScaffolding.Bool) -> @SAWCoreVectorsAsCoqVectors.Vec n1 (@SAWCoreScaffolding.Bool) -> @SAWCoreVectorsAsCoqVectors.Vec n1 (@SAWCoreScaffolding.Bool)) (@SAWCoreScaffolding.error (@SAWCoreVectorsAsCoqVectors.Vec 0 (@SAWCoreScaffolding.Bool) -> @SAWCoreVectorsAsCoqVectors.Vec 0 (@SAWCoreScaffolding.Bool) -> @SAWCoreVectorsAsCoqVectors.Vec 0 (@SAWCoreScaffolding.Bool)) "ecSMod: illegal 0-width word"%string) (fun (n' : @SAWCoreScaffolding.Nat) (_1 : @SAWCoreVectorsAsCoqVectors.Vec n' (@SAWCoreScaffolding.Bool) -> @SAWCoreVectorsAsCoqVectors.Vec n' (@SAWCoreScaffolding.Bool) -> @SAWCoreVectorsAsCoqVectors.Vec n' (@SAWCoreScaffolding.Bool)) => @SAWCoreVectorsAsCoqVectors.bvSRem n')) (@SAWCoreScaffolding.error (@SAWCorePrelude.Stream (@SAWCoreScaffolding.Bool) -> @SAWCorePrelude.Stream (@SAWCoreScaffolding.Bool) -> @SAWCorePrelude.Stream (@SAWCoreScaffolding.Bool)) "ecSMod: expected finite word"%string) n. +Definition toSignedInteger : forall (n : @Num), @seq n (@SAWCoreScaffolding.Bool) -> @SAWCoreScaffolding.Integer := + fun (n : @Num) => CryptolPrimitivesForSAWCore.Num_rect (fun (n1 : @Num) => @seq n1 (@SAWCoreScaffolding.Bool) -> @SAWCoreScaffolding.Integer) (@SAWCoreVectorsAsCoqVectors.sbvToInt) (@SAWCoreScaffolding.error (@SAWCorePrelude.Stream (@SAWCoreScaffolding.Bool) -> @SAWCoreScaffolding.Integer) "toSignedInteger: expected finite word"%string) n. + Definition ecEq : forall (a : Type), @PEq a -> a -> a -> @SAWCoreScaffolding.Bool := fun (a : Type) (pa : RecordTypeCons "eq" (a -> a -> @SAWCoreScaffolding.Bool) RecordTypeNil) => RecordProj pa "eq". diff --git a/saw-core-coq/coq/generated/CryptolToCoq/SAWCorePrelude.v b/saw-core-coq/coq/generated/CryptolToCoq/SAWCorePrelude.v index cfcecfaac1..e54ecacc32 100644 --- a/saw-core-coq/coq/generated/CryptolToCoq/SAWCorePrelude.v +++ b/saw-core-coq/coq/generated/CryptolToCoq/SAWCorePrelude.v @@ -934,8 +934,8 @@ Axiom at_gen_BVVec : forall (n : @SAWCoreScaffolding.Nat), forall (len : @SAWCor Axiom gen_at_BVVec : forall (n : @SAWCoreScaffolding.Nat), forall (len : @SAWCoreVectorsAsCoqVectors.Vec n (@SAWCoreScaffolding.Bool)), forall (a : Type), forall (x : @BVVec n len a), @SAWCoreScaffolding.Eq (@BVVec n len a) (@genBVVec n len a (@atBVVec n len a x)) x . -Definition updBVVec : forall (n : @SAWCoreScaffolding.Nat), forall (len : @SAWCoreVectorsAsCoqVectors.Vec n (@SAWCoreScaffolding.Bool)), forall (a : Type), @BVVec n len a -> forall (ix : @SAWCoreVectorsAsCoqVectors.Vec n (@SAWCoreScaffolding.Bool)), @is_bvult n ix len -> a -> @BVVec n len a := - fun (n : @SAWCoreScaffolding.Nat) (len : @SAWCoreVectorsAsCoqVectors.Vec n (@SAWCoreScaffolding.Bool)) (a : Type) (v : @SAWCoreVectorsAsCoqVectors.Vec (@SAWCoreVectorsAsCoqVectors.bvToNat n len) a) (ix : @SAWCoreVectorsAsCoqVectors.Vec n (@SAWCoreScaffolding.Bool)) (pf : @SAWCoreScaffolding.Eq (@SAWCoreScaffolding.Bool) (@SAWCoreVectorsAsCoqVectors.bvult n ix len) (@SAWCoreScaffolding.true)) (elem : a) => @genBVVec n len a (fun (i : @SAWCoreVectorsAsCoqVectors.Vec n (@SAWCoreScaffolding.Bool)) (_1 : @SAWCoreScaffolding.Eq (@SAWCoreScaffolding.Bool) (@SAWCoreVectorsAsCoqVectors.bvult n i len) (@SAWCoreScaffolding.true)) => if @bvEq n i ix then elem else @atBVVec n len a v ix pf). +Definition updBVVec : forall (n : @SAWCoreScaffolding.Nat), forall (len : @SAWCoreVectorsAsCoqVectors.Vec n (@SAWCoreScaffolding.Bool)), forall (a : Type), @BVVec n len a -> forall (ix : @SAWCoreVectorsAsCoqVectors.Vec n (@SAWCoreScaffolding.Bool)), a -> @BVVec n len a := + fun (n : @SAWCoreScaffolding.Nat) (len : @SAWCoreVectorsAsCoqVectors.Vec n (@SAWCoreScaffolding.Bool)) (a : Type) (v : @SAWCoreVectorsAsCoqVectors.Vec (@SAWCoreVectorsAsCoqVectors.bvToNat n len) a) (ix : @SAWCoreVectorsAsCoqVectors.Vec n (@SAWCoreScaffolding.Bool)) (elem : a) => @genBVVec n len a (fun (i : @SAWCoreVectorsAsCoqVectors.Vec n (@SAWCoreScaffolding.Bool)) (pf : @SAWCoreScaffolding.Eq (@SAWCoreScaffolding.Bool) (@SAWCoreVectorsAsCoqVectors.bvult n i len) (@SAWCoreScaffolding.true)) => if @bvEq n i ix then elem else @atBVVec n len a v i pf). Definition adjustBVVec : forall (n : @SAWCoreScaffolding.Nat), forall (len : @SAWCoreVectorsAsCoqVectors.Vec n (@SAWCoreScaffolding.Bool)), forall (a : Type), @BVVec n len a -> (a -> a) -> @SAWCoreVectorsAsCoqVectors.Vec n (@SAWCoreScaffolding.Bool) -> @BVVec n len a := fun (n : @SAWCoreScaffolding.Nat) (len : @SAWCoreVectorsAsCoqVectors.Vec n (@SAWCoreScaffolding.Bool)) (a : Type) (v : @SAWCoreVectorsAsCoqVectors.Vec (@SAWCoreVectorsAsCoqVectors.bvToNat n len) a) (f : a -> a) (ix : @SAWCoreVectorsAsCoqVectors.Vec n (@SAWCoreScaffolding.Bool)) => @genBVVec n len a (fun (i : @SAWCoreVectorsAsCoqVectors.Vec n (@SAWCoreScaffolding.Bool)) (pf : @SAWCoreScaffolding.Eq (@SAWCoreScaffolding.Bool) (@SAWCoreVectorsAsCoqVectors.bvult n i len) (@SAWCoreScaffolding.true)) => if @bvEq n i ix then f (@atBVVec n len a v i pf) else @atBVVec n len a v i pf). From ac9194a5a042d88ac3e63c7855e7a6ba718d9863 Mon Sep 17 00:00:00 2001 From: Eddy Westbrook Date: Fri, 24 Sep 2021 07:55:21 -0700 Subject: [PATCH 79/98] updated array permissions in the examples to use the new array permission syntax --- heapster-saw/examples/arrays.saw | 2 +- heapster-saw/examples/clearbufs.saw | 2 +- heapster-saw/examples/mbox.saw | 26 +++++++++++++------------- 3 files changed, 15 insertions(+), 15 deletions(-) diff --git a/heapster-saw/examples/arrays.saw b/heapster-saw/examples/arrays.saw index d5543838cd..df20935966 100644 --- a/heapster-saw/examples/arrays.saw +++ b/heapster-saw/examples/arrays.saw @@ -23,6 +23,6 @@ heapster_typecheck_fun env "zero_array_from" "(len:bv 64, off:bv 64).arg0:int64a heapster_join_point_hint env "filter_and_sum_pos" []; heapster_typecheck_fun env "filter_and_sum_pos" "(len:bv 64).arg0:int64array, arg1:eq(llvmword(len)) -o arg0:int64array, arg1:true, ret:int64<>"; -heapster_typecheck_fun env "sum_2d" "(l1:bv 64,l2:bv 64).arg0:array(W,0,))), arg1:eq(llvmword(l1)), arg2:eq(llvmword(l2)) -o arg0:arraysh(l2,*8,fieldsh(int64<>)), arg1:true, arg2:true, ret:int64<>"; +heapster_typecheck_fun env "sum_2d" "(l1:bv 64,l2:bv 64).arg0:array(W,0,)))), arg1:eq(llvmword(l1)), arg2:eq(llvmword(l2)) -o arg0:array(W,0,)))), arg1:true, arg2:true, ret:int64<>"; heapster_export_coq env "arrays_gen.v"; diff --git a/heapster-saw/examples/clearbufs.saw b/heapster-saw/examples/clearbufs.saw index b819426484..fa8561db52 100644 --- a/heapster-saw/examples/clearbufs.saw +++ b/heapster-saw/examples/clearbufs.saw @@ -4,7 +4,7 @@ env <- heapster_init_env_from_file "clearbufs.sawcore" "clearbufs.bc"; // Integer types heapster_define_perm env "int64" " " "llvmptr 64" "exists x:bv 64.eq(llvmword(x))"; -heapster_define_reachability_perm env "Bufs" "x:llvmptr 64" "llvmptr 64" "exists len:(bv 64).ptr((W,0) |-> Bufs) * ptr((W,8) |-> eq(llvmword(len))) * array(16, int64<>])" "Mbox_def" "foldMbox" "unfoldMbox" "transMbox"; +heapster_define_reachability_perm env "Bufs" "x:llvmptr 64" "llvmptr 64" "exists len:(bv 64).ptr((W,0) |-> Bufs) * ptr((W,8) |-> eq(llvmword(len))) * array(W, 16, ))" "Mbox_def" "foldMbox" "unfoldMbox" "transMbox"; heapster_block_entry_hint env "clearbufs" 3 "top1:llvmptr 64" "frm:llvmframe 64,ghost:llvmptr 64" "top1:Bufs, arg0:ptr((W,0) |-> eq(ghost)), ghost:Bufs,frm:llvmframe [arg0:8]"; diff --git a/heapster-saw/examples/mbox.saw b/heapster-saw/examples/mbox.saw index 19844ce74b..1e17a55621 100644 --- a/heapster-saw/examples/mbox.saw +++ b/heapster-saw/examples/mbox.saw @@ -20,15 +20,15 @@ heapster_define_perm env "int32" " " "llvmptr 32" "exists x:bv 32.eq(llvmword(x) heapster_define_perm env "int64" " " "llvmptr 64" "exists x:bv 64.eq(llvmword(x))"; -heapster_define_perm env "state_t" " " "llvmptr 64" "array(0, <16, *1, [(W,0) |-> int64<>])"; +heapster_define_perm env "state_t" " " "llvmptr 64" "array(W, 0, <16, *1, fieldsh(int64<>))"; -heapster_define_perm env "aes_sw_ctx" "rw1:rwmodality, rw2:rwmodality" "llvmptr 64" "array(0, <240, *1, [(rw1,0) |-> int64<>]) * ptr((rw2, 1920) |-> int64<>)"; +heapster_define_perm env "aes_sw_ctx" "rw1:rwmodality, rw2:rwmodality" "llvmptr 64" "array(rw1, 0, <240, *1, fieldsh(int64<>)) * ptr((rw2, 1920) |-> int64<>)"; -heapster_define_reachability_perm env "mbox" "rw:rwmodality, x:llvmptr 64" "llvmptr 64" "ptr((rw,0) |-> int64<>) * ptr((rw,8) |-> int64<>) * ptr((rw,16) |-> mbox) * array(24, <128, *1, [(rw,0,8) |-> int8<>])" "Mbox_def" "foldMbox" "unfoldMbox" "transMbox"; +heapster_define_reachability_perm env "mbox" "rw:rwmodality, x:llvmptr 64" "llvmptr 64" "ptr((rw,0) |-> int64<>) * ptr((rw,8) |-> int64<>) * ptr((rw,16) |-> mbox) * array(rw, 24, <128, *1, fieldsh(8,int8<>))" "Mbox_def" "foldMbox" "unfoldMbox" "transMbox"; // heapster_define_perm env "mbox_nonnull" "rw:rwmodality, p:perm (llvmptr 64)" "llvmptr 64" "ptr((rw,0) |-> int64<>) * ptr((rw,8) |-> int64<>) * ptr((rw,16) |-> int64<>) * ptr((rw,24) |-> mbox) * array(32, <128, *1, [(rw,0,8) |-> int8<>])"; -heapster_define_perm env "byte_array" "rw:rwmodality, len:bv 64" "llvmptr 64" "array(0, int8<>])"; +heapster_define_perm env "byte_array" "rw:rwmodality, off:bv 64, len:bv 64" "llvmptr 64" "array(rw, off, ))"; heapster_define_perm env "boolean" " " "llvmptr 1" "exists x:bv 1.eq(llvmword(x))"; @@ -43,7 +43,7 @@ heapster_define_perm env "boolean" " " "llvmptr 1" "exists x:bv 1.eq(llvmword(x) heapster_assume_fun env "llvm.objectsize.i64.p0i8" "().empty -o empty" "returnM #() ()"; -heapster_assume_fun env "__memcpy_chk" "(len:bv 64).arg0:byte_array,arg1:byte_array,arg2:eq(llvmword (len)) -o arg0:byte_array,arg1:byte_array" "\\ (len:Vec 64 Bool) (_ src : BVVec 64 len (Vec 8 Bool)) -> returnM (BVVec 64 len (Vec 8 Bool) * BVVec 64 len (Vec 8 Bool)) (src, src)"; +heapster_assume_fun env "__memcpy_chk" "(len:bv 64).arg0:byte_array,arg1:byte_array,arg2:eq(llvmword (len)) -o arg0:byte_array,arg1:byte_array" "\\ (len:Vec 64 Bool) (_ src : BVVec 64 len (Vec 8 Bool)) -> returnM (BVVec 64 len (Vec 8 Bool) * BVVec 64 len (Vec 8 Bool)) (src, src)"; //------------------------------------------------------------------------------ @@ -62,7 +62,7 @@ heapster_assume_fun env "mbox_all_freed" "().empty -o ret:boolean<>" "mboxAllFre heapster_assume_fun env "mbox_new" "().empty -o ret:mbox" "mboxNewSpec"; -heapster_assume_fun env "mbox_free" "().arg0:ptr((W,0) |-> true) * ptr((W,8) |-> true) * ptr((W,16) |-> true) * array(24, <128, *1, [(W,0,8) |-> int8<>]) -o arg0:true, ret:int32<>" "mboxFreeSpec"; +heapster_assume_fun env "mbox_free" "().arg0:ptr((W,0) |-> true) * ptr((W,8) |-> true) * ptr((W,16) |-> true) * byte_array -o arg0:true, ret:int32<>" "mboxFreeSpec"; heapster_block_entry_hint env "mbox_free_chain" 3 "top1:llvmptr 64" "frm:llvmframe 64" "top1:true, arg0:ptr((W,0,32) |-> true), arg1:ptr((W,0) |-> mbox), arg2:ptr((W,0) |-> true), arg3:ptr((W,0,32) |-> true),frm:llvmframe [arg3:4,arg2:8,arg1:8,arg0:4]"; @@ -75,17 +75,17 @@ heapster_block_entry_hint env "mbox_eq" 29 "top1:llvmptr 64, top2:llvmptr 64" "f heapster_typecheck_fun env "mbox_eq" "().arg0:mbox, arg1:mbox -o arg0:mbox, arg1:mbox, ret:int32<>"; -heapster_block_entry_hint env "mbox_from_buffer" 24 "top1:bv 64, top2:llvmptr 64, top3:llvmptr 64" "frm:llvmframe 64, ghost0:llvmptr 64, ghost1:bv 64" "top1:true, top2:array(0, int8<>]), top3:eq(llvmword(top1)), arg0:ptr((W,0) |-> true), arg1:ptr((W,0) |-> eq(top2)), arg2:ptr((W,0) |-> eq(llvmword(top1))), arg3:ptr((W,0) |-> mbox), arg4:ptr((W,0) |-> eq(ghost0)), arg5:ptr((W,0) |-> eq(llvmword(ghost1))), arg6:ptr((W,0) |-> true), frm:llvmframe [arg6:8, arg5:8, arg4:8, arg3:8, arg2:8, arg1:8, arg0:8], ghost0:ptr((W,0) |-> int64<>) * ptr((W,8) |-> int64<>) * ptr((W,16) |-> mbox) * array(24, <128, *1, [(W,0,8) |-> int8<>]), ghost1:true"; +heapster_block_entry_hint env "mbox_from_buffer" 24 "top1:bv 64, top2:llvmptr 64, top3:llvmptr 64" "frm:llvmframe 64, ghost0:llvmptr 64, ghost1:bv 64" "top1:true, top2:byte_array, top3:eq(llvmword(top1)), arg0:ptr((W,0) |-> true), arg1:ptr((W,0) |-> eq(top2)), arg2:ptr((W,0) |-> eq(llvmword(top1))), arg3:ptr((W,0) |-> mbox), arg4:ptr((W,0) |-> eq(ghost0)), arg5:ptr((W,0) |-> eq(llvmword(ghost1))), arg6:ptr((W,0) |-> true), frm:llvmframe [arg6:8, arg5:8, arg4:8, arg3:8, arg2:8, arg1:8, arg0:8], ghost0:ptr((W,0) |-> int64<>) * ptr((W,8) |-> int64<>) * ptr((W,16) |-> mbox) * byte_array, ghost1:true"; -heapster_typecheck_fun env "mbox_from_buffer" "(len:bv 64).arg0:array(0, int8<>]), arg1:eq(llvmword(len)) -o arg0:array(0, int8<>]), arg1:true, ret:mbox"; +heapster_typecheck_fun env "mbox_from_buffer" "(len:bv 64).arg0:byte_array, arg1:eq(llvmword(len)) -o arg0:byte_array, arg1:true, ret:mbox"; -heapster_block_entry_hint env "mbox_to_buffer" 32 "top1:bv 64, top2:llvmptr 64, top3:llvmptr 64, top4:llvmptr 64, top5:llvmptr 64" "frm:llvmframe 64, ghost0:llvmptr 64" "top1:true, top2:array(0, int8<>]), top3:eq(llvmword(top1)), top4:mbox, top5:int64<>, arg0:ptr((W,0) |-> true), arg1:ptr((W,0) |-> eq(top2)), arg2:ptr((W,0) |-> eq(top3)), arg3:ptr((W,0) |-> eq(ghost0)), arg4:ptr((W,0) |-> int64<>), arg5:ptr((W,0) |-> int64<>), arg6:ptr((W,0) |-> true), frm:llvmframe [arg6:8, arg5:8, arg4:8, arg3:8, arg2:8, arg1:8, arg0:8], ghost0:mbox"; +heapster_block_entry_hint env "mbox_to_buffer" 32 "top1:bv 64, top2:llvmptr 64, top3:llvmptr 64, top4:llvmptr 64, top5:llvmptr 64" "frm:llvmframe 64, ghost0:llvmptr 64" "top1:true, top2:byte_array, top3:eq(llvmword(top1)), top4:mbox, top5:int64<>, arg0:ptr((W,0) |-> true), arg1:ptr((W,0) |-> eq(top2)), arg2:ptr((W,0) |-> eq(top3)), arg3:ptr((W,0) |-> eq(ghost0)), arg4:ptr((W,0) |-> int64<>), arg5:ptr((W,0) |-> int64<>), arg6:ptr((W,0) |-> true), frm:llvmframe [arg6:8, arg5:8, arg4:8, arg3:8, arg2:8, arg1:8, arg0:8], ghost0:mbox"; -heapster_typecheck_fun env "mbox_to_buffer" "(len:bv 64).arg0:array(0, int8<>]), arg1:eq(llvmword(len)), arg2:mbox, arg3:int64<> -o arg0:array(0, int8<>]), arg1:true, arg2:mbox, arg3:true, ret:int64<>"; +heapster_typecheck_fun env "mbox_to_buffer" "(len:bv 64).arg0:byte_array, arg1:eq(llvmword(len)), arg2:mbox, arg3:int64<> -o arg0:byte_array, arg1:true, arg2:mbox, arg3:true, ret:int64<>"; -heapster_typecheck_fun env "mbox_to_buffer_rec" "(len:bv 64).arg0:array(0, int8<>]), arg1:eq(llvmword(len)), arg2:mbox -o arg0:array(0, int8<>]), arg1:true, arg2:mbox, ret:true"; +heapster_typecheck_fun env "mbox_to_buffer_rec" "(len:bv 64).arg0:byte_array, arg1:eq(llvmword(len)), arg2:mbox -o arg0:byte_array, arg1:true, arg2:mbox, ret:true"; // heapster_typecheck_fun env "mbox_to_buffer_rec" "(len:bv 64).arg0:byte_array, arg1:eq(llvmword(len)), arg2:mbox, arg3:int64<> -o arg0:byte_array, arg1:true, arg2:mbox, arg3:true, ret:int64<>"; @@ -98,7 +98,7 @@ heapster_typecheck_fun env "mbox_len" "().arg0:mbox -o arg0:mbox< heapster_typecheck_fun env "mbox_concat" "().arg0:mbox, arg1:mbox -o arg0:mbox, arg1:true"; -heapster_block_entry_hint env "mbox_concat_chains" 16 "top1:llvmptr 64, top2:llvmptr 64" "frm:llvmframe 64, x0:llvmptr 64" "top1:mbox, top2:mbox, arg0:ptr((W,0) |-> eq(x0)), arg1:ptr((W,0) |-> eq(top2)), frm:llvmframe [arg1:8, arg0:8], x0:ptr((W,0) |-> int64<>) * ptr((W,8) |-> int64<>) * ptr((W,16) |-> mbox) * array(24, <128, *1, [(W,0,8) |-> int8<>])"; +heapster_block_entry_hint env "mbox_concat_chains" 16 "top1:llvmptr 64, top2:llvmptr 64" "frm:llvmframe 64, x0:llvmptr 64" "top1:mbox, top2:mbox, arg0:ptr((W,0) |-> eq(x0)), arg1:ptr((W,0) |-> eq(top2)), frm:llvmframe [arg1:8, arg0:8], x0:ptr((W,0) |-> int64<>) * ptr((W,8) |-> int64<>) * ptr((W,16) |-> mbox) * byte_array"; heapster_typecheck_fun env "mbox_concat_chains" "().arg0:mbox, arg1:mbox -o arg0:mbox"; @@ -127,7 +127,7 @@ heapster_typecheck_fun env "mbox_detach_from_end" "().arg0:ptr((W,0) |-> mbox -o arg0:mbox, ret:int32<>"; -heapster_block_entry_hint env "mbox_randomize" 16 "top1:llvmptr 64" "frm:llvmframe 64" "top1:ptr((W,0) |-> int64<>) * ptr((W,8) |-> int64<>) * ptr((W,16) |-> mbox) * array(24, <128, *1, [(W,0,8) |-> int8<>]), arg0:ptr((W,0,32) |-> true), arg1:ptr((W,0) |-> eq(top1)), arg2:ptr((W,0) |-> int64<>), frm:llvmframe [arg2:8, arg1:8, arg0:4]"; +heapster_block_entry_hint env "mbox_randomize" 16 "top1:llvmptr 64" "frm:llvmframe 64" "top1:ptr((W,0) |-> int64<>) * ptr((W,8) |-> int64<>) * ptr((W,16) |-> mbox) * byte_array, arg0:ptr((W,0,32) |-> true), arg1:ptr((W,0) |-> eq(top1)), arg2:ptr((W,0) |-> int64<>), frm:llvmframe [arg2:8, arg1:8, arg0:4]"; heapster_typecheck_fun env "mbox_randomize" "().arg0:mbox -o arg0:mbox, ret:int32<>"; From a3f9967a605aac24febee81b061ac0b9e1247eaa Mon Sep 17 00:00:00 2001 From: Eddy Westbrook Date: Fri, 24 Sep 2021 10:40:06 -0700 Subject: [PATCH 80/98] fixed a bug in implElimLLVMBlockForOffset, which was not handling non-conjunctive permissions returned by implElimLLVMBlock; added pretty-printing and typing information for the names bound by local implications --- .../src/Verifier/SAW/Heapster/Implication.hs | 30 ++++++++++++------- 1 file changed, 19 insertions(+), 11 deletions(-) diff --git a/heapster-saw/src/Verifier/SAW/Heapster/Implication.hs b/heapster-saw/src/Verifier/SAW/Heapster/Implication.hs index 44e30e4310..ccdd519666 100644 --- a/heapster-saw/src/Verifier/SAW/Heapster/Implication.hs +++ b/heapster-saw/src/Verifier/SAW/Heapster/Implication.hs @@ -2697,19 +2697,24 @@ embedImplM ps_in m = -- | Embed a sub-computation in a name-binding inside another 'ImplM' -- computation, throwing away any state from that sub-computation and returning -- a 'PermImpl' inside a name-binding -embedMbImplM :: Mb ctx (DistPerms ps_in) -> +embedMbImplM :: KnownRepr CruCtx ctx => Mb ctx (DistPerms ps_in) -> Mb ctx (ImplM RNil s r' ps_out ps_in (r' ps_out)) -> ImplM vars s r ps ps (Mb ctx (PermImpl r' ps_in)) embedMbImplM mb_ps_in mb_m = do s <- get - lift $ strongMbM $ mbMap2 - (\ps_in m -> + lift $ strongMbM $ nuMultiWithElim + (\ns (_ :>: Identity ps_in :>: Identity m) -> runImplM CruCtxNil (distPermSet ps_in) (view implStatePermEnv s) (view implStatePPInfo s) (view implStateFailPrefix s) (view implStateDebugLevel s) - (view implStateNameTypes s) m (pure . fst)) - mb_ps_in mb_m + (view implStateNameTypes s) + (gmodify (over implStatePPInfo + (ppInfoAddTypedExprNames knownRepr ns)) >>> + implSetNameTypes ns knownRepr >>> + m) + (pure . fst)) + (MNil :>: mb_ps_in :>: mb_m) -- | Run an 'ImplM' computation in a locally-scoped way, where all effects -- are restricted to the local computation. This is essentially a form of the @@ -4195,9 +4200,13 @@ implElimLLVMBlockForOffset :: (1 <= w, KnownNat w, NuMatchingAny1 r) => (ps :> LLVMPointerType w) (AtomicPerm (LLVMPointerType w)) implElimLLVMBlockForOffset x bp imprecise_p off mb_p = - implElimLLVMBlock x bp >>> getTopDistPerm x >>>= \(ValPerm_Conj ps) -> - implGetLLVMPermForOffset x ps imprecise_p True off mb_p - + implElimLLVMBlock x bp >>> elimOrsExistsNamesM x >>>= \p' -> + case p' of + ValPerm_Conj ps -> + implGetLLVMPermForOffset x ps imprecise_p True off mb_p + _ -> + -- FIXME: handle eq perms here + implFailVarM "implElimLLVMBlockForOffset" x (ValPerm_LLVMBlock bp) mb_p -- | Assume @x:p1*...*pn@ is on top of the stack, and try to find a permission -- @pi@ that contains a given offset @off@. If a @pi@ is found that definitely @@ -7072,9 +7081,8 @@ localProveVars ps_in ps_out = -- | Prove one sequence of permissions over an extended set of local variables -- from another and capture the proof as a 'LocalPermImpl' in a binding -localMbProveVars :: NuMatchingAny1 r => - Mb (ctx :: RList CrucibleType) (DistPerms ps_in) -> - Mb ctx (DistPerms ps_out) -> +localMbProveVars :: NuMatchingAny1 r => KnownRepr CruCtx ctx => + Mb ctx (DistPerms ps_in) -> Mb ctx (DistPerms ps_out) -> ImplM vars s r ps ps (Mb ctx (LocalPermImpl ps_in ps_out)) localMbProveVars mb_ps_in mb_ps_out = implTraceM (\i -> sep [pretty "localMbProveVars:", permPretty i mb_ps_in, From 25235b6c795aff67fb6ed889b31e93e431c57402 Mon Sep 17 00:00:00 2001 From: Eddy Westbrook Date: Fri, 24 Sep 2021 11:11:37 -0700 Subject: [PATCH 81/98] fixed a subtle bug in offsetLLVMPermTrans applied to the translations of defined permissions --- heapster-saw/src/Verifier/SAW/Heapster/SAWTranslation.hs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/heapster-saw/src/Verifier/SAW/Heapster/SAWTranslation.hs b/heapster-saw/src/Verifier/SAW/Heapster/SAWTranslation.hs index 9b3cc36949..35a14d5c9d 100644 --- a/heapster-saw/src/Verifier/SAW/Heapster/SAWTranslation.hs +++ b/heapster-saw/src/Verifier/SAW/Heapster/SAWTranslation.hs @@ -1347,7 +1347,8 @@ offsetLLVMPermTrans mb_off (PTrans_Conj ps) = PTrans_Conj $ mapMaybe (offsetLLVMAtomicPermTrans mb_off) ps offsetLLVMPermTrans mb_off (PTrans_Defined n args off ptrans) = PTrans_Defined n args (mbMap2 addPermOffsets off - (fmap mkLLVMPermOffset mb_off)) ptrans + (fmap mkLLVMPermOffset mb_off)) $ + offsetLLVMPermTrans mb_off ptrans offsetLLVMPermTrans mb_off (PTrans_Term mb_p t) = PTrans_Term (mbMap2 offsetLLVMPerm mb_off mb_p) t From d970fc63175c09fe55fde72b5ee62960b16732c5 Mon Sep 17 00:00:00 2001 From: Eddy Westbrook Date: Fri, 24 Sep 2021 11:19:53 -0700 Subject: [PATCH 82/98] fixed the pretty-printer for array shapes to use the < and * prefixes --- heapster-saw/src/Verifier/SAW/Heapster/Permissions.hs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/heapster-saw/src/Verifier/SAW/Heapster/Permissions.hs b/heapster-saw/src/Verifier/SAW/Heapster/Permissions.hs index 7b34d35408..19eef6c9da 100644 --- a/heapster-saw/src/Verifier/SAW/Heapster/Permissions.hs +++ b/heapster-saw/src/Verifier/SAW/Heapster/Permissions.hs @@ -892,7 +892,9 @@ instance PermPretty (PermExpr a) where do len_pp <- permPrettyM len sh_pp <- permPrettyM sh let stride_pp = pretty (toInteger stride) - return (pretty "arraysh" <> tupled [len_pp, stride_pp, sh_pp]) + return (pretty "arraysh" <> + ppEncList True [pretty "<" <> len_pp, + pretty "*" <> stride_pp, sh_pp]) permPrettyM (PExpr_SeqShape sh1 sh2) = do pp1 <- permPrettyM sh1 pp2 <- permPrettyM sh2 From c03016d5b6f8a65adbfd711802444d3d896fb983 Mon Sep 17 00:00:00 2001 From: Eddy Westbrook Date: Fri, 24 Sep 2021 11:33:29 -0700 Subject: [PATCH 83/98] whoops, I accidentally swapped the input and output permissions of the local implication used to prove array contents! --- heapster-saw/src/Verifier/SAW/Heapster/Implication.hs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/heapster-saw/src/Verifier/SAW/Heapster/Implication.hs b/heapster-saw/src/Verifier/SAW/Heapster/Implication.hs index ccdd519666..f18e1d3836 100644 --- a/heapster-saw/src/Verifier/SAW/Heapster/Implication.hs +++ b/heapster-saw/src/Verifier/SAW/Heapster/Implication.hs @@ -5331,9 +5331,9 @@ proveVarLLVMArray_FromArray2 x ap_lhs _ bs mb_ap = else -- Otherwise, coerce the contents let dps_in = nu $ \y -> distPerms1 y $ ValPerm_LLVMBlock $ - llvmArrayCellPerm ap $ bvInt 0 + llvmArrayCellPerm ap_lhs'' $ bvInt 0 dps_out = nu $ \y -> distPerms1 y $ ValPerm_LLVMBlock $ - llvmArrayCellPerm ap_lhs'' $ bvInt 0 in + llvmArrayCellPerm ap $ bvInt 0 in localMbProveVars dps_in dps_out >>>= \mb_impl -> implSimplM Proxy (SImpl_LLVMArrayContents x ap_lhs'' sh mb_impl) >>> return (ap_lhs'' { llvmArrayCellShape = sh })) >>>= \ap_lhs''' -> From af014643241cb0b31f843f49e3a1769ae86bba5b Mon Sep 17 00:00:00 2001 From: Eddy Westbrook Date: Sun, 26 Sep 2021 13:03:20 -0700 Subject: [PATCH 84/98] Changed the SImpl_LLVMArrayCopy and SImpl_LLVMArrayBorrow rules to generate the sub-array being borrowed, and to only take the borrows from the larger array that could overlap with the sub-array; Added cases to prove field permissions from arrays of smaller strides; added more debug information --- .../src/Verifier/SAW/Heapster/Implication.hs | 311 +++++++++++------- .../src/Verifier/SAW/Heapster/Permissions.hs | 87 ++++- .../Verifier/SAW/Heapster/SAWTranslation.hs | 19 +- 3 files changed, 272 insertions(+), 145 deletions(-) diff --git a/heapster-saw/src/Verifier/SAW/Heapster/Implication.hs b/heapster-saw/src/Verifier/SAW/Heapster/Implication.hs index f18e1d3836..d84c01e341 100644 --- a/heapster-saw/src/Verifier/SAW/Heapster/Implication.hs +++ b/heapster-saw/src/Verifier/SAW/Heapster/Implication.hs @@ -594,12 +594,12 @@ data SimplImpl ps_in ps_out where ExprVar (LLVMPointerType w) -> LLVMArrayPerm w -> SimplImpl (RNil :> LLVMPointerType w) (RNil :> LLVMPointerType w) - -- | Copy an array permission out of a larger array permission, assuming that - -- all fields of the array are copyable, using a proof that the copied array - -- permission is contained in the larger one as per 'llvmArrayContainsArray', - -- i.e., that the range of the smaller array is contained in the larger one - -- and that all borrows in the larger one are either preserved in the smaller - -- or are disjoint from it: + -- | Copy a portion of an array permission with a given offset and length, as + -- computed by 'llvmMakeSubArray', assuming that the array is copyable. This + -- requires a proof that the copied sub-array permission is contained in the + -- larger one as per 'llvmArrayContainsArray', i.e., that the range of the + -- smaller array is contained in the larger one and that all borrows in the + -- larger one are either preserved in the smaller or are disjoint from it: -- -- > x:ar1=array(off1, * x:prop('llvmArrayContainsArray' ar1 ar2) @@ -607,12 +607,14 @@ data SimplImpl ps_in ps_out where -- > * x:ar1=[l]array(rw,off1, - ExprVar (LLVMPointerType w) -> LLVMArrayPerm w -> LLVMArrayPerm w -> + ExprVar (LLVMPointerType w) -> LLVMArrayPerm w -> + PermExpr (BVType w) -> PermExpr (BVType w) -> SimplImpl (RNil :> LLVMPointerType w :> LLVMPointerType w) (RNil :> LLVMPointerType w :> LLVMPointerType w) - -- | Borrow an array permission from a larger array permission, using a proof - -- that the borrowed array permission is contained in the larger one as per + -- | Borrow a portion of an arra permission with a given offset and length, as + -- computed by 'llvmMakeSubArray'. This requires a proof that the borrowed + -- array permission is contained in the larger one as per -- 'llvmArrayContainsArray', i.e., that the range of the smaller array is -- contained in the larger one and that all borrows in the larger one are -- either preserved in the smaller or are disjoint from it: @@ -623,7 +625,8 @@ data SimplImpl ps_in ps_out where -- > * x:[l]array(rw,off1, - ExprVar (LLVMPointerType w) -> LLVMArrayPerm w -> LLVMArrayPerm w -> + ExprVar (LLVMPointerType w) -> LLVMArrayPerm w -> + PermExpr (BVType w) -> PermExpr (BVType w) -> SimplImpl (RNil :> LLVMPointerType w :> LLVMPointerType w) (RNil :> LLVMPointerType w :> LLVMPointerType w) @@ -667,17 +670,14 @@ data SimplImpl ps_in ps_out where ExprVar (LLVMPointerType w) -> LLVMArrayPerm w -> SimplImpl RNil (RNil :> LLVMPointerType w) - {- - -- | Convert an array to a field of the same size with @true@ contents: - -- - -- > x:array(off,<(sz/stride/8),*stride,sh,[]) -o x:[l]ptr((rw,off) |-> true) + -- | Convert an array of byte-sized cells to a field of the same size with + -- @true@ contents: -- - -- where all @fps@ must have the same @rw@ and @l@ + -- > x:array[l](rw,off,<(sz/8),*stride,sh) -o x:[l]ptr((sz,rw,off) |-> true) SImpl_LLVMArrayToField :: (1 <= w, KnownNat w, 1 <= sz, KnownNat sz) => ExprVar (LLVMPointerType w) -> LLVMArrayPerm w -> NatRepr sz -> SimplImpl (RNil :> LLVMPointerType w) (RNil :> LLVMPointerType w) - -} -- | Prove an array of length 1 from a block of its same shape: -- @@ -1619,17 +1619,19 @@ simplImplIn (SImpl_DemoteLLVMFieldRW x fld) = distPerms1 x (ValPerm_Conj [Perm_LLVMField fld]) simplImplIn (SImpl_DemoteLLVMArrayRW x ap) = distPerms1 x (ValPerm_Conj [Perm_LLVMArray ap]) -simplImplIn (SImpl_LLVMArrayCopy x ap sub_ap) = - if isJust (llvmArrayIsOffsetArray ap sub_ap) && +simplImplIn (SImpl_LLVMArrayCopy x ap off len) = + if isJust (matchLLVMArrayCell ap off) && atomicPermIsCopyable (Perm_LLVMArray ap) then distPerms2 x (ValPerm_Conj [Perm_LLVMArray ap]) - x (ValPerm_Conj $ map Perm_BVProp $ llvmArrayContainsArray ap sub_ap) + x (ValPerm_Conj $ map Perm_BVProp $ llvmArrayContainsArray ap $ + llvmMakeSubArray ap off len) else error "simplImplIn: SImpl_LLVMArrayCopy: array permission not copyable or not a sub-array" -simplImplIn (SImpl_LLVMArrayBorrow x ap sub_ap) = - if isJust (llvmArrayIsOffsetArray ap sub_ap) then +simplImplIn (SImpl_LLVMArrayBorrow x ap off len) = + if isJust (matchLLVMArrayCell ap off) then distPerms2 x (ValPerm_Conj [Perm_LLVMArray ap]) - x (ValPerm_Conj $ map Perm_BVProp $ llvmArrayContainsArray ap sub_ap) + x (ValPerm_Conj $ map Perm_BVProp $ llvmArrayContainsArray ap $ + llvmMakeSubArray ap off len) else error "simplImplIn: SImpl_LLVMArrayBorrow: array permission not a sub-array" simplImplIn (SImpl_LLVMArrayReturn x ap ret_ap) = @@ -1655,10 +1657,8 @@ simplImplIn (SImpl_LLVMArrayRearrange x ap bs) = else error "simplImplIn: SImpl_LLVMArrayRearrange: malformed output borrows list" -{- simplImplIn (SImpl_LLVMArrayToField x ap _) = distPerms1 x (ValPerm_Conj1 $ Perm_LLVMArray ap) --} simplImplIn (SImpl_LLVMArrayEmpty _ ap) = if bvIsZero (llvmArrayLen ap) then DistPermsNil else @@ -1903,24 +1903,24 @@ simplImplOut (SImpl_DemoteLLVMFieldRW x fld) = simplImplOut (SImpl_DemoteLLVMArrayRW x ap) = distPerms1 x (ValPerm_Conj [Perm_LLVMArray $ ap { llvmArrayRW = PExpr_Read }]) -simplImplOut (SImpl_LLVMArrayCopy x ap sub_ap) = - if isJust (llvmArrayIsOffsetArray ap sub_ap) && +simplImplOut (SImpl_LLVMArrayCopy x ap off len) = + if isJust (matchLLVMArrayCell ap off) && atomicPermIsCopyable (Perm_LLVMArray ap) then - distPerms2 x (ValPerm_Conj [Perm_LLVMArray sub_ap]) + distPerms2 x (ValPerm_Conj [Perm_LLVMArray $ llvmMakeSubArray ap off len]) x (ValPerm_Conj [Perm_LLVMArray ap]) else error "simplImplOut: SImpl_LLVMArrayCopy: array permission not copyable or not a sub-array" -simplImplOut (SImpl_LLVMArrayBorrow x ap sub_ap) = - case llvmArrayIsOffsetArray ap sub_ap of - Just _ -> - distPerms2 x (ValPerm_Conj [Perm_LLVMArray sub_ap]) - x (ValPerm_Conj - [Perm_LLVMArray $ - llvmArrayAddBorrow (llvmSubArrayBorrow ap sub_ap) $ +simplImplOut (SImpl_LLVMArrayBorrow x ap off len) = + if isJust (matchLLVMArrayCell ap off) then + let sub_ap = llvmMakeSubArray ap off len in + distPerms2 x (ValPerm_Conj [Perm_LLVMArray sub_ap]) + x (ValPerm_Conj + [Perm_LLVMArray $ + llvmArrayAddBorrow (llvmSubArrayBorrow ap sub_ap) $ llvmArrayRemArrayBorrows ap sub_ap]) - Nothing -> - error "simplImplOut: SImpl_LLVMArrayBorrow: array permission not a sub-array" + else + error "simplImplOut: SImpl_LLVMArrayBorrow: array permission not a sub-array" simplImplOut (SImpl_LLVMArrayReturn x ap ret_ap) = if isJust (llvmArrayIsOffsetArray ap ret_ap) && @@ -1949,13 +1949,11 @@ simplImplOut (SImpl_LLVMArrayRearrange x ap bs) = else error "simplImplOut: SImpl_LLVMArrayRearrange: malformed output borrows list" -{- simplImplOut (SImpl_LLVMArrayToField x ap sz) = case llvmArrayToField sz ap of Just fp -> distPerms1 x (ValPerm_Conj1 $ Perm_LLVMField fp) Nothing -> error "simplImplOut: SImpl_LLVMArrayToField: malformed array permission" --} simplImplOut (SImpl_LLVMArrayEmpty x ap) = if bvIsZero (llvmArrayLen ap) then @@ -2370,19 +2368,21 @@ instance SubstVar PermVarSubst m => SImpl_DemoteLLVMFieldRW <$> genSubst s x <*> genSubst s fld [nuMP| SImpl_DemoteLLVMArrayRW x ap |] -> SImpl_DemoteLLVMArrayRW <$> genSubst s x <*> genSubst s ap - [nuMP| SImpl_LLVMArrayCopy x ap rng |] -> - SImpl_LLVMArrayCopy <$> genSubst s x <*> genSubst s ap <*> genSubst s rng - [nuMP| SImpl_LLVMArrayBorrow x ap rng |] -> - SImpl_LLVMArrayBorrow <$> genSubst s x <*> genSubst s ap <*> genSubst s rng + [nuMP| SImpl_LLVMArrayCopy x ap off len |] -> + SImpl_LLVMArrayCopy <$> genSubst s x <*> genSubst s ap <*> genSubst s off + <*> genSubst s len + [nuMP| SImpl_LLVMArrayBorrow x ap off len |] -> + SImpl_LLVMArrayBorrow <$> genSubst s x <*> genSubst s ap <*> genSubst s off + <*> genSubst s len [nuMP| SImpl_LLVMArrayReturn x ap rng |] -> SImpl_LLVMArrayReturn <$> genSubst s x <*> genSubst s ap <*> genSubst s rng [nuMP| SImpl_LLVMArrayAppend x ap1 ap2 |] -> SImpl_LLVMArrayAppend <$> genSubst s x <*> genSubst s ap1 <*> genSubst s ap2 [nuMP| SImpl_LLVMArrayRearrange x ap bs |] -> SImpl_LLVMArrayRearrange <$> genSubst s x <*> genSubst s ap <*> genSubst s bs - -- [nuMP| SImpl_LLVMArrayToField x ap sz |] -> - -- SImpl_LLVMArrayToField <$> genSubst s x <*> genSubst s ap - -- <*> return (mbLift sz) + [nuMP| SImpl_LLVMArrayToField x ap sz |] -> + SImpl_LLVMArrayToField <$> genSubst s x <*> genSubst s ap + <*> return (mbLift sz) [nuMP| SImpl_LLVMArrayEmpty x ap |] -> SImpl_LLVMArrayEmpty <$> genSubst s x <*> genSubst s ap [nuMP| SImpl_LLVMArrayFromBlock x bp |] -> @@ -3869,6 +3869,26 @@ implLLVMArrayCellCopy x ap cell = implTryProveBVProps x (llvmArrayCellInArray ap cell) >>> implSimplM Proxy (SImpl_LLVMArrayCellCopy x ap cell) +-- | Copy or borrow a cell from an LLVM array permission on top of the stack, +-- depending on whether the array is copyable, after proving (with +-- 'implTryProveBVProps') that the index is in the array exclusive of any +-- outstanding borrows (see 'llvmArrayCellInArray'). Return the resulting array +-- permission with the borrow and the borrowed cell permission, leaving the +-- array permission on top of the stack and the cell permission just below it on +-- the stack. +implLLVMArrayCellGet :: + (1 <= w, KnownNat w, NuMatchingAny1 r) => + ExprVar (LLVMPointerType w) -> LLVMArrayPerm w -> PermExpr (BVType w) -> + ImplM vars s r (ps :> LLVMPointerType w + :> LLVMPointerType w) (ps :> LLVMPointerType w) + (LLVMArrayPerm w, LLVMBlockPerm w) +implLLVMArrayCellGet x ap cell = + if atomicPermIsCopyable (Perm_LLVMArray ap) then + implLLVMArrayCellCopy x ap cell >>> + return (ap, llvmArrayCellPerm ap cell) + else + implLLVMArrayCellBorrow x ap cell + -- | Return a cell that has been borrowed from an array permission, where the -- array permission is on the top of the stack and the cell permission borrowed -- from it is just below it @@ -3885,12 +3905,14 @@ implLLVMArrayCellReturn x ap cell = -- sub-array just beneath it. Return the remainder of @ap@. implLLVMArrayBorrow :: (1 <= w, KnownNat w, NuMatchingAny1 r) => - ExprVar (LLVMPointerType w) -> LLVMArrayPerm w -> LLVMArrayPerm w -> + ExprVar (LLVMPointerType w) -> LLVMArrayPerm w -> + PermExpr (BVType w) -> PermExpr (BVType w) -> ImplM vars s r (ps :> LLVMPointerType w :> LLVMPointerType w) (ps :> LLVMPointerType w) (LLVMArrayPerm w) -implLLVMArrayBorrow x ap sub_ap = +implLLVMArrayBorrow x ap off len = + let sub_ap = llvmMakeSubArray ap off len in implTryProveBVProps x (llvmArrayContainsArray ap sub_ap) >>> - implSimplM Proxy (SImpl_LLVMArrayBorrow x ap sub_ap) >>> + implSimplM Proxy (SImpl_LLVMArrayBorrow x ap off len) >>> return (llvmArrayAddBorrow (llvmSubArrayBorrow ap sub_ap) $ llvmArrayRemArrayBorrows ap sub_ap) @@ -3899,12 +3921,14 @@ implLLVMArrayBorrow x ap sub_ap = -- it. Return the remainder of @ap@ that is on top of the stack. implLLVMArrayCopy :: (1 <= w, KnownNat w, NuMatchingAny1 r) => - ExprVar (LLVMPointerType w) -> LLVMArrayPerm w -> LLVMArrayPerm w -> + ExprVar (LLVMPointerType w) -> LLVMArrayPerm w -> + PermExpr (BVType w) -> PermExpr (BVType w) -> ImplM vars s r (ps :> LLVMPointerType w :> LLVMPointerType w) (ps :> LLVMPointerType w) () -implLLVMArrayCopy x ap sub_ap = - implTryProveBVProps x (llvmArrayContainsArray ap sub_ap) >>> - implSimplM Proxy (SImpl_LLVMArrayCopy x ap sub_ap) +implLLVMArrayCopy x ap off len = + implTryProveBVProps x (llvmArrayContainsArray ap $ + llvmMakeSubArray ap off len) >>> + implSimplM Proxy (SImpl_LLVMArrayCopy x ap off len) -- | Copy or borrow a sub-array from an array @ap@, depending on whether @ap@ is -- copyable, assuming @ap@ is on top of the stack. Leave the remainder of @ap@ @@ -3912,14 +3936,14 @@ implLLVMArrayCopy x ap sub_ap = -- @ap@ that was left on top of the stack. implLLVMArrayGet :: (1 <= w, KnownNat w, NuMatchingAny1 r) => - ExprVar (LLVMPointerType w) -> LLVMArrayPerm w -> LLVMArrayPerm w -> + ExprVar (LLVMPointerType w) -> LLVMArrayPerm w -> + PermExpr (BVType w) -> PermExpr (BVType w) -> ImplM vars s r (ps :> LLVMPointerType w :> LLVMPointerType w) (ps :> LLVMPointerType w) (LLVMArrayPerm w) -implLLVMArrayGet x ap sub_ap +implLLVMArrayGet x ap off len | atomicPermIsCopyable (Perm_LLVMArray ap) = - implLLVMArrayCopy x ap sub_ap >>> return ap -implLLVMArrayGet x ap sub_ap = - implLLVMArrayBorrow x ap sub_ap + implLLVMArrayCopy x ap off len >>> return ap +implLLVMArrayGet x ap off len = implLLVMArrayBorrow x ap off len -- | Return a borrowed sub-array to an array as per 'SImpl_LLVMArrayReturn', @@ -3937,9 +3961,10 @@ implLLVMArrayReturn x ap ret_ap = pure (llvmArrayRemBorrow (llvmSubArrayBorrow ap ret_ap) $ llvmArrayAddArrayBorrows ap ret_ap) --- | Add a borrow to an LLVM array permission, failing if that is not possible --- because the borrow is not in range of the array. The permission that is --- borrowed is left on top of the stack and returned as a return value. +-- | Add a borrow to an LLVM array permission by borrowing its corresponding +-- permission, failing if that is not possible because the borrow is not in +-- range of the array. The permission that is borrowed is left on top of the +-- stack and returned as a return value. implLLVMArrayBorrowBorrow :: (1 <= w, KnownNat w, NuMatchingAny1 r) => ExprVar (LLVMPointerType w) -> LLVMArrayPerm w -> LLVMArrayBorrow w -> @@ -3949,13 +3974,11 @@ implLLVMArrayBorrowBorrow x ap (FieldBorrow cell) = implLLVMArrayCellBorrow x ap cell >>>= \(ap',bp) -> implSwapM x (ValPerm_LLVMBlock bp) x (ValPerm_LLVMArray ap') >>> return (ValPerm_LLVMBlock bp) -implLLVMArrayBorrowBorrow x ap b@(RangeBorrow _) = - let p = permForLLVMArrayBorrow ap b - ValPerm_Conj1 (Perm_LLVMArray sub_ap) = p - ap' = llvmArrayAddBorrow b ap in - implLLVMArrayBorrow x ap' sub_ap >>> - implSwapM x p x (ValPerm_Conj1 $ Perm_LLVMArray ap') >>> - pure p +implLLVMArrayBorrowBorrow x ap (RangeBorrow (BVRange cell len)) = + let off = llvmArrayCellToAbsOffset ap cell + p = ValPerm_LLVMArray $ llvmMakeSubArray ap off len in + implLLVMArrayBorrow x ap off len >>>= \ap' -> + implSwapM x p x (ValPerm_LLVMArray ap') >>> return p -- | Return a borrow to an LLVM array permission, assuming the array is at the -- top of the stack and the borrowed permission, which should be that returned @@ -4078,9 +4101,9 @@ implElimLLVMBlock x bp@(LLVMBlockPerm { llvmBlockShape = PExpr_PtrShape _ _ _ }) -- For a field shape, eliminate to a field permission implElimLLVMBlock x bp@(LLVMBlockPerm { llvmBlockShape = - PExpr_FieldShape (LLVMFieldShape p) }) = - implSimplM Proxy (SImpl_ElimLLVMBlockField x $ fromJust $ - llvmBlockPermToField (exprLLVMTypeWidth p) bp) + PExpr_FieldShape (LLVMFieldShape p) }) + | Just fp <- llvmBlockPermToField (exprLLVMTypeWidth p) bp = + implSimplM Proxy (SImpl_ElimLLVMBlockField x fp) -- For an array shape of the right length, eliminate to an array permission implElimLLVMBlock x bp @@ -4213,16 +4236,16 @@ implElimLLVMBlockForOffset x bp imprecise_p off mb_p = -- contains @off@, in the sense of 'bvPropHolds', it is selected. Otherwise, if -- the first 'Bool' flag is 'True', imprecise matches are allowed, which are -- permissions @pi@ that could contain @off@ in the sense of 'bvPropCouldHold', --- and all such imprecise matches are returned, using 'implCatchM' to try each --- possibility and fallback to the next one if it leads to a failure. If the --- selected @pi@ is a @memblock@ permission and the second 'Bool' flag is --- 'True', it is then repeatedly eliminated in the sense of 'implElimLLVMBlock' --- until a non-@memblock@ permission containing @off@ results, and this --- permission is then used as the new @pi@. The resulting permission @pi@ is --- then left on top of the stack and returned by the function, while the --- remaining permissions for @x@ are recombined with any other existing --- permissions for @x@. If no matches are found, fail using 'implFailVarM', --- citing the supplied permission as the one we are trying to prove. +-- and all of these matches are selected. Use 'implCatchM' to try each selected +-- @pi@ and fall back to the next one if it leads to a failure. If the selected +-- @pi@ is a @memblock@ permission and the second 'Bool' flag is 'True', it is +-- then repeatedly eliminated in the sense of 'implElimLLVMBlock' until a +-- non-@memblock@ permission containing @off@ results, and this permission is +-- then used as the new @pi@. The resulting permission @pi@ is then left on top +-- of the stack and returned by the function, while the remaining permissions +-- for @x@ are recombined with any other existing permissions for @x@. If no +-- matches are found, fail using 'implFailVarM', citing the supplied permission +-- as the one we are trying to prove. implGetLLVMPermForOffset :: (1 <= w, KnownNat w, NuMatchingAny1 r) => ExprVar (LLVMPointerType w) -> {- ^ the variable @x@ -} @@ -4247,7 +4270,9 @@ implGetLLVMPermForOffset x ps imprecise_p elim_blocks_p off mb_p = _ -> implFailVarM "implGetLLVMPermForOffset" x (ValPerm_Conj ps) mb_p) ixs -> foldr1 implCatchM $ flip map ixs $ \i -> - implGetConjM x ps i >>>= \ps' -> recombinePerm x (ValPerm_Conj ps') >>> + implExtractConjM x ps i >>> + let ps' = deleteNth i ps in + recombinePerm x (ValPerm_Conj ps') >>> case ps!!i of Perm_LLVMBlock bp | elim_blocks_p -> @@ -4991,9 +5016,23 @@ proveVarLLVMFieldH :: PermExpr (BVType w) -> Mb vars (LLVMFieldPerm w sz) -> ImplM vars s r (ps :> LLVMPointerType w) (ps :> LLVMPointerType w) () +proveVarLLVMFieldH x p off mb_fp = + implTraceM (\i -> + pretty "proveVarLLVMFieldH:" <+> permPretty i x <> colon <> + align (sep [PP.group (permPretty i p), + pretty "-o", + PP.group (permPretty i mb_fp)])) >>> + proveVarLLVMFieldH2 x p off mb_fp + +proveVarLLVMFieldH2 :: + (1 <= w, KnownNat w, 1 <= sz, KnownNat sz, NuMatchingAny1 r) => + ExprVar (LLVMPointerType w) -> AtomicPerm (LLVMPointerType w) -> + PermExpr (BVType w) -> Mb vars (LLVMFieldPerm w sz) -> + ImplM vars s r (ps :> LLVMPointerType w) (ps :> LLVMPointerType w) () + -- If we have a field permission of the correct size on the left, use it to -- prove the field permission on the right -proveVarLLVMFieldH x (Perm_LLVMField fp) off mb_fp +proveVarLLVMFieldH2 x (Perm_LLVMField fp) off mb_fp | bvEq (llvmFieldOffset fp) off , Just Refl <- testEquality (llvmFieldSize fp) (mbLLVMFieldSize mb_fp) = -- Step 1: make sure to have a variable for the contents @@ -5029,32 +5068,42 @@ proveVarLLVMFieldH x (Perm_LLVMField fp) off mb_fp return () -- If we have a block permission on the left, eliminate it -proveVarLLVMFieldH x (Perm_LLVMBlock bp) off mb_fp = +proveVarLLVMFieldH2 x (Perm_LLVMBlock bp) off mb_fp = implElimLLVMBlockForOffset x bp True off (mbValPerm_LLVMField mb_fp) >>>= \p -> proveVarLLVMFieldH x p off mb_fp --- If we have a copyable array permission on the left such that @off@ matches an --- index into that array permission, copy the corresponding cell -proveVarLLVMFieldH x p@(Perm_LLVMArray ap) off mb_fp +-- If we have an array permission on the left such that @off@ matches an index +-- into that array permission and mb_fp fits into the cell of that index, copy +-- or borrow the corresponding cell and recurse +proveVarLLVMFieldH2 x (Perm_LLVMArray ap) off mb_fp | Just ix <- matchLLVMArrayIndex ap off , cell <- llvmArrayIndexCell ix - , atomicPermIsCopyable p = - implLLVMArrayCellCopy x ap cell >>> - recombinePerm x (ValPerm_LLVMArray ap) >>> - proveVarLLVMFieldH x (Perm_LLVMBlock $ llvmArrayCellPerm ap cell) off mb_fp - --- If we have a non-copyable array permission on the left such that @off@ --- matches an index into that array permission, borrow the corresponding cell -proveVarLLVMFieldH x (Perm_LLVMArray ap) off mb_fp + , sz_int <- intValue (mbLLVMFieldSize mb_fp) `div` 8 + , BV.asUnsigned (llvmArrayIndexOffset ix) + sz_int <= (toInteger $ + llvmArrayStride ap) = + implLLVMArrayCellGet x ap cell >>>= \(ap', bp) -> + recombinePerm x (ValPerm_LLVMArray ap') >>> + proveVarLLVMFieldH x (Perm_LLVMBlock bp) off mb_fp + +-- If we have an array on the left with a sub-array of the same size as mb_fp, +-- prove that sub-array, convert it to a field, and recurse +proveVarLLVMFieldH2 x (Perm_LLVMArray ap) off mb_fp | Just ix <- matchLLVMArrayIndex ap off - , cell <- llvmArrayIndexCell ix = - implLLVMArrayCellBorrow x ap cell >>> - recombinePerm x (ValPerm_LLVMArray $ - llvmArrayAddBorrow (FieldBorrow cell) ap) >>> - proveVarLLVMFieldH x (Perm_LLVMBlock $ llvmArrayCellPerm ap cell) off mb_fp + , BV.BV 0 <- llvmArrayIndexOffset ix + , sz <- mbLLVMFieldSize mb_fp + , num_cells <- intValue sz `div` llvmArrayStrideBits ap + , cell <- llvmArrayIndexCell ix + , sub_ap <- ap { llvmArrayOffset = llvmArrayCellToAbsOffset ap cell, + llvmArrayLen = bvInt num_cells, + llvmArrayBorrows = [] } + , Just fp <- llvmArrayToField sz sub_ap = + mbVarsM sub_ap >>>= \mb_sub_ap -> + proveVarLLVMArray_FromArray x ap mb_sub_ap >>> + implSimplM Proxy (SImpl_LLVMArrayToField x sub_ap sz) >>> + proveVarLLVMFieldH x (Perm_LLVMField fp) off mb_fp -- If none of the above cases match, then fail -proveVarLLVMFieldH x p _ mb_fp = +proveVarLLVMFieldH2 x p _ mb_fp = implFailVarM "proveVarLLVMFieldH" x (ValPerm_Conj1 p) (mbValPerm_LLVMField mb_fp) @@ -5097,6 +5146,11 @@ proveVarLLVMArrayH x _ psubst ps mb_ap -- Otherwise, look for any permission the could contain the offset of mb_ap proveVarLLVMArrayH x first_p _ ps mb_ap = + implTraceM (\i -> + pretty "proveVarLLVMArrayH:" <+> permPretty i x <> colon <> + align (sep [PP.group (permPretty i (ValPerm_Conj ps)), + pretty "-o", + PP.group (permPretty i mb_ap)])) >>> partialSubstForceM (mbLLVMArrayOffset mb_ap) "proveVarLLVMArray: incomplete array offset" >>>= \off -> implGetLLVMPermForOffset x ps first_p True off @@ -5220,19 +5274,16 @@ proveVarLLVMArray_FromArray1 x ps ap_lhs off len bs mb_ap -- If ap_lhs starts before ap, then borrow or copy the portion we are going -- to use, and otherwise just use ap_lhs as is (if bvEq (llvmArrayOffset ap_lhs) off then return ap_lhs else - (let ap_lhs' = ap_lhs { llvmArrayOffset = off, llvmArrayLen = len' } in - implLLVMArrayGet x ap_lhs ap_lhs' >>>= \ap_lhs'' -> - recombinePerm x (ValPerm_LLVMArray ap_lhs'') >>> - return ap_lhs')) >>>= \ap_lhs' -> + (implLLVMArrayGet x ap_lhs off len' >>>= \ap_lhs' -> + recombinePerm x (ValPerm_LLVMArray ap_lhs') >>> + return (llvmMakeSubArray ap_lhs off len'))) >>>= \ap_lhs' -> -- Recursively prove ap with length len' and borrows that could be in the -- first portion of ap proveVarLLVMArray_FromArray2 x ap_lhs' len' bs_first mb_ap >>>= \ap' -> -- Prove ap with the remaining offset, length, and borrows - let ap_rest = ap' { llvmArrayLen = bvSub len len', - llvmArrayOffset = bvAdd off len', - llvmArrayBorrows = bs_rest } in + let ap_rest = llvmMakeSubArray ap' off len in mbVarsM ap_rest >>>= \mb_ap_rest -> getAtomicPerms x >>>= \ps' -> implPushM x (ValPerm_Conj ps') >>> @@ -5248,8 +5299,8 @@ proveVarLLVMArray_FromArray1 x ps ap_lhs off len bs mb_ap -- Otherwise, borrow or copy len bytes of ap_lhs and recurse proveVarLLVMArray_FromArray1 x _ ap_lhs off len bs mb_ap = - let ap_lhs' = ap_lhs { llvmArrayOffset = off, llvmArrayLen = len } in - implLLVMArrayGet x ap_lhs ap_lhs' >>>= \ap_lhs'' -> + let ap_lhs' = llvmMakeSubArray ap_lhs off len in + implLLVMArrayGet x ap_lhs off len >>>= \ap_lhs'' -> recombinePerm x (ValPerm_LLVMArray ap_lhs'') >>> proveVarLLVMArray_FromArray2 x ap_lhs' len bs mb_ap @@ -5265,12 +5316,29 @@ proveVarLLVMArray_FromArray2 :: ImplM vars s r (ps :> LLVMPointerType w) (ps :> LLVMPointerType w) (LLVMArrayPerm w) +proveVarLLVMArray_FromArray2 x ap_lhs len bs mb_ap = + implTraceM (\info -> + pretty "proveVarLLVMArray_FromArray2:" <+> + permPretty info x <> colon <> + align (sep [permPretty info (ValPerm_LLVMArray ap_lhs), + pretty "-o", + PP.group (permPretty info mb_ap)])) >>> + proveVarLLVMArray_FromArray2H x ap_lhs len bs mb_ap + +-- | The implementation of 'proveVarLLVMArray_FromArray2' +proveVarLLVMArray_FromArray2H :: + (1 <= w, KnownNat w, NuMatchingAny1 r) => ExprVar (LLVMPointerType w) -> + LLVMArrayPerm w -> PermExpr (BVType w) -> [LLVMArrayBorrow w] -> + Mb vars (LLVMArrayPerm w) -> + ImplM vars s r (ps :> LLVMPointerType w) (ps :> LLVMPointerType w) + (LLVMArrayPerm w) + -- If there is a borrow in ap_lhs that is not in ap, return it to ap_lhs -- -- FIXME: when an array ap_ret is being borrowed from ap_lhs, this code requires -- all of it to be returned, with no borrows, even though it could be that ap -- allows some of ap_ret to be borrowed -proveVarLLVMArray_FromArray2 x ap_lhs len bs mb_ap +proveVarLLVMArray_FromArray2H x ap_lhs len bs mb_ap | Just b <- find (flip notElem bs) (llvmArrayBorrows ap_lhs) = -- Prove the rest of ap with b borrowed @@ -5289,7 +5357,7 @@ proveVarLLVMArray_FromArray2 x ap_lhs len bs mb_ap -- If there is a borrow in ap that is not in ap_lhs, borrow it from ap_lhs. Note -- the assymmetry with the previous case: we only add borrows if we definitely -- have to, but we remove borrows if we might have to. -proveVarLLVMArray_FromArray2 x ap_lhs len bs mb_ap +proveVarLLVMArray_FromArray2H x ap_lhs len bs mb_ap | Just b <- find (flip notElem (llvmArrayBorrows ap_lhs)) bs = -- Prove the rest of ap without b borrowed @@ -5306,7 +5374,7 @@ proveVarLLVMArray_FromArray2 x ap_lhs len bs mb_ap -- If we get here then ap_lhs and ap have the same borrows, offset, length, and -- stride, so equalize their modalities, prove the shape of mb_ap from that of -- ap_lhs, rearrange their borrows, and we are done -proveVarLLVMArray_FromArray2 x ap_lhs _ bs mb_ap = +proveVarLLVMArray_FromArray2H x ap_lhs _ bs mb_ap = -- Coerce the rw modality of ap_lhs to that of mb_ap, if possibe equalizeRWs x (\rw -> ValPerm_LLVMArray $ ap_lhs { llvmArrayRW = rw }) (llvmArrayRW ap_lhs) (mbLLVMArrayRW mb_ap) @@ -5580,8 +5648,9 @@ proveVarLLVMBlocks1 x ps psubst (mb_bp:mb_bps) _ -> False) ps , Perm_LLVMBlock bp <- ps!!i = - -- Copy or extract the memblock perm we chose to the top of the stack - implGetSwapConjM x ps i >>>= \ps' -> + -- Move the memblock perm we chose to the top of the stack + implExtractSwapConjM x ps i >>> + let ps' = deleteNth i ps in -- Make the input block have the required modalities equalizeBlockModalities x bp mb_bp >>>= \bp' -> @@ -5892,32 +5961,30 @@ proveVarLLVMBlocks2 x ps psubst mb_bp mb_sh mb_bps -- Move the pointer permission we proved to the top of the stack getTopDistPerm x >>>= \(ValPerm_Conj ps') -> - let i = length mb_bps in - implExtractSwapConjM x ps' i >>> + implExtractSwapConjM x ps' 0 >>> -- Use the SImpl_IntroLLVMBlockPtr rule to prove the required memblock perm partialSubstForceM mb_bp "proveVarLLVMBlocks" >>>= \bp -> implSimplM Proxy (SImpl_IntroLLVMBlockPtr x bp) >>> -- Finally, move the memblock perm we proved back into position - implSwapInsertConjM x (Perm_LLVMBlock bp) (deleteNth i ps') 0 + implSwapInsertConjM x (Perm_LLVMBlock bp) (tail ps') 0 -- If proving a field shape, prove the remaining blocks and then prove the -- corresponding field permission proveVarLLVMBlocks2 x ps psubst mb_bp mb_sh mb_bps | [nuMP| PExpr_FieldShape (LLVMFieldShape mb_p) |] <- mb_sh - , sz <- mbExprLLVMTypeWidth mb_p = + , sz <- mbExprLLVMTypeWidth mb_p + , [nuP| Just mb_fp |] <- mbMapCl ($(mkClosed [| llvmBlockPermToField |]) + `clApply` toClosed sz) mb_bp = -- Recursively prove the remaining block permissions proveVarLLVMBlocks x ps psubst mb_bps >>> getTopDistPerm x >>>= \(ValPerm_Conj ps') -> -- Prove the corresponding field permission - proveVarImplInt x (mbMapCl - ($(mkClosed [| \sz' -> ValPerm_LLVMField . fromJust . - llvmBlockPermToField sz' |]) - `clApply` toClosed sz) mb_bp) >>> + proveVarImplInt x (mbValPerm_LLVMField mb_fp) >>> getTopDistPerm x >>>= \(ValPerm_LLVMField fp) -> -- Finally, convert the field perm to a block and move it into position diff --git a/heapster-saw/src/Verifier/SAW/Heapster/Permissions.hs b/heapster-saw/src/Verifier/SAW/Heapster/Permissions.hs index 19eef6c9da..d0d866b6c2 100644 --- a/heapster-saw/src/Verifier/SAW/Heapster/Permissions.hs +++ b/heapster-saw/src/Verifier/SAW/Heapster/Permissions.hs @@ -82,6 +82,7 @@ import Verifier.SAW.OpenTerm import Verifier.SAW.Heapster.CruUtil +import GHC.Stack import Debug.Trace @@ -3314,13 +3315,29 @@ llvmBlockPermToField :: (1 <= w, KnownNat w, 1 <= sz, KnownNat sz) => Maybe (LLVMFieldPerm w sz) llvmBlockPermToField sz bp | PExpr_FieldShape (LLVMFieldShape p) <- llvmBlockShape bp - , Just Refl <- testEquality sz (exprLLVMTypeWidth p) = + , Just Refl <- testEquality sz (exprLLVMTypeWidth p) + , bvEq (llvmBlockLen bp) (bvInt (intValue sz `div` 8)) = Just $ LLVMFieldPerm { llvmFieldRW = llvmBlockRW bp, llvmFieldLifetime = llvmBlockLifetime bp, llvmFieldOffset = llvmBlockOffset bp, llvmFieldContents = p } llvmBlockPermToField _ _ = Nothing +-- | Convert an array permission with total size @sz@ bits to a field permission +-- of size @sz@ bits, assuming it has no borrows +llvmArrayToField :: (1 <= w, KnownNat w, 1 <= sz, KnownNat sz) => + NatRepr sz -> LLVMArrayPerm w -> + Maybe (LLVMFieldPerm w sz) +llvmArrayToField sz ap + | bvEq (bvMult (llvmArrayStrideBits ap) (llvmArrayLen ap)) (bvInt $ + intValue sz) + , [] <- llvmArrayBorrows ap = + Just $ LLVMFieldPerm { llvmFieldRW = llvmArrayRW ap, + llvmFieldLifetime = llvmArrayLifetime ap, + llvmFieldOffset = llvmArrayOffset ap, + llvmFieldContents = ValPerm_True } +llvmArrayToField _ _ = Nothing + -- | Convert an array permission with no borrows to a block permission llvmArrayPermToBlock :: (1 <= w, KnownNat w) => LLVMArrayPerm w -> Maybe (LLVMBlockPerm w) @@ -3883,31 +3900,36 @@ llvmArrayAddArrayBorrows _ _ = error "llvmArrayAddArrayBorrows" -- | Find the position in the list of borrows of an 'LLVMArrayPerm' of a -- specific borrow -llvmArrayFindBorrow :: LLVMArrayBorrow w -> LLVMArrayPerm w -> Int +llvmArrayFindBorrow :: HasCallStack => LLVMArrayBorrow w -> LLVMArrayPerm w -> + Int llvmArrayFindBorrow b ap = case findIndex (== b) (llvmArrayBorrows ap) of Just i -> i Nothing -> error "llvmArrayFindBorrow: borrow not found" -- | Remove a borrow from an 'LLVMArrayPerm' -llvmArrayRemBorrow :: LLVMArrayBorrow w -> LLVMArrayPerm w -> LLVMArrayPerm w +llvmArrayRemBorrow :: HasCallStack => LLVMArrayBorrow w -> LLVMArrayPerm w -> + LLVMArrayPerm w llvmArrayRemBorrow b ap = ap { llvmArrayBorrows = deleteNth (llvmArrayFindBorrow b ap) (llvmArrayBorrows ap) } -- | Remove a sequence of borrows from an 'LLVMArrayPerm' -llvmArrayRemBorrows :: [LLVMArrayBorrow w] -> LLVMArrayPerm w -> LLVMArrayPerm w +llvmArrayRemBorrows :: HasCallStack => [LLVMArrayBorrow w] -> LLVMArrayPerm w -> + LLVMArrayPerm w llvmArrayRemBorrows bs ap = foldr llvmArrayRemBorrow ap bs -- | Remove all borrows from the second array to the first, assuming the one is -- an offset array as in 'llvmArrayIsOffsetArray' -llvmArrayRemArrayBorrows :: (1 <= w, KnownNat w) => LLVMArrayPerm w -> - LLVMArrayPerm w -> LLVMArrayPerm w +llvmArrayRemArrayBorrows :: HasCallStack => (1 <= w, KnownNat w) => + LLVMArrayPerm w -> LLVMArrayPerm w -> + LLVMArrayPerm w llvmArrayRemArrayBorrows ap sub_ap | Just cell_num <- llvmArrayIsOffsetArray ap sub_ap = - llvmArrayRemBorrows - (map (cellOffsetLLVMArrayBorrow cell_num) (llvmArrayBorrows sub_ap)) - ap + let sub_bs = + map (cellOffsetLLVMArrayBorrow cell_num) (llvmArrayBorrows sub_ap) + bs' = filter (flip notElem sub_bs) $ llvmArrayBorrows ap in + ap { llvmArrayBorrows = bs' } llvmArrayRemArrayBorrows _ _ = error "llvmArrayRemArrayBorrows" -- | Test if the borrows of an array can be permuted to another order @@ -3937,10 +3959,23 @@ cellOffsetLLVMArrayBorrow off (RangeBorrow rng) = matchLLVMArrayIndex :: (1 <= w, KnownNat w) => LLVMArrayPerm w -> PermExpr (BVType w) -> Maybe (LLVMArrayIndex w) matchLLVMArrayIndex ap o = - do let rel_off = bvSub o (llvmArrayOffset ap) - (ix, cell_off) <- - bvMatchFactorPlusConst (bytesToInteger $ llvmArrayStride ap) rel_off - return $ LLVMArrayIndex ix cell_off + do let rel_off = bvSub o (llvmArrayOffset ap) + (ix, cell_off) <- + bvMatchFactorPlusConst (bytesToInteger $ llvmArrayStride ap) rel_off + return $ LLVMArrayIndex ix cell_off + +-- | Test if a byte offset @o@ statically aligns with a cell boundary in an +-- array, i.e., whether +-- +-- > o - off = stride*cell +-- +-- for some @cell@. Return @cell@ on success. +matchLLVMArrayCell :: (1 <= w, KnownNat w) => LLVMArrayPerm w -> + PermExpr (BVType w) -> Maybe (PermExpr (BVType w)) +matchLLVMArrayCell ap off + | Just (LLVMArrayIndex cell (BV.BV 0)) <- matchLLVMArrayIndex ap off = + Just cell +matchLLVMArrayCell _ _ = Nothing -- | Return a list 'BVProp' stating that the cell(s) represented by an array -- borrow are in the "base" set of cells in an array, before the borrows are @@ -3967,7 +4002,7 @@ llvmArrayBorrowsDisjoint (RangeBorrow rng) (FieldBorrow ix) = llvmArrayBorrowsDisjoint (RangeBorrow rng1) (RangeBorrow rng2) = bvPropRangesDisjoint rng1 rng2 --- | Return a list of propositions stating that the field(s) represented by an +-- | Return a list of propositions stating that the cell(s) represented by an -- array borrow are in the set of fields of an array permission. This takes into -- account the current borrows on the array permission, which are fields that -- are /not/ currently in that array permission. @@ -4002,9 +4037,8 @@ llvmArrayCellsInArray ap rng = llvmArrayBorrowInArray ap (RangeBorrow rng) llvmArrayIsOffsetArray :: (1 <= w, KnownNat w) => LLVMArrayPerm w -> LLVMArrayPerm w -> Maybe (PermExpr (BVType w)) llvmArrayIsOffsetArray ap1 ap2 - | llvmArrayStride ap1 == llvmArrayStride ap2 - , Just (LLVMArrayIndex cell_num (BV.BV 0)) <- - matchLLVMArrayIndex ap1 (llvmArrayOffset ap2) = Just cell_num + | llvmArrayStride ap1 == llvmArrayStride ap2 = + matchLLVMArrayCell ap1 (llvmArrayOffset ap2) llvmArrayIsOffsetArray _ _ = Nothing -- | Build a 'BVRange' for the cells of a sub-array @ap2@ in @ap1@ @@ -4037,6 +4071,25 @@ llvmArrayContainsArray ap sub_ap = (llvmArrayRemArrayBorrows ap sub_ap) (llvmSubArrayRange ap sub_ap) +-- | Build a sub-array of an array permission at a given offset with a given +-- length, keeping only those borrows from the original array that could (in the +-- sense of 'bvPropCouldHold') overlap with the range of the sub-array. This +-- means that the borrows in the returned sub-array are an over-approximation of +-- the borrows that overlap with it, i.e., there could be borrows in the +-- returned sub-array permission that are not in its range. +llvmMakeSubArray :: (1 <= w, KnownNat w) => LLVMArrayPerm w -> + PermExpr (BVType w) -> PermExpr (BVType w) -> + LLVMArrayPerm w +llvmMakeSubArray ap off len + | Just cell <- matchLLVMArrayCell ap off + , cell_rng <- BVRange cell len = + ap { llvmArrayOffset = off, llvmArrayLen = len, + llvmArrayBorrows = + filter (all bvPropCouldHold . + llvmArrayBorrowsDisjoint (RangeBorrow cell_rng)) $ + llvmArrayBorrows ap } +llvmMakeSubArray _ _ _ = error "llvmMakeSubArray" + -- | Test if an atomic LLVM permission potentially allows a read or write of a -- given offset. If so, return a list of the propositions required for the read -- to be allowed, and whether the propositions definitely hold (as in diff --git a/heapster-saw/src/Verifier/SAW/Heapster/SAWTranslation.hs b/heapster-saw/src/Verifier/SAW/Heapster/SAWTranslation.hs index 35a14d5c9d..86cfcdc7c2 100644 --- a/heapster-saw/src/Verifier/SAW/Heapster/SAWTranslation.hs +++ b/heapster-saw/src/Verifier/SAW/Heapster/SAWTranslation.hs @@ -2379,8 +2379,12 @@ translateSimplImpl (ps0 :: Proxy ps0) mb_simpl m = case mbMatch mb_simpl of pctx :>: typeTransF ttrans (transTerms ptrans)) m - [nuMP| SImpl_LLVMArrayCopy _ mb_ap mb_sub_ap |] -> - do let _w = natVal2 mb_ap + [nuMP| SImpl_LLVMArrayCopy _ mb_ap _ _ |] -> + do let mb_sub_ap = + case mbSimplImplOut mb_simpl of + [nuP| _ :>: VarAndPerm _ (ValPerm_LLVMArray sub_ap) :>: _ |] -> + sub_ap + _ -> error "translateSimplImpl: SImpl_LLVMArrayCopy: unexpected perms" sub_ap_tp_trans <- translate mb_sub_ap rng_trans <- translate $ mbMap2 llvmSubArrayRange mb_ap mb_sub_ap -- let mb_sub_borrows = fmap llvmArrayBorrows mb_sub_ap @@ -2399,8 +2403,13 @@ translateSimplImpl (ps0 :: Proxy ps0) mb_simpl m = case mbMatch mb_simpl of :>: ptrans_array) m - [nuMP| SImpl_LLVMArrayBorrow _ mb_ap mb_sub_ap |] -> - do sub_ap_tp_trans <- translate mb_sub_ap + [nuMP| SImpl_LLVMArrayBorrow _ mb_ap _ _ |] -> + do let mb_sub_ap = + case mbSimplImplOut mb_simpl of + [nuP| _ :>: VarAndPerm _ (ValPerm_LLVMArray sub_ap) :>: _ |] -> + sub_ap + _ -> error "translateSimplImpl: SImpl_LLVMArrayCopy: unexpected perms" + sub_ap_tp_trans <- translate mb_sub_ap let mb_rng = mbMap2 llvmSubArrayRange mb_ap mb_sub_ap rng_trans <- translate mb_rng -- let mb_sub_borrows = fmap llvmArrayBorrows mb_sub_ap @@ -2493,13 +2502,11 @@ translateSimplImpl (ps0 :: Proxy ps0) mb_simpl m = case mbMatch mb_simpl of (\(pctx :>: ptrans) -> pctx :>: typeTransF ttrans [transTerm1 ptrans]) m -{- [nuMP| SImpl_LLVMArrayToField _ _ _ |] -> do ttrans <- translateSimplImplOutHead mb_simpl withPermStackM id (\(pctx :>: _) -> pctx :>: typeTransF ttrans []) m --} [nuMP| SImpl_LLVMArrayEmpty x mb_ap |] -> do (w_term, _, elem_tp, ap_tp_trans) <- translateLLVMArrayPerm mb_ap From bb697a09feaec170f4d075403d02cceb6559a0a8 Mon Sep 17 00:00:00 2001 From: Eddy Westbrook Date: Sun, 26 Sep 2021 13:18:33 -0700 Subject: [PATCH 85/98] whoops, llvmMakeSubArray was keeping the borrows the could be disjoint from the sub-array instead of those the could overlap with it --- heapster-saw/src/Verifier/SAW/Heapster/Permissions.hs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/heapster-saw/src/Verifier/SAW/Heapster/Permissions.hs b/heapster-saw/src/Verifier/SAW/Heapster/Permissions.hs index d0d866b6c2..e244f10503 100644 --- a/heapster-saw/src/Verifier/SAW/Heapster/Permissions.hs +++ b/heapster-saw/src/Verifier/SAW/Heapster/Permissions.hs @@ -4085,7 +4085,7 @@ llvmMakeSubArray ap off len , cell_rng <- BVRange cell len = ap { llvmArrayOffset = off, llvmArrayLen = len, llvmArrayBorrows = - filter (all bvPropCouldHold . + filter (not . all bvPropHolds . llvmArrayBorrowsDisjoint (RangeBorrow cell_rng)) $ llvmArrayBorrows ap } llvmMakeSubArray _ _ _ = error "llvmMakeSubArray" From cf12e297205ae249a985de72c7737755dda8121a Mon Sep 17 00:00:00 2001 From: Eddy Westbrook Date: Mon, 27 Sep 2021 11:36:41 -0700 Subject: [PATCH 86/98] changed the way tagged union shapes are proved to always try to prove a tag first, thereby reducing the cases in which they bottom out into general disjunctions --- .../src/Verifier/SAW/Heapster/Implication.hs | 94 ++++++++++----- .../src/Verifier/SAW/Heapster/Permissions.hs | 110 +++++++++++++++--- 2 files changed, 160 insertions(+), 44 deletions(-) diff --git a/heapster-saw/src/Verifier/SAW/Heapster/Implication.hs b/heapster-saw/src/Verifier/SAW/Heapster/Implication.hs index d84c01e341..f69ab6b238 100644 --- a/heapster-saw/src/Verifier/SAW/Heapster/Implication.hs +++ b/heapster-saw/src/Verifier/SAW/Heapster/Implication.hs @@ -3500,39 +3500,44 @@ implCastStackM some_eqp = -- | Introduce a proof of @x:true@ onto the top of the stack, which is the same -- as an empty conjunction -introConjM :: NuMatchingAny1 r => ExprVar a -> ImplM vars s r (ps :> a) ps () +introConjM :: HasCallStack => NuMatchingAny1 r => + ExprVar a -> ImplM vars s r (ps :> a) ps () introConjM x = implSimplM Proxy (SImpl_IntroConj x) -- | Extract the @i@th atomic permission from the conjunct on the top of the -- stack and put it just below the top of the stack -implExtractConjM :: NuMatchingAny1 r => ExprVar a -> [AtomicPerm a] -> Int -> +implExtractConjM :: HasCallStack => NuMatchingAny1 r => + ExprVar a -> [AtomicPerm a] -> Int -> ImplM vars s r (ps :> a :> a) (ps :> a) () implExtractConjM x ps i = implSimplM Proxy (SImpl_ExtractConj x ps i) -- | Extract the @i@th atomic permission from the conjunct on the top of the -- stack and push it to the top of the stack; i.e., call 'implExtractConjM' and -- then swap the top two stack elements -implExtractSwapConjM :: NuMatchingAny1 r => ExprVar a -> [AtomicPerm a] -> Int -> +implExtractSwapConjM :: HasCallStack => NuMatchingAny1 r => + ExprVar a -> [AtomicPerm a] -> Int -> ImplM vars s r (ps :> a :> a) (ps :> a) () implExtractSwapConjM x ps i = implExtractConjM x ps i >>> implSwapM x (ValPerm_Conj1 $ ps!!i) x (ValPerm_Conj $ deleteNth i ps) -- | Combine the top two conjunctive permissions on the stack -implAppendConjsM :: NuMatchingAny1 r => ExprVar a -> +implAppendConjsM :: HasCallStack => NuMatchingAny1 r => ExprVar a -> [AtomicPerm a] -> [AtomicPerm a] -> ImplM vars s r (ps :> a) (ps :> a :> a) () implAppendConjsM x ps1 ps2 = implSimplM Proxy (SImpl_AppendConjs x ps1 ps2) -- | Split the conjuctive permissions on the top of the stack into the first @i@ -- and the remaining conjuncts after those -implSplitConjsM :: NuMatchingAny1 r => ExprVar a -> [AtomicPerm a] -> Int -> +implSplitConjsM :: HasCallStack => NuMatchingAny1 r => + ExprVar a -> [AtomicPerm a] -> Int -> ImplM vars s r (ps :> a :> a) (ps :> a) () implSplitConjsM x ps i = implSimplM Proxy (SImpl_SplitConjs x ps i) -- | Split the conjuctive permissions on the top of the stack into the first @i@ -- and the remaining conjuncts after those, and then swap them -implSplitSwapConjsM :: NuMatchingAny1 r => ExprVar a -> [AtomicPerm a] -> Int -> +implSplitSwapConjsM :: HasCallStack => NuMatchingAny1 r => + ExprVar a -> [AtomicPerm a] -> Int -> ImplM vars s r (ps :> a :> a) (ps :> a) () implSplitSwapConjsM x ps i = implSplitConjsM x ps i >>> @@ -3542,14 +3547,16 @@ implSplitSwapConjsM x ps i = -- assuming that conjunction contains the given atomic permissions and that the -- given conjunct is copyable, and put the copied atomic permission just below -- the top of the stack -implCopyConjM :: NuMatchingAny1 r => ExprVar a -> [AtomicPerm a] -> Int -> +implCopyConjM :: HasCallStack => NuMatchingAny1 r => + ExprVar a -> [AtomicPerm a] -> Int -> ImplM vars s r (ps :> a :> a) (ps :> a) () implCopyConjM x ps i = implSimplM Proxy (SImpl_CopyConj x ps i) -- | Copy the @i@th atomic permission in the conjunct on the top of the stack -- and push it to the top of the stack; i.e., call 'implCopyConjM' and then swap -- the top two stack elements -implCopySwapConjM :: NuMatchingAny1 r => ExprVar a -> [AtomicPerm a] -> Int -> +implCopySwapConjM :: HasCallStack => NuMatchingAny1 r => + ExprVar a -> [AtomicPerm a] -> Int -> ImplM vars s r (ps :> a :> a) (ps :> a) () implCopySwapConjM x ps i = implCopyConjM x ps i >>> @@ -3559,7 +3566,8 @@ implCopySwapConjM x ps i = -- top of the stack, leaving the extracted or copied permission just below the -- top of the stack and the remaining other permissions on top of the stack. -- Return the list of conjuncts remaining on top of the stack. -implGetConjM :: NuMatchingAny1 r => ExprVar a -> [AtomicPerm a] -> Int -> +implGetConjM :: HasCallStack => NuMatchingAny1 r => + ExprVar a -> [AtomicPerm a] -> Int -> ImplM vars s r (ps :> a :> a) (ps :> a) [AtomicPerm a] implGetConjM x ps i = if atomicPermIsCopyable (ps!!i) then @@ -3571,7 +3579,8 @@ implGetConjM x ps i = -- top of the stack, leaving the extracted or copied permission on top of the -- stack and the remaining other permissions just below it. Return the list of -- conjuncts remaining just below the top of the stack. -implGetSwapConjM :: NuMatchingAny1 r => ExprVar a -> [AtomicPerm a] -> Int -> +implGetSwapConjM :: HasCallStack => NuMatchingAny1 r => + ExprVar a -> [AtomicPerm a] -> Int -> ImplM vars s r (ps :> a :> a) (ps :> a) [AtomicPerm a] implGetSwapConjM x ps i = if atomicPermIsCopyable (ps!!i) then @@ -3581,7 +3590,8 @@ implGetSwapConjM x ps i = -- | Either extract or copy the @i@th atomic permission in the conjunct on the -- top of the stack, popping the remaining permissions -implGetPopConjM :: NuMatchingAny1 r => ExprVar a -> [AtomicPerm a] -> Int -> +implGetPopConjM :: HasCallStack => NuMatchingAny1 r => + ExprVar a -> [AtomicPerm a] -> Int -> ImplM vars s r (ps :> a) (ps :> a) () implGetPopConjM x ps i = if atomicPermIsCopyable (ps!!i) then @@ -3593,14 +3603,15 @@ implGetPopConjM x ps i = -- | If the top element of the stack is copyable, then copy it and pop it, and -- otherwise just leave it alone on top of the stack -implMaybeCopyPopM :: NuMatchingAny1 r => ExprVar a -> ValuePerm a -> +implMaybeCopyPopM :: HasCallStack => NuMatchingAny1 r => + ExprVar a -> ValuePerm a -> ImplM vars s r (ps :> a) (ps :> a) () implMaybeCopyPopM x p | permIsCopyable p = implCopyM x p >>> implPopM x p implMaybeCopyPopM _ _ = pure () -- | Insert an atomic permission below the top of the stack at the @i@th -- position in the conjunct on the top of the stack, where @i@ must be between -implInsertConjM :: NuMatchingAny1 r => ExprVar a -> +implInsertConjM :: HasCallStack => NuMatchingAny1 r => ExprVar a -> AtomicPerm a -> [AtomicPerm a] -> Int -> ImplM vars s r (ps :> a) (ps :> a :> a) () implInsertConjM x p ps i = implSimplM Proxy (SImpl_InsertConj x p ps i) @@ -3608,7 +3619,7 @@ implInsertConjM x p ps i = implSimplM Proxy (SImpl_InsertConj x p ps i) -- | Insert an atomic permission on the top of the stack into the @i@th position -- in the conjunct below it on the of the stack; that is, swap the top two -- permissions and call 'implInsertConjM' -implSwapInsertConjM :: NuMatchingAny1 r => ExprVar a -> +implSwapInsertConjM :: HasCallStack => NuMatchingAny1 r => ExprVar a -> AtomicPerm a -> [AtomicPerm a] -> Int -> ImplM vars s r (ps :> a) (ps :> a :> a) () implSwapInsertConjM x p ps i = @@ -5739,8 +5750,8 @@ proveVarLLVMBlocks1 x ps psubst mb_bps_in@(mb_bp:_) -- length 0 for this case, since eliminating on the left does not help prove -- these permissions. proveVarLLVMBlocks1 x ps psubst mb_bps_in@(mb_bp:_) - | Just off <- partialSubst psubst $ fmap llvmBlockOffset mb_bp - , Just len <- partialSubst psubst $ fmap llvmBlockLen mb_bp + | Just off <- partialSubst psubst $ mbLLVMBlockOffset mb_bp + , Just len <- partialSubst psubst $ mbLLVMBlockLen mb_bp , not (bvIsZero len) , rng <- BVRange off len , Just i <- findIndex (\case @@ -5756,7 +5767,7 @@ proveVarLLVMBlocks1 x ps psubst mb_bps_in@(mb_bp:_) -- operates by induction on the shape proveVarLLVMBlocks1 x ps psubst (mb_bp:mb_bps) = proveVarLLVMBlocks2 x ps psubst mb_bp (mbMatch $ - fmap llvmBlockShape mb_bp) mb_bps + mbLLVMBlockShape mb_bp) mb_bps -- | Stage 2 of 'proveVarLLVMBlocks'. See that comments on that function. The @@ -6044,31 +6055,52 @@ proveVarLLVMBlocks2 x ps psubst mb_bp mb_sh mb_bps implSwapInsertConjM x (Perm_LLVMBlock bp) ps'' 0 --- If proving a tagged union shape where we have an equality permission on the --- left that matches one of the disjuncts, prove that disjunct and or it up with --- the other disjuncts +-- If proving a tagged union shape, first prove an equality permission for the +-- tag and then use that equality permission to proveVarLLVMBlocks2 x ps psubst mb_bp _ mb_bps - | [nuMP| Just mb_tag_u |] <- mbMatch $ fmap (asTaggedUnionShape - . llvmBlockShape) mb_bp - , Just off <- partialSubst psubst $ fmap llvmBlockOffset mb_bp - , Just i <- mbLift $ fmap (findTaggedUnionIndexForPerms off ps) mb_tag_u - , mb_shs <- fmap taggedUnionDisjs mb_tag_u - , mb_sh <- fmap (!!i) mb_shs = + | Just [nuP| SomeTaggedUnionShape mb_tag_u |] <- mbLLVMBlockToTaggedUnion mb_bp + , mb_shs <- mbTaggedUnionDisjs mb_tag_u + , mb_tag_fp <- mbTaggedUnionExTagPerm mb_bp + , Just off <- partialSubst psubst $ mbLLVMBlockOffset mb_bp = + + -- Prove permission x:ptr((R,off) |-> eq(z)) with existential variable z to + -- get the tag value for the tagged union, then take it off the stack + withExtVarsM (proveVarLLVMField x ps off mb_tag_fp) >>>= \((), e_tag) -> + getTopDistPerm x >>>= \p' -> + recombinePerm x p' >>> + + -- Find the disjunct corresponding to e_tag, if there is one; otherwise, we + -- don't know which disjunct to use, so return each of them in turn, + -- combining them with implCatchM + (getEqualsExpr e_tag >>>= \case + (bvMatchConst -> Just tag_bv) + | Just i <- mbFindTaggedUnionIndex tag_bv mb_tag_u -> return i + _ -> + let len = + mbLift $ mbMapCl $(mkClosed [| length . + taggedUnionDisjs |]) mb_tag_u in + foldr1 implCatchM $ map return [0..len-1]) >>>= \i -> - -- Recursively prove the ith disjunct - proveVarLLVMBlocks x ps psubst + -- Get the permissions we now have for x and push them back to the top of + -- the stack + getAtomicPerms x >>>= \ps' -> + implPushM x (ValPerm_Conj ps') >>> + + -- Recursively prove the ith disjunct and all the rest of mb_bps + let mb_sh = mbTaggedUnionNthDisj i mb_tag_u in + proveVarLLVMBlocks x ps' psubst (mbMap2 (\bp sh -> bp { llvmBlockShape = sh }) mb_bp mb_sh : mb_bps) >>> -- Move the block permission with shape mb_sh to the top of the stack - getTopDistPerm x >>>= \(ValPerm_Conj ps') -> - implExtractSwapConjM x ps' 0 >>> + getTopDistPerm x >>>= \(ValPerm_Conj ps'') -> + implExtractSwapConjM x ps'' 0 >>> -- Finally, weaken the block permission to be the desired tagged union -- shape, and move it back into position partialSubstForceM mb_shs "proveVarLLVMBlock" >>>= \shs -> partialSubstForceM mb_bp "proveVarLLVMBlock" >>>= \bp -> implIntroOrShapeMultiM x bp shs i >>> - implSwapInsertConjM x (Perm_LLVMBlock bp) (tail ps') 0 + implSwapInsertConjM x (Perm_LLVMBlock bp) (tail ps'') 0 -- If proving a disjunctive shape, try to prove one of the disjuncts diff --git a/heapster-saw/src/Verifier/SAW/Heapster/Permissions.hs b/heapster-saw/src/Verifier/SAW/Heapster/Permissions.hs index e244f10503..cb7b2f113e 100644 --- a/heapster-saw/src/Verifier/SAW/Heapster/Permissions.hs +++ b/heapster-saw/src/Verifier/SAW/Heapster/Permissions.hs @@ -31,7 +31,6 @@ import Prelude hiding (pred) import Data.Char (isDigit) import Data.Maybe -import Data.Foldable (asum) import Data.List hiding (sort) import Data.List.NonEmpty (NonEmpty(..)) import qualified Data.List.NonEmpty as NonEmpty @@ -1797,6 +1796,19 @@ data LLVMBlockPerm w = mbLLVMBlockRW :: Mb ctx (LLVMBlockPerm w) -> Mb ctx (PermExpr RWModalityType) mbLLVMBlockRW = mbMapCl $(mkClosed [| llvmBlockRW |]) +-- | Get the offset-in-binding of a block permission in binding +mbLLVMBlockOffset :: Mb ctx (LLVMBlockPerm w) -> Mb ctx (PermExpr (BVType w)) +mbLLVMBlockOffset = mbMapCl $(mkClosed [| llvmBlockOffset |]) + +-- | Get the length-in-binding of a block permission in binding +mbLLVMBlockLen :: Mb ctx (LLVMBlockPerm w) -> Mb ctx (PermExpr (BVType w)) +mbLLVMBlockLen = mbMapCl $(mkClosed [| llvmBlockLen |]) + +-- | Get the shape-in-binding of a block permission in binding +mbLLVMBlockShape :: Mb ctx (LLVMBlockPerm w) -> + Mb ctx (PermExpr (LLVMShapeType w)) +mbLLVMBlockShape = mbMapCl $(mkClosed [| llvmBlockShape |]) + -- | An LLVM shape for a single pointer field of unknown size data LLVMFieldShape w = forall sz. (1 <= sz, KnownNat sz) => @@ -3745,17 +3757,48 @@ remLLVMBLockPermRange rng bp = -- determines which disjunct should be used. These shapes are represented as a -- list of the disjuncts, which are tagged with the bitvector values @bvi@ used -- in the equality permission. -data TaggedUnionShape w +data TaggedUnionShape w sz + = TaggedUnionShape (NonEmpty (BV sz, PermExpr (LLVMShapeType w))) + +-- | A 'TaggedUnionShape' with existentially quantified tag size +data SomeTaggedUnionShape w = forall sz. (1 <= sz, KnownNat sz) => - TaggedUnionShape (NonEmpty (BV sz, PermExpr (LLVMShapeType w))) + SomeTaggedUnionShape (TaggedUnionShape w sz) -- | Extract the disjunctive shapes from a 'TaggedUnionShape' -taggedUnionDisjs :: TaggedUnionShape w -> [PermExpr (LLVMShapeType w)] +taggedUnionDisjs :: TaggedUnionShape w sz -> [PermExpr (LLVMShapeType w)] taggedUnionDisjs (TaggedUnionShape disjs) = map snd $ NonEmpty.toList disjs +-- | Extract the disjunctive shapes from a 'TaggedUnionShape' in a binding +mbTaggedUnionDisjs :: Mb ctx (TaggedUnionShape w sz) -> + Mb ctx [PermExpr (LLVMShapeType w)] +mbTaggedUnionDisjs = mbMapCl $(mkClosed [| taggedUnionDisjs |]) + +-- | Get the @n@th disjunct of a 'TaggedUnionShape' in a binding +mbTaggedUnionNthDisj :: Int -> Mb ctx (TaggedUnionShape w sz) -> + Mb ctx (PermExpr (LLVMShapeType w)) +mbTaggedUnionNthDisj n_top = + mbMapCl ($(mkClosed [| \n -> (!!n) . taggedUnionDisjs |]) + `clApply` toClosed n_top) + +-- | Get the tags from a 'TaggedUnionShape' +taggedUnionTags :: TaggedUnionShape w sz -> [BV sz] +taggedUnionTags (TaggedUnionShape disjs) = map fst $ NonEmpty.toList disjs + +-- | Build a 'TaggedUnionShape' with a single disjunct +taggedUnionSingle :: BV sz -> PermExpr (LLVMShapeType w) -> + TaggedUnionShape w sz +taggedUnionSingle tag sh = TaggedUnionShape ((tag,sh) :| []) + +-- | Add a disjunct to the front of a 'TaggedUnionShape' +taggedUnionCons :: BV sz -> PermExpr (LLVMShapeType w) -> + TaggedUnionShape w sz -> TaggedUnionShape w sz +taggedUnionCons tag sh (TaggedUnionShape disjs) = + TaggedUnionShape $ NonEmpty.cons (tag,sh) disjs + -- | Convert a 'TaggedUnionShape' to the shape it represents -taggedUnionToShape :: TaggedUnionShape w -> PermExpr (LLVMShapeType w) +taggedUnionToShape :: TaggedUnionShape w sz -> PermExpr (LLVMShapeType w) taggedUnionToShape (TaggedUnionShape disjs) = foldr1 PExpr_OrShape $ NonEmpty.map snd disjs @@ -3780,17 +3823,56 @@ getShapeBVTag _ = Nothing -- | Test if a shape is a tagged union shape and, if so, convert it to the -- 'TaggedUnionShape' representation -asTaggedUnionShape :: PermExpr (LLVMShapeType w) -> Maybe (TaggedUnionShape w) +asTaggedUnionShape :: PermExpr (LLVMShapeType w) -> + Maybe (SomeTaggedUnionShape w) asTaggedUnionShape (PExpr_OrShape sh1 sh2) - | Just (SomeBV bv1) <- getShapeBVTag sh1 - , Just (TaggedUnionShape disjs2@((bv2,_) :| _)) <- asTaggedUnionShape sh2 - , Just Refl <- testEquality (natRepr bv1) (natRepr bv2) = - Just (TaggedUnionShape (NonEmpty.cons (bv1,sh1) disjs2)) + | Just (SomeBV tag1) <- getShapeBVTag sh1 + , Just (SomeTaggedUnionShape tag_u2) <- asTaggedUnionShape sh2 + , Just Refl <- testEquality (natRepr tag1) (natRepr tag_u2) = + Just $ SomeTaggedUnionShape $ taggedUnionCons tag1 sh1 tag_u2 asTaggedUnionShape sh - | Just (SomeBV bv) <- getShapeBVTag sh = - Just (TaggedUnionShape ((bv,sh) :| [])) + | Just (SomeBV tag) <- getShapeBVTag sh = + Just $ SomeTaggedUnionShape $ taggedUnionSingle tag sh asTaggedUnionShape _ = Nothing +-- | Try to convert a @memblock@ permission in a binding to a tagged union shape +-- in a binding +mbLLVMBlockToTaggedUnion :: Mb ctx (LLVMBlockPerm w) -> + Maybe (Mb ctx (SomeTaggedUnionShape w)) +mbLLVMBlockToTaggedUnion = + mbMaybe . mbMapCl $(mkClosed [| asTaggedUnionShape . llvmBlockShape |]) + +-- | Convert a @memblock@ permission with a union shape to a field permission +-- with an equality permission @eq(z)@ with evar @z@ for the tag +taggedUnionExTagPerm :: (1 <= sz, KnownNat sz) => LLVMBlockPerm w -> + Binding (BVType sz) (LLVMFieldPerm w sz) +taggedUnionExTagPerm bp = + nu $ \z -> LLVMFieldPerm { llvmFieldRW = llvmBlockRW bp, + llvmFieldLifetime = llvmBlockLifetime bp, + llvmFieldOffset = llvmBlockOffset bp, + llvmFieldContents = + ValPerm_Eq (PExpr_LLVMWord $ PExpr_Var z) } + +-- | Convert a tagged union shape in a binding to +mbTaggedUnionExTagPerm :: (1 <= sz, KnownNat sz) => Mb ctx (LLVMBlockPerm w) -> + Mb (ctx :> BVType sz) (LLVMFieldPerm w sz) +mbTaggedUnionExTagPerm = + mbCombine RL.typeCtxProxies . mbMapCl $(mkClosed [| taggedUnionExTagPerm |]) + +-- | Find a disjunct in a 'TaggedUnionShape' with the given tag +findTaggedUnionIndex :: BV.BV sz -> TaggedUnionShape w sz -> Maybe Int +findTaggedUnionIndex tag_bv (TaggedUnionShape disjs) = + findIndex (== tag_bv) $ map fst $ NonEmpty.toList disjs + +-- | Find a disjunct in a 'TaggedUnionShape' in a binding with the given tag +mbFindTaggedUnionIndex :: BV.BV sz -> Mb ctx (TaggedUnionShape w sz) -> + Maybe Int +mbFindTaggedUnionIndex tag_bv = + mbLift . mbMapCl ($(mkClosed [| findTaggedUnionIndex |]) + `clApply` toClosed tag_bv) + +-- FIXME: delete these? +{- -- | Find a disjunct in a 'TaggedUnionShape' that could be proven at the given -- offset from the given atomic permission, by checking if it is a field or -- block permission containing an equality permission to one of the tags. If @@ -3817,6 +3899,7 @@ findTaggedUnionIndexForPerms :: PermExpr (BVType w) -> TaggedUnionShape w -> Maybe Int findTaggedUnionIndexForPerms off ps tag_un = asum $ map (\p -> findTaggedUnionIndexForPerm off p tag_un) ps +-} -- | Convert an array cell number @cell@ to the byte offset for that cell, given @@ -6408,7 +6491,8 @@ data PermEnv = PermEnv { permEnvHints :: [Hint] } -$(mkNuMatching [t| forall w. TaggedUnionShape w |]) +$(mkNuMatching [t| forall w sz. TaggedUnionShape w sz |]) +$(mkNuMatching [t| forall w. SomeTaggedUnionShape w |]) $(mkNuMatching [t| forall ctx. PermVarSubst ctx |]) $(mkNuMatching [t| PermEnvFunEntry |]) $(mkNuMatching [t| SomeNamedPerm |]) From d2d04c43fe1b5ca38bb683b00fdec622cabaf496 Mon Sep 17 00:00:00 2001 From: Eddy Westbrook Date: Tue, 28 Sep 2021 15:59:43 -0700 Subject: [PATCH 87/98] re-imagined how solveForPermListImpl works, by having solveForPermListImplBlock delete all the BVRanges of perms on the left-hand size from the BVRange of the right-hande side, and then creating blocks with existentially-quantified shapes for those ranges --- .../src/Verifier/SAW/Heapster/Implication.hs | 157 +++++---- .../src/Verifier/SAW/Heapster/Permissions.hs | 320 +++++++++++------- 2 files changed, 294 insertions(+), 183 deletions(-) diff --git a/heapster-saw/src/Verifier/SAW/Heapster/Implication.hs b/heapster-saw/src/Verifier/SAW/Heapster/Implication.hs index f69ab6b238..28132cb19e 100644 --- a/heapster-saw/src/Verifier/SAW/Heapster/Implication.hs +++ b/heapster-saw/src/Verifier/SAW/Heapster/Implication.hs @@ -66,6 +66,18 @@ import Verifier.SAW.Heapster.GenMonad import GHC.Stack +-- * Helper functions (should be moved to Hobbits) + +-- | Append two existentially quantified 'RAssign' lists +apSomeRAssign :: Some (RAssign f) -> Some (RAssign f) -> Some (RAssign f) +apSomeRAssign (Some x) (Some y) = Some (RL.append x y) + +-- | Concatenate a list of existentially quantified 'RAssign' lists +concatSomeRAssign :: [Some (RAssign f)] -> Some (RAssign f) +concatSomeRAssign = foldl apSomeRAssign (Some MNil) +-- foldl is intentional, appending RAssign matches on the second argument + + ---------------------------------------------------------------------- -- * Equality Proofs ---------------------------------------------------------------------- @@ -2819,6 +2831,15 @@ withExtVarsM m = Just e -> e Nothing -> zeroOfType knownRepr) +-- | Run an implication computation with an additional context of existential +-- variables +withExtVarsMultiM :: KnownCruCtx vars' -> + ImplM (vars :++: vars') s r ps1 ps2 a -> + ImplM vars s r ps1 ps2 a +withExtVarsMultiM MNil m = m +withExtVarsMultiM (ctx :>: KnownReprObj) m = + withExtVarsMultiM ctx (withExtVarsM m >>>= \(a,_) -> return a) + -- | Perform either the first, second, or both computations with an 'implCatchM' -- between, depending on the recursion flag implRecFlagCaseM :: NuMatchingAny1 r => ImplM vars s r ps_out ps_in a -> @@ -4868,35 +4889,44 @@ proveVarLifetimeFunctor' x f args l mb_l psubst = case mbMatch mb_l of -- * Solving for Permission List Implications ---------------------------------------------------------------------- --- | A sequence of permissions in bindings that need to be proved -type NeededPerms vars = Some (RAssign (Compose (Mb vars) VarAndPerm)) - --- | Append two existentially quantified 'RAssign' lists -apSomeRAssign :: Some (RAssign f) -> Some (RAssign f) -> Some (RAssign f) -apSomeRAssign (Some x) (Some y) = Some (RL.append x y) +-- | A permission that needs to be proved for an implication, which has at least +-- those evars mentioned in @vars@ but possibly more +data NeededPerm vars a where + NeededPerm :: KnownCruCtx vars' -> ExprVar a -> + Mb (vars :++: vars') (ValuePerm a) -> + NeededPerm vars a --- | Concatenate a list of existentially quantified 'RAssign' lists -concatSomeRAssign :: [Some (RAssign f)] -> Some (RAssign f) -concatSomeRAssign = foldl apSomeRAssign (Some MNil) --- foldl is intentional, appending RAssign matches on the second argument - --- | Convert a 'NeededPerms' list to an 'ExDistPerms' -neededPermsToExDistPerms :: RAssign prx vars -> - RAssign (Compose (Mb vars) VarAndPerm) ps -> - Mb vars (DistPerms ps) -neededPermsToExDistPerms vars MNil = nuMulti (RL.map (\_-> Proxy) vars) (const MNil) -neededPermsToExDistPerms vars (ps :>: Compose mb_vap) = - mbMap2 (:>:) (neededPermsToExDistPerms vars ps) mb_vap +-- | A sequence of permissions in bindings that need to be proved +type NeededPerms vars = Some (RAssign (NeededPerm vars)) -- | A single needed permission -neededPerms1 :: Mb vars (ExprVar a) -> Mb vars (ValuePerm a) -> NeededPerms vars -neededPerms1 mb_x mb_p = Some (MNil :>: Compose (mbMap2 VarAndPerm mb_x mb_p)) +neededPerms1 :: ExprVar a -> Mb vars (ValuePerm a) -> NeededPerms vars +neededPerms1 x mb_p = Some (MNil :>: NeededPerm MNil x mb_p) + +-- | A single needed permission with a single existential variable +mbNeededPerms1 :: KnownRepr TypeRepr tp => ExprVar a -> + Mb (vars :> tp) (ValuePerm a) -> NeededPerms vars +mbNeededPerms1 x mb_p = + Some (MNil :>: NeededPerm (MNil :>: KnownReprObj) x mb_p) -- | Convert an existential 'DistPerms' not in a binding to a 'NeededPerms' someDistPermsToNeededPerms :: RAssign Proxy vars -> Some DistPerms -> NeededPerms vars someDistPermsToNeededPerms prxs = - fmapF $ RL.map (Compose . nuMulti prxs . const) + fmapF $ RL.map (\(VarAndPerm x p) -> + NeededPerm MNil x (nuMulti prxs (const p))) + +-- | Prove the permission represented by a 'NeededPerm' +proveNeededPerm :: NuMatchingAny1 r => NeededPerm vars a -> + ImplM vars s r (ps :> a) ps () +proveNeededPerm (NeededPerm ctx x mb_p) = + withExtVarsMultiM ctx $ proveVarImpl x mb_p + +-- | Prove the permission represented by a 'NeededPerm' +proveNeededPerms :: NuMatchingAny1 r => RAssign (NeededPerm vars) ps' -> + ImplM vars s r (ps :++: ps') ps () +proveNeededPerms MNil = return () +proveNeededPerms (ps :>: p) = proveNeededPerms ps >>> proveNeededPerm p -- | If the second argument is an unset variable, set it to the first, otherwise -- do nothing @@ -4910,6 +4940,7 @@ tryUnifyVars x mb_x = case mbMatch mb_x of _ -> pure () _ -> pure () + -- | Find all the permissions that need to be added to the given list of -- permissions to prove the given block permission solveForPermListImplBlock :: (NuMatchingAny1 r, 1 <= w, KnownNat w) => @@ -4918,29 +4949,30 @@ solveForPermListImplBlock :: (NuMatchingAny1 r, 1 <= w, KnownNat w) => Mb vars (LLVMBlockPerm w) -> ImplM vars s r ps ps (NeededPerms vars) --- If the LHS is empty, return the input block permission -solveForPermListImplBlock MNil x mb_bp = - pure (neededPerms1 (fmap (const x) mb_bp) (fmap ValPerm_LLVMBlock mb_bp)) - --- If the LHS starts with a field permission, treat it like a block permission -solveForPermListImplBlock (ps_l :>: LOwnedPermField e fp_l) x mb_bp = - solveForPermListImplBlock - (ps_l :>: LOwnedPermBlock e (llvmFieldPermToBlock fp_l)) x mb_bp - --- If the LHS starts with a block permission bp', remove the range of bp' from --- the required bp and recurse on the results, setting the lifetime of our block --- permission to that of bp' if it is not already set -solveForPermListImplBlock (ps_l :>: LOwnedPermBlock (PExpr_Var y) bp_l) x mb_bp - | Just Refl <- testEquality x y - , rng_l <- llvmBlockRange bp_l - , [nuMP| Just mb_bps |] <- mbMatch $ fmap (remLLVMBLockPermRange rng_l) mb_bp = - tryUnifyVars (llvmBlockLifetime bp_l) (fmap llvmBlockLifetime mb_bp) >>> - tryUnifyVars (llvmBlockRW bp_l) (fmap llvmBlockRW mb_bp) >>> - concatSomeRAssign <$> mapM (solveForPermListImplBlock ps_l x) (mbList mb_bps) - --- Otherwise, recurse on the tail of the permission list -solveForPermListImplBlock (ps_l :>: _) x mb_bp = - solveForPermListImplBlock ps_l x mb_bp +solveForPermListImplBlock lops x mb_bp + | Just some_lop <- findLOwnedPermForVar x lops = + -- Use the modalities of some_lop to set the modalities of mb_bp, if needed + let (rw,l) = llvmLownedPermModalities some_lop in + tryUnifyVars rw (mbLLVMBlockRW mb_bp) >>> + tryUnifyVars l (mbLLVMBlockLifetime mb_bp) >>> + let rngs_lhs = lownedPermsOffsetsForLLVMVar x lops in + let mb_ex_bps = + fmap (\bp -> + -- Subtract all ranges of offsets in lops from that of mb_bp, + -- and, for each remaining range, create a memblock permission + -- with existential shape + map (\rng -> nu $ \z -> + (llvmBlockSetRange bp rng) + { llvmBlockShape = PExpr_Var z }) $ + bvRangesDelete (llvmBlockRange bp) rngs_lhs) mb_bp in + return $ concatSomeRAssign $ + map (\mb_ex_bp -> mbNeededPerms1 x $ mbValPerm_LLVMBlock $ + mbCombine RL.typeCtxProxies mb_ex_bp) $ + mbList mb_ex_bps + +-- If none of our lowned perms contain x, we need all of mb_bp +solveForPermListImplBlock _ x mb_bp = + return $ neededPerms1 x $ mbValPerm_LLVMBlock mb_bp -- | The second stage of 'solveForPermListImpl', after equality permissions have @@ -4949,31 +4981,23 @@ solveForPermListImpl1 :: NuMatchingAny1 r => LOwnedPerms ps_l -> Mb vars (LOwnedPerms ps_r) -> ImplM vars s r ps ps (NeededPerms vars) solveForPermListImpl1 ps_l mb_ps = case mbMatch mb_ps of - -- If the RHS is empty, we are done [nuMP| MNil |] -> pure (Some MNil) - -- If the RHS starts with a field perm, convert to a block perm and call - -- solveForPermListImplBlock - [nuMP| mb_ps_r :>: LOwnedPermField (PExpr_Var mb_x) mb_fp |] - | Right x <- mbNameBoundP mb_x - , mb_bp <- fmap llvmFieldPermToBlock mb_fp -> - do needed1 <- solveForPermListImplBlock ps_l x mb_bp - needed2 <- solveForPermListImpl1 ps_l mb_ps_r - pure (apSomeRAssign needed1 needed2) - - -- If the RHS starts with a block perm, call solveForPermListImplBlock - [nuMP| mb_ps_r :>: LOwnedPermBlock (PExpr_Var mb_x) mb_bp |] - | Right x <- mbNameBoundP mb_x -> - do needed1 <- solveForPermListImplBlock ps_l x mb_bp - needed2 <- solveForPermListImpl1 ps_l mb_ps_r - pure (apSomeRAssign needed1 needed2) - - -- Otherwise, we don't know what to do, so do nothing and return - _ -> - pure (Some MNil) + -- If the head of the RHS converts to a block permission, call + -- solveForPermListImplBlock, and recurse on the tail + [nuMP| mb_ps_r :>: mb_p_r |] + | Just [nuP| (mb_x, SomeLLVMBlockPerm mb_bp) |] <- + mbLownedPermVarBlockPerm mb_p_r + , Right x <- mbNameBoundP mb_x -> + do neededs1 <- solveForPermListImplBlock ps_l x mb_bp + neededs2 <- solveForPermListImpl1 ps_l mb_ps_r + pure (apSomeRAssign neededs1 neededs2) + -- Otherwise, drop the head and recurse on the tail + [nuMP| mb_ps_r :>: _ |] -> + solveForPermListImpl1 ps_l mb_ps_r -- | Determine what additional permissions from the variable permissions, if -- any, would be needed to prove one list of permissions implies another. Also @@ -6503,9 +6527,6 @@ proveVarAtomicImpl x ps mb_p = case mbMatch mb_p of let mb_ps_inL = fmap (const ps_inL) mb_ps_inR in solveForPermListImpl ps_inR mb_ps_inL >>>= \(Some neededs1) -> solveForPermListImpl ps_outL mb_ps_outR >>>= \(Some neededs2) -> - uses implStateVars cruCtxProxies >>>= \prxs -> - let mb_ps1 = neededPermsToExDistPerms prxs neededs1 - mb_ps2 = neededPermsToExDistPerms prxs neededs2 in -- Prove ps1 and ps2, which can have evars, and then look at the -- substitution instances of ps1 and ps2 that were actually proved on top @@ -6514,7 +6535,7 @@ proveVarAtomicImpl x ps mb_p = case mbMatch mb_p of -- on the LHSs and not arbitrary expressions getDistPerms >>>= \ps0_with_a -> let ps0 = RL.tail ps0_with_a in - proveVarsImplAppendInt (mbMap2 RL.append mb_ps1 mb_ps2) >>> + proveNeededPerms (RL.append neededs1 neededs2) >>> getTopDistPerms ps0_with_a (RL.append neededs1 neededs2) >>>= \ps12 -> let (ps1,ps2) = RL.split neededs1 neededs2 ps12 in partialSubstForceM mb_ps_outR "proveVarAtomicImpl" >>>= \ps_outR -> diff --git a/heapster-saw/src/Verifier/SAW/Heapster/Permissions.hs b/heapster-saw/src/Verifier/SAW/Heapster/Permissions.hs index cb7b2f113e..c619433803 100644 --- a/heapster-saw/src/Verifier/SAW/Heapster/Permissions.hs +++ b/heapster-saw/src/Verifier/SAW/Heapster/Permissions.hs @@ -719,21 +719,6 @@ findAtomicPermInList x pred plist = foldPermListAtomic x (\p rest -> if pred p then Just p else rest) Nothing plist --- FIXME: move this down below the mkNuMatching calls or move --- llvmAtomicPermToBlock up before them... or just remove this function -{- --- | Find a permission on a specific variable in a permission list that is --- equivalent to a block permission -findBlockPermInList :: ExprVar (LLVMPointerType w) -> - (LLVMBlockPerm w -> Bool) -> - PermExpr PermListType -> Maybe (LLVMBlockPerm w) -findBlockPermInList x pred plist = - foldPermListAtomic x (\p rest -> - case llvmAtomicPermToBlock p of - Just bp | pred bp -> Just bp - _ -> rest) Nothing plist --} - -- | A bitvector variable, possibly multiplied by a constant data BVFactor w where -- | A variable of type @'BVType' w@ multiplied by a constant @i@, which @@ -1251,6 +1236,54 @@ bvRangeSub :: (1 <= w, KnownNat w) => BVRange w -> PermExpr (BVType w) -> BVRange w bvRangeSub (BVRange off len) x = BVRange (bvSub off x) len +-- | Delete all offsets from the first 'BVRange' that are definitely (in the +-- sense of 'bvPropHolds') in the second, returning a list of 'BVRange's that +-- together describe the remaining offsets +bvRangeDelete :: (1 <= w, KnownNat w) => BVRange w -> BVRange w -> [BVRange w] +bvRangeDelete rng1 rng2 + -- If rng1 is a subset of rng2, return the empty set + | bvRangeSubset rng1 rng2 = [] +bvRangeDelete rng1 rng2 + -- If both endpoints of rng1 are in rng2 but it is not a subset of rng2, then + -- one of the ranges wrapped, and we return the range from the end of rng2 to + -- its beginning again + | bvInRange (bvRangeOffset rng1) rng2 && + bvInRange (bvRangeEnd rng1) rng2 = + [BVRange (bvRangeEnd rng2) (bvSub (bvInt 0) (bvRangeLength rng2))] +bvRangeDelete rng1 rng2 + -- If the beginning of rng1 is in rng2 but the above cases don't hold, then + -- rng2 removes some prefix of rng1, so return the range from the end of rng2 + -- to the end of rng1 + | bvInRange (bvRangeOffset rng1) rng2 = + [bvRangeSuffix (bvRangeEnd rng2) rng1] +bvRangeDelete rng1 rng2 + -- If the end of rng1 is in rng2 but the above cases don't hold, then rng2 + -- removes some suffix of rng1, so return the range from the beginnning of + -- rng1 to the beginning of rng2 + | bvInRange (bvRangeEnd rng1) rng2 = + [BVRange (bvRangeOffset rng1) + (bvSub (bvRangeOffset rng2) (bvRangeOffset rng1))] +bvRangeDelete rng1 rng2 + -- If we get here then both endpoints of rng1 are not in rng2, but rng2 sits + -- inside of rng1, so return the prefix of rng1 before rng2 and the suffix of + -- rng1 after rng2 + | off1 <- bvRangeOffset rng1 + , off2 <- bvRangeOffset rng2 + , end1 <- bvRangeEnd rng1 + , end2 <- bvRangeEnd rng2 + , bvInRange off2 rng1 = + [BVRange off1 (bvSub off2 off1), BVRange end2 (bvSub end1 end2)] +bvRangeDelete rng1 _ = + -- If we get here, then rng2 is completely disjoint from rng1, so return rng1 + [rng1] + +-- | Delete all offsets in any of a list of ranges from a range, yielding a list +-- of ranges of the remaining offsets +bvRangesDelete :: (1 <= w, KnownNat w) => BVRange w -> [BVRange w] -> + [BVRange w] +bvRangesDelete rng_top = + foldr (\rng_del rngs -> concatMap (flip bvRangeDelete rng_del) rngs) [rng_top] + -- | Build a bitvector expression from an integer bvInt :: (1 <= w, KnownNat w) => Integer -> PermExpr (BVType w) bvInt i = PExpr_BV [] $ BV.mkBV knownNat i @@ -1796,6 +1829,11 @@ data LLVMBlockPerm w = mbLLVMBlockRW :: Mb ctx (LLVMBlockPerm w) -> Mb ctx (PermExpr RWModalityType) mbLLVMBlockRW = mbMapCl $(mkClosed [| llvmBlockRW |]) +-- | Get the lifetime-in-binding of a block permission in binding +mbLLVMBlockLifetime :: Mb ctx (LLVMBlockPerm w) -> + Mb ctx (PermExpr LifetimeType) +mbLLVMBlockLifetime = mbMapCl $(mkClosed [| llvmBlockLifetime |]) + -- | Get the offset-in-binding of a block permission in binding mbLLVMBlockOffset :: Mb ctx (LLVMBlockPerm w) -> Mb ctx (PermExpr (BVType w)) mbLLVMBlockOffset = mbMapCl $(mkClosed [| llvmBlockOffset |]) @@ -1897,6 +1935,54 @@ lownedPermVar _ = Nothing lownedPermPerm :: LOwnedPerm a -> ValuePerm a lownedPermPerm = exprAndPermPerm . lownedPermExprAndPerm +-- | Convert the permission part of an 'LOwnedPerm' to a block permission on a +-- variable, if possible +lownedPermVarBlockPerm :: LOwnedPerm a -> Maybe (ExprVar a, SomeLLVMBlockPerm a) +lownedPermVarBlockPerm lop + | Just (x, perm_off) <- asVarOffset (lownedPermExpr lop) + , ValPerm_Conj1 p <- lownedPermPerm lop + , Just (SomeLLVMBlockPerm bp) <- llvmAtomicPermToSomeBlock p + , off <- llvmPermOffsetExpr perm_off = + Just (x, SomeLLVMBlockPerm (offsetLLVMBlockPerm off bp)) +lownedPermVarBlockPerm _ = Nothing + +-- | Convert the permission part of an 'LOwnedPerm' in a binding to a block +-- permission on a variable in a binding, if possible +mbLownedPermVarBlockPerm :: Mb ctx (LOwnedPerm a) -> + Maybe (Mb ctx (ExprVar a, SomeLLVMBlockPerm a)) +mbLownedPermVarBlockPerm = + mbMaybe . mbMapCl $(mkClosed [| lownedPermVarBlockPerm |]) + +-- | Get the read/write and lifetime modalities of an 'LOwnedPerm' of LLVM type +llvmLownedPermModalities :: LOwnedPerm (LLVMPointerType w) -> + (PermExpr RWModalityType, PermExpr LifetimeType) +llvmLownedPermModalities (LOwnedPermField _ fp) = + (llvmFieldRW fp, llvmFieldLifetime fp) +llvmLownedPermModalities (LOwnedPermArray _ ap) = + (llvmArrayRW ap, llvmArrayLifetime ap) +llvmLownedPermModalities (LOwnedPermBlock _ bp) = + (llvmBlockRW bp, llvmBlockLifetime bp) + +-- | Find an 'LOwnedPerm' for a particular variable in an 'LOwnedPerms' list +findLOwnedPermForVar :: ExprVar a -> LOwnedPerms ps -> Maybe (LOwnedPerm a) +findLOwnedPermForVar _ MNil = Nothing +findLOwnedPermForVar x (_ :>: lop) + | Just (y, _) <- asVarOffset (lownedPermExpr lop) + , Just Refl <- testEquality x y = Just lop +findLOwnedPermForVar x (lops :>: _) = findLOwnedPermForVar x lops + +-- | Find all 'LOwnedPerm's for a specific variable of LLVM pointer type in an +-- 'LOwnedPerms' list, and return the ranges of offsets that each of those cover +lownedPermsOffsetsForLLVMVar :: (1 <= w, KnownNat w) => + ExprVar (LLVMPointerType w) -> LOwnedPerms ps -> + [BVRange w] +lownedPermsOffsetsForLLVMVar _ MNil = [] +lownedPermsOffsetsForLLVMVar x (lops :>: lop) + | Just (y, SomeLLVMBlockPerm bp) <- lownedPermVarBlockPerm lop + , Just Refl <- testEquality x y = + llvmBlockRange bp : lownedPermsOffsetsForLLVMVar x lops +lownedPermsOffsetsForLLVMVar x (lops :>: _) = + lownedPermsOffsetsForLLVMVar x lops -- | A function permission is a set of input and output permissions inside a -- context of ghost variables @@ -2158,6 +2244,12 @@ mkLLVMPermOffset :: (1 <= w, KnownNat w) => PermExpr (BVType w) -> mkLLVMPermOffset off | bvIsZero off = NoPermOffset mkLLVMPermOffset off = LLVMPermOffset off +-- | Extract a bitvector offset expression from a 'PermOffset' of pointer type +llvmPermOffsetExpr :: (1 <= w, KnownNat w) => PermOffset (LLVMPointerType w) -> + PermExpr (BVType w) +llvmPermOffsetExpr NoPermOffset = bvInt 0 +llvmPermOffsetExpr (LLVMPermOffset e) = e + -- | Test two 'PermOffset's for semantic, not just syntactic, equality offsetsEq :: PermOffset a -> PermOffset a -> Bool offsetsEq NoPermOffset NoPermOffset = True @@ -2903,99 +2995,6 @@ instance PermPrettyF ExprAndPerm where permPrettyMF = permPrettyM -$(mkNuMatching [t| forall a . PermExpr a |]) -$(mkNuMatching [t| forall a . BVFactor a |]) -$(mkNuMatching [t| forall w. BVRange w |]) -$(mkNuMatching [t| forall w. BVProp w |]) -$(mkNuMatching [t| forall a . AtomicPerm a |]) -$(mkNuMatching [t| forall a . ValuePerm a |]) --- $(mkNuMatching [t| forall as. ValuePerms as |]) -$(mkNuMatching [t| forall a . VarAndPerm a |]) - -instance NuMatchingAny1 PermExpr where - nuMatchingAny1Proof = nuMatchingProof - -instance NuMatchingAny1 ValuePerm where - nuMatchingAny1Proof = nuMatchingProof - -instance NuMatchingAny1 VarAndPerm where - nuMatchingAny1Proof = nuMatchingProof - -$(mkNuMatching [t| forall w sz . LLVMFieldPerm w sz |]) -$(mkNuMatching [t| forall w . LLVMArrayPerm w |]) -$(mkNuMatching [t| forall w . LLVMBlockPerm w |]) -$(mkNuMatching [t| RWModality |]) -$(mkNuMatching [t| forall w . LLVMArrayIndex w |]) -$(mkNuMatching [t| forall w . LLVMArrayBorrow w |]) -$(mkNuMatching [t| forall w . LLVMFieldShape w |]) -$(mkNuMatching [t| forall w . LOwnedPerm w |]) -$(mkNuMatching [t| forall ghosts args ret. FunPerm ghosts args ret |]) -$(mkNuMatching [t| forall args ret. SomeFunPerm args ret |]) -$(mkNuMatching [t| forall ns. NameSortRepr ns |]) -$(mkNuMatching [t| forall ns args a. NameReachConstr ns args a |]) -$(mkNuMatching [t| forall ns args a. NamedPermName ns args a |]) -$(mkNuMatching [t| SomeNamedPermName |]) -$(mkNuMatching [t| forall b args w. NamedShape b args w |]) -$(mkNuMatching [t| forall b args w. NamedShapeBody b args w |]) -$(mkNuMatching [t| forall a. PermOffset a |]) -$(mkNuMatching [t| forall ns args a. NamedPerm ns args a |]) -$(mkNuMatching [t| forall b args a. OpaquePerm b args a |]) -$(mkNuMatching [t| forall args a reach. ReachMethods args a reach |]) -$(mkNuMatching [t| forall b reach args a. RecPerm b reach args a |]) -$(mkNuMatching [t| forall b args a. DefinedPerm b args a |]) -$(mkNuMatching [t| forall args a. LifetimeFunctor args a |]) -$(mkNuMatching [t| forall ps. LifetimeCurrentPerms ps |]) - - - -instance NuMatchingAny1 LOwnedPerm where - nuMatchingAny1Proof = nuMatchingProof - -instance NuMatchingAny1 DistPerms where - nuMatchingAny1Proof = nuMatchingProof - -instance Liftable RWModality where - mbLift mb_rw = case mbMatch mb_rw of - [nuMP| Write |] -> Write - [nuMP| Read |] -> Read - -instance Closable RWModality where - toClosed Write = $(mkClosed [| Write |]) - toClosed Read = $(mkClosed [| Read |]) - -instance Closable (NameSortRepr ns) where - toClosed (DefinedSortRepr b) = - $(mkClosed [| DefinedSortRepr |]) `clApply` toClosed b - toClosed (OpaqueSortRepr b) = - $(mkClosed [| OpaqueSortRepr |]) `clApply` toClosed b - toClosed (RecursiveSortRepr b reach) = - $(mkClosed [| RecursiveSortRepr |]) - `clApply` toClosed b `clApply` toClosed reach - -instance Liftable (NameSortRepr ns) where - mbLift = unClosed . mbLift . fmap toClosed - -instance Closable (NameReachConstr ns args a) where - toClosed NameReachConstr = $(mkClosed [| NameReachConstr |]) - toClosed NameNonReachConstr = $(mkClosed [| NameNonReachConstr |]) - -instance Liftable (NameReachConstr ns args a) where - mbLift = unClosed . mbLift . fmap toClosed - -instance Liftable (NamedPermName ns args a) where - mbLift (mbMatch -> [nuMP| NamedPermName n tp args ns r |]) = - NamedPermName (mbLift n) (mbLift tp) (mbLift args) (mbLift ns) (mbLift r) - -instance Liftable SomeNamedPermName where - mbLift (mbMatch -> [nuMP| SomeNamedPermName rpn |]) = - SomeNamedPermName $ mbLift rpn - -instance Liftable (ReachMethods args a reach) where - mbLift mb_x = case mbMatch mb_x of - [nuMP| ReachMethods transIdent |] -> - ReachMethods (mbLift transIdent) - [nuMP| NoReachMethods |] -> NoReachMethods - -- | Embed a 'ValuePerm' in a 'PermExpr' - like 'PExpr_ValPerm' but maps -- 'ValPerm_Var's to 'PExpr_Var's permToExpr :: ValuePerm a -> PermExpr (ValuePermType a) @@ -3444,13 +3443,6 @@ llvmAtomicPermToSomeBlock (Perm_LLVMBlock bp) = Just $ SomeLLVMBlockPerm $ bp llvmAtomicPermToSomeBlock _ = Nothing --- | Get the lifetime of an atomic permission, if it has one -llvmAtomicPermLifetime :: AtomicPerm a -> Maybe (PermExpr LifetimeType) -llvmAtomicPermLifetime (llvmAtomicPermToSomeBlock -> - Just (SomeLLVMBlockPerm bp)) = - Just $ llvmBlockLifetime bp -llvmAtomicPermLifetime _ = Nothing - -- | Get the offset of an atomic permission, if it has one llvmAtomicPermOffset :: AtomicPerm (LLVMPointerType w) -> Maybe (PermExpr (BVType w)) @@ -3470,6 +3462,11 @@ llvmAtomicPermRange p = fmap llvmBlockRange $ llvmAtomicPermToBlock p llvmBlockRange :: LLVMBlockPerm w -> BVRange w llvmBlockRange bp = BVRange (llvmBlockOffset bp) (llvmBlockLen bp) +-- | Set the range of an 'LLVMBlock' +llvmBlockSetRange :: LLVMBlockPerm w -> BVRange w -> LLVMBlockPerm w +llvmBlockSetRange bp (BVRange off len) = + bp { llvmBlockOffset = off, llvmBlockLen = len } + -- | Get the ending offset of a block permission llvmBlockEndOffset :: (1 <= w, KnownNat w) => LLVMBlockPerm w -> PermExpr (BVType w) @@ -6409,6 +6406,99 @@ instance AbstractNamedShape w (FunPerm ghosts args ret) where <*> abstractNSM perms_out +$(mkNuMatching [t| forall a . PermExpr a |]) +$(mkNuMatching [t| forall a . BVFactor a |]) +$(mkNuMatching [t| forall w. BVRange w |]) +$(mkNuMatching [t| forall w. BVProp w |]) +$(mkNuMatching [t| forall a . AtomicPerm a |]) +$(mkNuMatching [t| forall a . ValuePerm a |]) +-- $(mkNuMatching [t| forall as. ValuePerms as |]) +$(mkNuMatching [t| forall a . VarAndPerm a |]) + +instance NuMatchingAny1 PermExpr where + nuMatchingAny1Proof = nuMatchingProof + +instance NuMatchingAny1 ValuePerm where + nuMatchingAny1Proof = nuMatchingProof + +instance NuMatchingAny1 VarAndPerm where + nuMatchingAny1Proof = nuMatchingProof + +$(mkNuMatching [t| forall w sz . LLVMFieldPerm w sz |]) +$(mkNuMatching [t| forall w . LLVMArrayPerm w |]) +$(mkNuMatching [t| forall w . LLVMBlockPerm w |]) +$(mkNuMatching [t| RWModality |]) +$(mkNuMatching [t| forall w . LLVMArrayIndex w |]) +$(mkNuMatching [t| forall w . LLVMArrayBorrow w |]) +$(mkNuMatching [t| forall w . LLVMFieldShape w |]) +$(mkNuMatching [t| forall w . LOwnedPerm w |]) +$(mkNuMatching [t| forall ghosts args ret. FunPerm ghosts args ret |]) +$(mkNuMatching [t| forall args ret. SomeFunPerm args ret |]) +$(mkNuMatching [t| forall ns. NameSortRepr ns |]) +$(mkNuMatching [t| forall ns args a. NameReachConstr ns args a |]) +$(mkNuMatching [t| forall ns args a. NamedPermName ns args a |]) +$(mkNuMatching [t| SomeNamedPermName |]) +$(mkNuMatching [t| forall b args w. NamedShape b args w |]) +$(mkNuMatching [t| forall b args w. NamedShapeBody b args w |]) +$(mkNuMatching [t| forall a. PermOffset a |]) +$(mkNuMatching [t| forall ns args a. NamedPerm ns args a |]) +$(mkNuMatching [t| forall b args a. OpaquePerm b args a |]) +$(mkNuMatching [t| forall args a reach. ReachMethods args a reach |]) +$(mkNuMatching [t| forall b reach args a. RecPerm b reach args a |]) +$(mkNuMatching [t| forall b args a. DefinedPerm b args a |]) +$(mkNuMatching [t| forall args a. LifetimeFunctor args a |]) +$(mkNuMatching [t| forall ps. LifetimeCurrentPerms ps |]) +$(mkNuMatching [t| forall a. SomeLLVMBlockPerm a |]) + +instance NuMatchingAny1 LOwnedPerm where + nuMatchingAny1Proof = nuMatchingProof + +instance NuMatchingAny1 DistPerms where + nuMatchingAny1Proof = nuMatchingProof + +instance Liftable RWModality where + mbLift mb_rw = case mbMatch mb_rw of + [nuMP| Write |] -> Write + [nuMP| Read |] -> Read + +instance Closable RWModality where + toClosed Write = $(mkClosed [| Write |]) + toClosed Read = $(mkClosed [| Read |]) + +instance Closable (NameSortRepr ns) where + toClosed (DefinedSortRepr b) = + $(mkClosed [| DefinedSortRepr |]) `clApply` toClosed b + toClosed (OpaqueSortRepr b) = + $(mkClosed [| OpaqueSortRepr |]) `clApply` toClosed b + toClosed (RecursiveSortRepr b reach) = + $(mkClosed [| RecursiveSortRepr |]) + `clApply` toClosed b `clApply` toClosed reach + +instance Liftable (NameSortRepr ns) where + mbLift = unClosed . mbLift . fmap toClosed + +instance Closable (NameReachConstr ns args a) where + toClosed NameReachConstr = $(mkClosed [| NameReachConstr |]) + toClosed NameNonReachConstr = $(mkClosed [| NameNonReachConstr |]) + +instance Liftable (NameReachConstr ns args a) where + mbLift = unClosed . mbLift . fmap toClosed + +instance Liftable (NamedPermName ns args a) where + mbLift (mbMatch -> [nuMP| NamedPermName n tp args ns r |]) = + NamedPermName (mbLift n) (mbLift tp) (mbLift args) (mbLift ns) (mbLift r) + +instance Liftable SomeNamedPermName where + mbLift (mbMatch -> [nuMP| SomeNamedPermName rpn |]) = + SomeNamedPermName $ mbLift rpn + +instance Liftable (ReachMethods args a reach) where + mbLift mb_x = case mbMatch mb_x of + [nuMP| ReachMethods transIdent |] -> + ReachMethods (mbLift transIdent) + [nuMP| NoReachMethods |] -> NoReachMethods + + ---------------------------------------------------------------------- -- * Permission Environments ---------------------------------------------------------------------- From 08571949ffa7f9f73cfce920074d585e55f92424 Mon Sep 17 00:00:00 2001 From: Eddy Westbrook Date: Tue, 28 Sep 2021 17:30:03 -0700 Subject: [PATCH 88/98] removed the checks that the block perm has the proper length in llvmBlockPermToField and llvmBlockPermToArray, because these do not take the current partial substitution into account --- .../src/Verifier/SAW/Heapster/Implication.hs | 12 ++++++++---- .../src/Verifier/SAW/Heapster/Permissions.hs | 16 +++++++++++----- 2 files changed, 19 insertions(+), 9 deletions(-) diff --git a/heapster-saw/src/Verifier/SAW/Heapster/Implication.hs b/heapster-saw/src/Verifier/SAW/Heapster/Implication.hs index 28132cb19e..9eb547e8c4 100644 --- a/heapster-saw/src/Verifier/SAW/Heapster/Implication.hs +++ b/heapster-saw/src/Verifier/SAW/Heapster/Implication.hs @@ -2095,8 +2095,10 @@ simplImplOut (SImpl_IntroLLVMBlockArray x ap) = error "simplImplOut: SImpl_IntroLLVMBlockArray: malformed array permission" simplImplOut (SImpl_ElimLLVMBlockArray x bp) = case llvmBlockPermToArray bp of - Just ap -> distPerms1 x (ValPerm_Conj1 $ Perm_LLVMArray ap) - Nothing -> + Just ap + | bvEq (llvmArrayLengthBytes ap) (llvmBlockLen bp) -> + distPerms1 x (ValPerm_Conj1 $ Perm_LLVMArray ap) + _ -> error "simplImplIn: SImpl_ElimLLVMBlockArray: malformed input permission" simplImplOut (SImpl_IntroLLVMBlockSeq x bp1 len2 sh2) = distPerms1 x (ValPerm_Conj1 $ Perm_LLVMBlock $ @@ -4134,12 +4136,14 @@ implElimLLVMBlock x bp@(LLVMBlockPerm { llvmBlockShape = PExpr_PtrShape _ _ _ }) implElimLLVMBlock x bp@(LLVMBlockPerm { llvmBlockShape = PExpr_FieldShape (LLVMFieldShape p) }) - | Just fp <- llvmBlockPermToField (exprLLVMTypeWidth p) bp = + | Just fp <- llvmBlockPermToField (exprLLVMTypeWidth p) bp + , bvEq (llvmFieldLen fp) (llvmBlockLen bp) = implSimplM Proxy (SImpl_ElimLLVMBlockField x fp) -- For an array shape of the right length, eliminate to an array permission implElimLLVMBlock x bp - | isJust (llvmBlockPermToArray bp) = + | Just ap <- llvmBlockPermToArray bp + , bvEq (llvmArrayLengthBytes ap) (llvmBlockLen bp) = implSimplM Proxy (SImpl_ElimLLVMBlockArray x bp) -- FIXME: if we match an array shape here, its stride*length must be greater diff --git a/heapster-saw/src/Verifier/SAW/Heapster/Permissions.hs b/heapster-saw/src/Verifier/SAW/Heapster/Permissions.hs index c619433803..46a6d02350 100644 --- a/heapster-saw/src/Verifier/SAW/Heapster/Permissions.hs +++ b/heapster-saw/src/Verifier/SAW/Heapster/Permissions.hs @@ -3320,15 +3320,18 @@ llvmFieldPermToBlock fp = llvmBlockLen = llvmFieldLen fp, llvmBlockShape = PExpr_FieldShape (LLVMFieldShape $ llvmFieldContents fp) } --- | Convert a block permission to a field permission, if possible +-- | Convert a block permission with field shape to a field permission +-- +-- NOTE: do not check that the length of the block equals that of the resulting +-- field permission, in case the length of the block has a free variable that +-- might be provably but not syntacitcally equal to the length llvmBlockPermToField :: (1 <= w, KnownNat w, 1 <= sz, KnownNat sz) => NatRepr sz -> LLVMBlockPerm w -> Maybe (LLVMFieldPerm w sz) llvmBlockPermToField sz bp | PExpr_FieldShape (LLVMFieldShape p) <- llvmBlockShape bp , Just Refl <- testEquality sz (exprLLVMTypeWidth p) - , bvEq (llvmBlockLen bp) (bvInt (intValue sz `div` 8)) = - Just $ LLVMFieldPerm { llvmFieldRW = llvmBlockRW bp, + = Just $ LLVMFieldPerm { llvmFieldRW = llvmBlockRW bp, llvmFieldLifetime = llvmBlockLifetime bp, llvmFieldOffset = llvmBlockOffset bp, llvmFieldContents = p } @@ -3366,11 +3369,14 @@ llvmArrayPermToBlock _ = Nothing -- | Convert a block permission with array shape to an array permission, -- assuming the length of the block permission equals the size of the array +-- +-- NOTE: do not check that the length of the block equals that of the resulting +-- array permission, in case the length of the block has a free variable that +-- might be provably but not syntacitcally equal to the length llvmBlockPermToArray :: (1 <= w, KnownNat w) => LLVMBlockPerm w -> Maybe (LLVMArrayPerm w) llvmBlockPermToArray bp - | PExpr_ArrayShape len stride sh <- llvmBlockShape bp - , bvEq (bvMult stride len) (llvmBlockLen bp) = + | PExpr_ArrayShape len stride sh <- llvmBlockShape bp = Just $ LLVMArrayPerm { llvmArrayRW = llvmBlockRW bp, llvmArrayLifetime = llvmBlockLifetime bp, From d1bce16939c2871f5a0a24198698fd419e67eb38 Mon Sep 17 00:00:00 2001 From: Eddy Westbrook Date: Thu, 7 Oct 2021 09:40:21 -0700 Subject: [PATCH 89/98] commented out proof in rust_data_proofs.v that no longer works --- heapster-saw/examples/rust_data_proofs.v | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/heapster-saw/examples/rust_data_proofs.v b/heapster-saw/examples/rust_data_proofs.v index 0c0716db4e..2e03ac14d3 100644 --- a/heapster-saw/examples/rust_data_proofs.v +++ b/heapster-saw/examples/rust_data_proofs.v @@ -27,7 +27,8 @@ Import SAWCorePrelude. (* Print str_struct_new__tuple_fun. *) -Lemma no_errors_str_struct_new : refinesFun str_struct_new (fun _ _ _ => noErrorsSpec). +(* FIXME: need to handle mapBVVecM for this one to work! +Lemma no_errors_str_struct_new : refinesFun str_struct_new (fun _ _ _ _ => noErrorsSpec). Proof. unfold str_struct_new, str_struct_new__tuple_fun, noErrorsSpec, llvm__x2ememcpy__x2ep0i8__x2ep0i8__x2ei64, to_string_str. prove_refinement. @@ -44,3 +45,4 @@ Proof. unfold str_struct_new, str_struct_new__tuple_fun, noErrorsSpec, llvm__x2ememcpy__x2ep0i8__x2ep0i8__x2ei64, to_string_str. prove_refinement. Qed. +*) From 60a2d1cb63be05135503216caa619829dbb85a41 Mon Sep 17 00:00:00 2001 From: Eddy Westbrook Date: Thu, 7 Oct 2021 09:43:59 -0700 Subject: [PATCH 90/98] *almost* got a use of the write! macro to work in the rust_data exmample --- heapster-saw/examples/rust_data.saw | 31 +++++++++++++++++++++++------ 1 file changed, 25 insertions(+), 6 deletions(-) diff --git a/heapster-saw/examples/rust_data.saw b/heapster-saw/examples/rust_data.saw index e23b31b6b9..eba09559a9 100644 --- a/heapster-saw/examples/rust_data.saw +++ b/heapster-saw/examples/rust_data.saw @@ -37,11 +37,11 @@ heapster_define_rust_type env "pub enum Option { None, Some (X) }"; // For now we have to define the shape explicitly without the int8 name because // we don't yet have implications on array cells //heapster_define_llvmshape env "str" 64 "" "exsh len:bv 64.arraysh(len,1,[(8,int8<>)])"; -heapster_define_llvmshape env "str" 64 "" "exsh len:bv 64.arraysh(len,1,[(8,exists x:bv 8.eq(llvmword(x)))])"; +heapster_define_llvmshape env "str" 64 "" "exsh len:bv 64.arraysh())"; //heapster_define_rust_type env "type str = [u8];"; // The String type -heapster_define_llvmshape env "String" 64 "" "exsh cap:bv 64. ptrsh(arraysh(cap,1,[(8,int8<>)]));fieldsh(int64<>);fieldsh(eq(llvmword(cap)))"; +heapster_define_llvmshape env "String" 64 "" "exsh cap:bv 64. ptrsh(arraysh()));fieldsh(int64<>);fieldsh(eq(llvmword(cap)))"; // List type //heapster_define_llvmshape env "List" 64 "L:perm(llvmptr 64),X:llvmshape 64" "(fieldsh(eq(llvmword(0)))) orsh (fieldsh(eq(llvmword(1)));X;fieldsh(L))"; @@ -65,6 +65,9 @@ heapster_define_rust_type env "pub struct ThreeValues(u32,u32,u32);"; heapster_define_rust_type env "pub struct FourValues(u32,u32,u32,u32);"; heapster_define_rust_type env "pub struct FiveValues(u32,u32,u32,u32,u32);"; +// The StrStruct type +heapster_define_rust_type env "pub struct StrStruct(String);"; + // MixedStruct type // heapster_define_llvmshape env "MixedStruct" 64 "" "String<>;fieldsh(64,int64<>);fieldsh(64,int64<>)"; heapster_define_rust_type env "pub struct MixedStruct { pub s: String, pub i1: u64, pub i2: u64, }"; @@ -127,10 +130,12 @@ heapster_define_rust_type_qual env "fmt" "pub enum Position { Next, At(usize),}" heapster_define_rust_type_qual env "fmt" "pub struct Argument { pub position: fmt::Position, pub format: fmt::FormatSpec,}"; // fmt::ArgumentV1 type -heapster_define_rust_type_qual env "fmt" "pub struct ArgumentV1<'a> { value: &'a Void, formatter: for <'b> fn(&'b Void, &'b mut fmt::Formatter) -> fmt::Result, }"; +//heapster_define_rust_type_qual env "fmt" "pub struct ArgumentV1<'a> { value: &'a Void, formatter: for <'b> fn(&'b Void, &'b mut fmt::Formatter) -> fmt::Result, }"; +heapster_define_rust_type_qual env "fmt" "pub struct ArgumentV1 { value: Box, formatter: Box, }"; // fmt::Arguments type //heapster_define_rust_type_qual env "fmt" "pub struct Arguments<'a> { pieces: &'a [&'a str], fmt: Option<&'a [fmt::Argument]>, args: &'a [fmt::ArgumentV1<'a>], }"; +heapster_define_rust_type_qual env "fmt" "pub struct Arguments { pieces: Box, pieces_len:u64, fmt: Box, fmt_len: u64, args: Box, arg_len:u64, }"; /*** @@ -151,7 +156,7 @@ to_string_str <- heapster_find_symbol env "$LT$str$u20$as$u20$alloc..string..ToS //heapster_assume_fun_rename env to_string_str "to_string_str" "(len:bv 64). arg0:memblock(W,0,24,emptysh), arg1:array(0, int8<>]), arg2:eq(llvmword(len)) -o arg0:exists len':bv 64. ptr((W,0) |-> array(0, int8<>])) * ptr((W,8) |-> int64<>) * ptr((W,16) |-> eq(llvmword(len')))" "\\ (len:Vec 64 Bool) (_:#()) (str:BVVec 64 len (Vec 8 Bool)) -> returnM (Sigma (Vec 64 Bool) (\\ (len':Vec 64 Bool) -> BVVec 64 len' (Vec 8 Bool) * Vec 64 Bool * #())) (exists (Vec 64 Bool) (\\ (len':Vec 64 Bool) -> BVVec 64 len' (Vec 8 Bool) * Vec 64 Bool * #()) len (str, len, ()))"; // NOTE: this is the incorrect version, with no lifetime argument -heapster_assume_fun_rename env to_string_str "to_string_str" "(len:bv 64). arg0:memblock(W,0,24,emptysh), arg1:array(0, int8<>]), arg2:eq(llvmword(len)) -o arg0:memblock(W,0,24,String<>)" "\\ (len:Vec 64 Bool) (_:#()) (str:BVVec 64 len (Vec 8 Bool)) -> returnM (Sigma (Vec 64 Bool) (\\ (len':Vec 64 Bool) -> BVVec 64 len' (Vec 8 Bool) * Vec 64 Bool * #())) (exists (Vec 64 Bool) (\\ (len':Vec 64 Bool) -> BVVec 64 len' (Vec 8 Bool) * Vec 64 Bool * #()) len (str, len, ()))"; +heapster_assume_fun_rename env to_string_str "to_string_str" "(len:bv 64). arg0:memblock(W,0,24,emptysh), arg1:array(R,0,), arg2:eq(llvmword(len)) -o arg0:memblock(W,0,24,String<>)" "\\ (len:Vec 64 Bool) (_:#()) (str:BVVec 64 len (Vec 8 Bool)) -> returnM (Sigma (Vec 64 Bool) (\\ (len':Vec 64 Bool) -> BVVec 64 len' (Vec 8 Bool) * Vec 64 Bool * #())) (exists (Vec 64 Bool) (\\ (len':Vec 64 Bool) -> BVVec 64 len' (Vec 8 Bool) * Vec 64 Bool * #()) len (str, len, ()))"; // FIXME: this is the correct version, with a lifetime argument //heapster_assume_fun_rename env to_string_str "to_string_str" "(ps:lowned_perm,l:lifetime,len:bv 64). l:lowned ps, arg0:[l]memblock(W,0,24,emptysh), arg1:array(0, int8<>]), arg2:eq(llvmword(len)) -o l:lowned ps, arg0:[l]memblock(W,0,24,String<>)" "\\ (len:Vec 64 Bool) (_:#()) (str:BVVec 64 len (Vec 8 Bool)) -> returnM (Sigma (Vec 64 Bool) (\\ (len':Vec 64 Bool) -> BVVec 64 len' (Vec 8 Bool) * Vec 64 Bool * #())) (exists (Vec 64 Bool) (\\ (len':Vec 64 Bool) -> BVVec 64 len' (Vec 8 Bool) * Vec 64 Bool * #()) len (str, len, ()))"; @@ -170,9 +175,18 @@ heapster_assume_fun_rename_prim env String__fmt_sym "String__fmt" "<'a, 'b> fn(& */ +// ArgumentV1::new +//ArgumentV1_new <- heapster_find_symbol env "10ArgumentV13new"; +//heapster_assume_fun_rename_prim env ArgumentV1_new "ArgumentV1_new" "<'a,'b,T> fn (x: &'b T, f: fn(&T, &mut fmt::Formatter) -> fmt::Result) -> fmt::ArgumentV1<'b>"; +//ArgumentV1_new_String <- heapster_find_symbol env "_ZN4core3fmt10ArgumentV13new17hdf7e5958686d74c0E"; +//heapster_assume_fun_rename_prim env ArgumentV1_new_String "ArgumentV1_new_String" "<'a,'b> fn (x: &'b String, f: for<'c,'d> fn (&'c String, &'d mut fmt::Formatter) -> fmt::Result) -> fmt::ArgumentV1<'b>"; +//heapster_assume_fun_rename_prim env ArgumentV1_new_String "ArgumentV1_new_String" "<'a,'b> fn (x: &'b String, f: Box) -> fmt::ArgumentV1<'b>"; +//heapster_assume_fun_rename_prim env ArgumentV1_new_String "ArgumentV1_new_String" "<'a,'b> fn (x: &'b String, f: Box) -> fmt::ArgumentV1"; + // Arguments::new_v1 Arguments__new_v1_sym <- heapster_find_symbol env "3fmt9Arguments6new_v1"; -//heapster_assume_fun_rename_prim env Arguments__new_v1_sym "Arguments__new" "<'a> fn (pieces: &'a [&'a str], args: &'a [ArgumentV1<'a>]) -> Arguments<'a>"; +//heapster_assume_fun_rename_prim env Arguments__new_v1_sym "Arguments__new" "<'a> fn (pieces: &'a [&'a str], args: &'a [fmt::ArgumentV1<'a>]) -> fmt::Arguments<'a>"; +heapster_assume_fun_rename_prim env Arguments__new_v1_sym "Arguments__new" "<'a> fn (pieces: &'a [&'a str], args: &'a [fmt::ArgumentV1]) -> fmt::Arguments"; // Formatter::write_str Formatter__write_str_sym <- heapster_find_symbol env "9Formatter9write_str"; @@ -216,6 +230,10 @@ heapster_typecheck_fun_rename env mixed_struct_get_i1 "MixedStruct_get_i1" "<'a> mixed_struct_get_i2 <- heapster_find_symbol env "11MixedStruct6get_i2"; heapster_typecheck_fun_rename env mixed_struct_get_i2 "MixedStruct_get_i2" "<'a> fn (m:&'a MixedStruct) -> u64"; +// MixedStruct::fmt +mixed_struct_fmt <- heapster_find_trait_method_symbol env "core::fmt::Display::fmt"; +heapster_typecheck_fun_rename env mixed_struct_fmt "MixedStruct_fmt" "<'a, 'b> fn(&'a MixedStruct, f: &'b mut fmt::Formatter) -> fmt::Result"; + cycle_true_enum_sym <- heapster_find_symbol env "15cycle_true_enum"; // NOTE: This typecheck requires full(er) support for disjunctive shapes, which Heapster currently lacks // heapster_typecheck_fun_rename env cycle_true_enum_sym "cycle_true_enum" "<'a> fn (te:&'a TrueEnum) -> TrueEnum"; @@ -249,7 +267,8 @@ str_struct_new <- heapster_find_symbol env "9StrStruct3new"; //heapster_typecheck_fun_rename env str_struct_new "str_struct_new" "(len:bv 64).arg0:memblock(W,0,24,emptysh), arg1:array(0, int8<>]), arg2:eq(llvmword(len)) -o arg0:exists len':bv 64. ptr((W,0) |-> array(0, int8<>])) * ptr((W,8) |-> int64<>) * ptr((W,16) |-> eq(llvmword(len')))"; // FIXME: this is the correct version, with the String shape -heapster_typecheck_fun_rename env str_struct_new "str_struct_new" "(len:bv 64).arg0:memblock(W,0,24,emptysh), arg1:array(0, int8<>]), arg2:eq(llvmword(len)) -o arg0:memblock(W,0,24,String<>)"; +//heapster_typecheck_fun_rename env str_struct_new "str_struct_new" "(len:bv 64).arg0:memblock(W,0,24,emptysh), arg1:array(0, int8<>]), arg2:eq(llvmword(len)) -o arg0:memblock(W,0,24,String<>)"; +heapster_typecheck_fun_rename env str_struct_new "str_struct_new" "<'a> fn (name:&'a str) -> StrStruct<>"; bintree_is_leaf_sym <- heapster_find_symbol env "15bintree_is_leaf"; heapster_typecheck_fun_rename env bintree_is_leaf_sym "bintree_is_leaf" "<'a> fn (t: &'a BinTree) -> bool"; From 8345aad73b9fae20b82e43038796a51604da25b7 Mon Sep 17 00:00:00 2001 From: Eddy Westbrook Date: Tue, 19 Oct 2021 13:26:04 -0700 Subject: [PATCH 91/98] wrapped an overly long line --- heapster-saw/examples/rust_data.saw | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/heapster-saw/examples/rust_data.saw b/heapster-saw/examples/rust_data.saw index 362bb3ebc8..698253fd16 100644 --- a/heapster-saw/examples/rust_data.saw +++ b/heapster-saw/examples/rust_data.saw @@ -447,7 +447,8 @@ str_struct_new <- heapster_find_symbol env "9StrStruct3new"; // FIXME: this is the correct version, with the String shape //heapster_typecheck_fun_rename env str_struct_new "str_struct_new" "(len:bv 64).arg0:memblock(W,0,24,emptysh), arg1:array(0, int8<>]), arg2:eq(llvmword(len)) -o arg0:memblock(W,0,24,String<>)"; -heapster_typecheck_fun_rename env str_struct_new "str_struct_new" "<'a> fn (name:&'a str) -> StrStruct<>"; +heapster_typecheck_fun_rename env str_struct_new "str_struct_new" + "<'a> fn (name:&'a str) -> StrStruct<>"; bintree_is_leaf_sym <- heapster_find_symbol env "15bintree_is_leaf"; heapster_typecheck_fun_rename env bintree_is_leaf_sym "bintree_is_leaf" From d52c5b459132bf23a8f38f1e0256ada4fbe7608a Mon Sep 17 00:00:00 2001 From: Eddy Westbrook Date: Tue, 19 Oct 2021 13:26:39 -0700 Subject: [PATCH 92/98] whoops, removed duplicate functions that were accidentally added during the recent merge --- saw-core/prelude/Prelude.sawcore | 18 ------------------ 1 file changed, 18 deletions(-) diff --git a/saw-core/prelude/Prelude.sawcore b/saw-core/prelude/Prelude.sawcore index 53a2dc9603..2df4e9fe22 100644 --- a/saw-core/prelude/Prelude.sawcore +++ b/saw-core/prelude/Prelude.sawcore @@ -1983,24 +1983,6 @@ fmapM3 : (a b c d: sort 0) -> (a -> b -> c -> d) -> CompM a -> CompM b -> CompM c -> CompM d; fmapM3 a b c d f m1 m2 m3 = applyM c d (fmapM2 a b (c -> d) f m1 m2) m3; --- Apply a pure function to a computation -fmapM : (a b: sort 0) -> (a -> b) -> CompM a -> CompM b; -fmapM a b f m = bindM a b m (\ (x:a) -> returnM b (f x)); - --- Apply a computation of a function to a computation of an argument -applyM : (a b: sort 0) -> CompM (a -> b) -> CompM a -> CompM b; -applyM a b f m = - bindM (a -> b) b f (\ (f:a->b) -> bindM a b m (\ (x:a) -> returnM b (f x))); - --- Apply a binary pure function to a computation -fmapM2 : (a b c: sort 0) -> (a -> b -> c) -> CompM a -> CompM b -> CompM c; -fmapM2 a b c f m1 m2 = applyM b c (fmapM a (b -> c) f m1) m2; - --- Apply a trinary pure function to a computation -fmapM3 : (a b c d: sort 0) -> (a -> b -> c -> d) -> - CompM a -> CompM b -> CompM c -> CompM d; -fmapM3 a b c d f m1 m2 m3 = applyM c d (fmapM2 a b (c -> d) f m1 m2) m3; - -- Compose two monadic functions composeM : (a b c: sort 0) -> (a -> CompM b) -> (b -> CompM c) -> a -> CompM c; composeM a b c f g x = bindM b c (f x) g; From 1aa5e26f6ec25133b00dc9bf077e72328c99a83c Mon Sep 17 00:00:00 2001 From: Eddy Westbrook Date: Tue, 19 Oct 2021 13:26:52 -0700 Subject: [PATCH 93/98] wrapped an overly long line --- heapster-saw/src/Verifier/SAW/Heapster/TypedCrucible.hs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/heapster-saw/src/Verifier/SAW/Heapster/TypedCrucible.hs b/heapster-saw/src/Verifier/SAW/Heapster/TypedCrucible.hs index bf44b436fe..80071e8ceb 100644 --- a/heapster-saw/src/Verifier/SAW/Heapster/TypedCrucible.hs +++ b/heapster-saw/src/Verifier/SAW/Heapster/TypedCrucible.hs @@ -4080,7 +4080,8 @@ visitEntry names can_widen blk entry = mapM (traverseF $ visitCallSite entry) (typedEntryCallers entry) >>= \callers -> - debugTrace dlevel ("can_widen: " ++ show can_widen ++ ", any_fails: " ++ show (any (anyF typedCallSiteImplFails) callers)) $ + debugTrace dlevel ("can_widen: " ++ show can_widen ++ ", any_fails: " + ++ show (any (anyF typedCallSiteImplFails) callers)) $ if can_widen && any (anyF typedCallSiteImplFails) callers then case widenEntry dlevel env entry of Some entry' -> From ab9eb6b2d46d223abab4e62e0943f589b8ccf13c Mon Sep 17 00:00:00 2001 From: Eddy Westbrook Date: Tue, 19 Oct 2021 13:27:16 -0700 Subject: [PATCH 94/98] changed widening to drop permissions on unreachable variables --- heapster-saw/src/Verifier/SAW/Heapster/Widening.hs | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/heapster-saw/src/Verifier/SAW/Heapster/Widening.hs b/heapster-saw/src/Verifier/SAW/Heapster/Widening.hs index a4a1b4c9b4..c7405b15da 100644 --- a/heapster-saw/src/Verifier/SAW/Heapster/Widening.hs +++ b/heapster-saw/src/Verifier/SAW/Heapster/Widening.hs @@ -102,6 +102,14 @@ wnMapExtWidFun :: WidNameMap -> ExtVarPermsFun vars wnMapExtWidFun wnmap = ExtVarPermsFun $ \ns -> ExtVarPerms_Base $ RL.map (flip wnMapGetPerm wnmap) ns +-- | Assign the trivial @true@ permission to any variable that has not yet been +-- visited +wnMapDropUnvisiteds :: WidNameMap -> WidNameMap +wnMapDropUnvisiteds = + NameMap.map $ \case + p@(Pair _ (Constant True)) -> p + (Pair _ (Constant False)) -> Pair ValPerm_True (Constant False) + newtype PolyContT r m a = PolyContT { runPolyContT :: forall x. (forall y. a -> m (r y)) -> m (r x) } @@ -956,6 +964,7 @@ widen dlevel env tops args (Some (ArgVarPerms void $ widenExprs all_args (RL.map PExpr_Var args_ns1) (RL.map PExpr_Var args_ns2) widenExtGhostVars vars1 vars1_ns vars2 vars2_ns + modifying wsNameMap wnMapDropUnvisiteds wnmap <- view wsNameMap <$> get traceM (\i -> pretty "Widening returning:" <> line <> From 9b12e598db6b38a1fe631a2fdbfb1896fd8ef58d Mon Sep 17 00:00:00 2001 From: Eddy Westbrook Date: Tue, 19 Oct 2021 14:01:39 -0700 Subject: [PATCH 95/98] oops, finished updating the examples to use the correct syntax --- heapster-saw/examples/mbox.saw | 2 +- heapster-saw/examples/rust_data.saw | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/heapster-saw/examples/mbox.saw b/heapster-saw/examples/mbox.saw index c2b41f66f6..de4edbb63d 100644 --- a/heapster-saw/examples/mbox.saw +++ b/heapster-saw/examples/mbox.saw @@ -31,7 +31,7 @@ heapster_define_reachability_perm env "mbox" "rw:rwmodality, x:llvmptr 64" "llvmptr 64" "ptr((rw,0) |-> int64<>) * ptr((rw,8) |-> int64<>) * ptr((rw,16) |-> mbox) * \ - \ array(W, 24, <128, *1, fieldsh(int8<>))" + \ array(W, 24, <128, *1, fieldsh(8,int8<>))" "Mbox_def" "foldMbox" "unfoldMbox" "transMbox"; // heapster_define_perm env "mbox_nonnull" diff --git a/heapster-saw/examples/rust_data.saw b/heapster-saw/examples/rust_data.saw index 698253fd16..18d15ae41a 100644 --- a/heapster-saw/examples/rust_data.saw +++ b/heapster-saw/examples/rust_data.saw @@ -274,7 +274,7 @@ to_string_str <- heapster_find_symbol env "$LT$str$u20$as$u20$alloc..string..ToS // NOTE: this is the incorrect version, with no lifetime argument heapster_assume_fun_rename env to_string_str "to_string_str" "(len:bv 64). arg0:memblock(W,0,24,emptysh), \ - \ arg1:array(R,0, int8<>]), \ + \ arg1:array(R,0,)), \ \ arg2:eq(llvmword(len)) -o \ \ arg0:memblock(W,0,24,String<>)" "\\ (len:Vec 64 Bool) (_:#()) (str:BVVec 64 len (Vec 8 Bool)) -> \ From fc15ae97e427cdbdff8b2dd2f8a700b7e8bdd22b Mon Sep 17 00:00:00 2001 From: Eddy Westbrook Date: Tue, 19 Oct 2021 14:02:06 -0700 Subject: [PATCH 96/98] commented out some parts of the proofs for sum_inc_ptr in the arrays example that no longer work --- heapster-saw/examples/arrays_proofs.v | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/heapster-saw/examples/arrays_proofs.v b/heapster-saw/examples/arrays_proofs.v index b1e5f1dd2e..32e80eaed0 100644 --- a/heapster-saw/examples/arrays_proofs.v +++ b/heapster-saw/examples/arrays_proofs.v @@ -150,11 +150,12 @@ Proof. unfold noErrorsSpec, sum_inc_ptr_invar. time "no_errors_sum_inc_ptr" prove_refinement. all: try assumption. + (* - assert (isBvult 64 a2 a1). + apply isBvule_to_isBvult_or_eq in e_assuming. destruct e_assuming; [assumption |]. apply bvEq_bvSub_r in H. - symmetry in H; contradiction. + (* symmetry in H; contradiction. *) admit. + rewrite H in e_maybe; discriminate e_maybe. - apply isBvult_to_isBvule_suc; assumption. - repeat rewrite bvSub_eq_bvAdd_neg. @@ -162,7 +163,9 @@ Proof. rewrite bvNeg_bvAdd_distrib; reflexivity. - apply isBvule_zero_n. - symmetry; apply bvSub_n_zero. -Qed. + *) +Admitted. +(* Qed. *) Definition sum_inc_ptr_spec len : BVVec 64 len (bitvector 8) -> bitvector 64 := @@ -186,6 +189,7 @@ Proof. 3: prove_refinement_eauto; [| apply refinesM_returnM ]. 7: prove_refinement_eauto; [| apply refinesM_returnM ]. (* same as no_errors_sum_inc_ptr *) + (* - assert (isBvult 64 a2 a1). + apply isBvule_to_isBvult_or_eq in e_forall. destruct e_forall; [assumption |]. @@ -206,5 +210,5 @@ Proof. (* unique to this proof *) - rewrite bvAdd_id_l. repeat f_equal. - admit. + admit. *) Admitted. From d72abef2d806fa82388da1bbb1b2e1c408ccfb24 Mon Sep 17 00:00:00 2001 From: Eddy Westbrook Date: Tue, 19 Oct 2021 14:53:58 -0700 Subject: [PATCH 97/98] wrapped some of the lines in rust_data.saw --- heapster-saw/examples/rust_data.saw | 91 +++++++++++++---------------- 1 file changed, 39 insertions(+), 52 deletions(-) diff --git a/heapster-saw/examples/rust_data.saw b/heapster-saw/examples/rust_data.saw index 18d15ae41a..8136b2df29 100644 --- a/heapster-saw/examples/rust_data.saw +++ b/heapster-saw/examples/rust_data.saw @@ -80,7 +80,8 @@ heapster_define_rust_type env "pub struct FiveValues(u32,u32,u32,u32,u32);"; heapster_define_rust_type env "pub struct StrStruct(String);"; // MixedStruct type -// heapster_define_llvmshape env "MixedStruct" 64 "" "String<>;fieldsh(64,int64<>);fieldsh(64,int64<>)"; +// heapster_define_llvmshape env "MixedStruct" 64 "" +// "String<>;fieldsh(64,int64<>);fieldsh(64,int64<>)"; heapster_define_rust_type env "pub struct MixedStruct { pub s: String, pub i1: u64, pub i2: u64, }"; @@ -148,7 +149,8 @@ heapster_define_rust_type env heapster_define_rust_type_qual env "fmt" "pub struct Error { }"; // fmt::Result type -// FIXME: there seems to be some optimization in Rust that lays out fmt::Result as a 1-bit value +// FIXME: there seems to be some optimization in Rust that lays out fmt::Result +// as a 1-bit value heapster_define_llvmshape env "fmt::Result" 64 "" "fieldsh(1,eq(llvmword(0))) orsh fieldsh(1,eq(llvmword(1)))"; //heapster_define_rust_type_qual env "fmt" @@ -193,43 +195,10 @@ heapster_define_rust_type_qual env "fmt" // \ args: &'a [fmt::ArgumentV1<'a>], }"; -/*** - *** Rust Formatting Types - ***/ - -// fmt::Error type -heapster_define_rust_type_qual env "fmt" "pub struct Error { }"; - -// fmt::Result type -// FIXME: there seems to be some optimization in Rust that lays out fmt::Result as a 1-bit value -heapster_define_llvmshape env "fmt::Result" 64 "" "fieldsh(1,eq(llvmword(0))) orsh fieldsh(1,eq(llvmword(1)))"; -//heapster_define_rust_type_qual env "fmt" "pub enum Result { Ok (), Err (fmt::Error) }"; - -// fmt::Formatter type -heapster_define_opaque_llvmshape env "fmt::Formatter" 64 "" "64" "#()"; - -// fmt::Alignment type -heapster_define_rust_type_qual env "fmt" "pub enum Alignment { Left, Right, Center, Unknown,}"; - -// fmt::Count type -heapster_define_rust_type_qual env "fmt" "pub enum Count { Is(usize), Param(usize), NextParam, Implied,}"; - -// fmt::FormatSpec -heapster_define_rust_type_qual env "fmt" "pub struct FormatSpec { pub fill: char, pub align: fmt::Alignment, pub flags: u32, pub precision: fmt::Count, pub width: fmt::Count, }"; - -// fmt::Position -heapster_define_rust_type_qual env "fmt" "pub enum Position { Next, At(usize),}"; - -// fmt::Argument type -heapster_define_rust_type_qual env "fmt" "pub struct Argument { pub position: fmt::Position, pub format: fmt::FormatSpec,}"; - -// fmt::ArgumentV1 type -//heapster_define_rust_type_qual env "fmt" "pub struct ArgumentV1<'a> { value: &'a Void, formatter: for <'b> fn(&'b Void, &'b mut fmt::Formatter) -> fmt::Result, }"; -heapster_define_rust_type_qual env "fmt" "pub struct ArgumentV1 { value: Box, formatter: Box, }"; - -// fmt::Arguments type -//heapster_define_rust_type_qual env "fmt" "pub struct Arguments<'a> { pieces: &'a [&'a str], fmt: Option<&'a [fmt::Argument]>, args: &'a [fmt::ArgumentV1<'a>], }"; -heapster_define_rust_type_qual env "fmt" "pub struct Arguments { pieces: Box, pieces_len:u64, fmt: Box, fmt_len: u64, args: Box, arg_len:u64, }"; +heapster_define_rust_type_qual env "fmt" + "pub struct Arguments { pieces: Box, pieces_len:u64, \ + \ fmt: Box, fmt_len: u64, args: Box, \ + \ arg_len:u64, }"; /*** @@ -257,7 +226,8 @@ heapster_assume_fun env "llvm.memcpy.p0i8.p0i8.i64" "\\ (X:sort 0) (len:Vec 64 Bool) (x:X) (_:#()) -> returnM (#() * #()) ((),())"; // ::to_string -to_string_str <- heapster_find_symbol env "$LT$str$u20$as$u20$alloc..string..ToString$GT$9to_string"; +to_string_str <- heapster_find_symbol env + "$LT$str$u20$as$u20$alloc..string..ToString$GT$9to_string"; // NOTE: this is the more incorrect version, with no lifetime argument and no shapes //heapster_assume_fun_rename env to_string_str "to_string_str" // "(len:bv 64). arg0:memblock(W,0,24,emptysh), @@ -332,16 +302,26 @@ heapster_assume_fun_rename_prim env String__fmt_sym "String__fmt" // ArgumentV1::new //ArgumentV1_new <- heapster_find_symbol env "10ArgumentV13new"; -//heapster_assume_fun_rename_prim env ArgumentV1_new "ArgumentV1_new" "<'a,'b,T> fn (x: &'b T, f: fn(&T, &mut fmt::Formatter) -> fmt::Result) -> fmt::ArgumentV1<'b>"; -//ArgumentV1_new_String <- heapster_find_symbol env "_ZN4core3fmt10ArgumentV13new17hdf7e5958686d74c0E"; -//heapster_assume_fun_rename_prim env ArgumentV1_new_String "ArgumentV1_new_String" "<'a,'b> fn (x: &'b String, f: for<'c,'d> fn (&'c String, &'d mut fmt::Formatter) -> fmt::Result) -> fmt::ArgumentV1<'b>"; -//heapster_assume_fun_rename_prim env ArgumentV1_new_String "ArgumentV1_new_String" "<'a,'b> fn (x: &'b String, f: Box) -> fmt::ArgumentV1<'b>"; -//heapster_assume_fun_rename_prim env ArgumentV1_new_String "ArgumentV1_new_String" "<'a,'b> fn (x: &'b String, f: Box) -> fmt::ArgumentV1"; +//heapster_assume_fun_rename_prim env ArgumentV1_new "ArgumentV1_new" +// "<'a,'b,T> fn (x: &'b T, f: fn(&T, &mut fmt::Formatter) -> fmt::Result) \ +// \ -> fmt::ArgumentV1<'b>"; +//ArgumentV1_new_String <- heapster_find_symbol env +// "_ZN4core3fmt10ArgumentV13new17hdf7e5958686d74c0E"; +//heapster_assume_fun_rename_prim env ArgumentV1_new_String "ArgumentV1_new_String" +// "<'a,'b> fn (x: &'b String, \ +// \ f: for<'c,'d> fn (&'c String, &'d mut fmt::Formatter) -> fmt::Result) \ +// \ -> fmt::ArgumentV1<'b>"; +//heapster_assume_fun_rename_prim env ArgumentV1_new_String "ArgumentV1_new_String" +// "<'a,'b> fn (x: &'b String, f: Box) -> fmt::ArgumentV1<'b>"; +//heapster_assume_fun_rename_prim env ArgumentV1_new_String "ArgumentV1_new_String" +// "<'a,'b> fn (x: &'b String, f: Box) -> fmt::ArgumentV1"; // Arguments::new_v1 Arguments__new_v1_sym <- heapster_find_symbol env "3fmt9Arguments6new_v1"; -//heapster_assume_fun_rename_prim env Arguments__new_v1_sym "Arguments__new" "<'a> fn (pieces: &'a [&'a str], args: &'a [fmt::ArgumentV1<'a>]) -> fmt::Arguments<'a>"; -heapster_assume_fun_rename_prim env Arguments__new_v1_sym "Arguments__new" "<'a> fn (pieces: &'a [&'a str], args: &'a [fmt::ArgumentV1]) -> fmt::Arguments"; +//heapster_assume_fun_rename_prim env Arguments__new_v1_sym "Arguments__new" +// "<'a> fn (pieces: &'a [&'a str], args: &'a [fmt::ArgumentV1<'a>]) -> fmt::Arguments<'a>"; +heapster_assume_fun_rename_prim env Arguments__new_v1_sym "Arguments__new" + "<'a> fn (pieces: &'a [&'a str], args: &'a [fmt::ArgumentV1]) -> fmt::Arguments"; // Formatter::write_str Formatter__write_str_sym <- heapster_find_symbol env "9Formatter9write_str"; @@ -393,15 +373,19 @@ heapster_typecheck_fun_rename env mixed_struct_get_i2 "MixedStruct_get_i2" "<'a> fn (m:&'a MixedStruct) -> u64"; // MixedStruct::fmt -mixed_struct_fmt <- heapster_find_trait_method_symbol env "core::fmt::Display::fmt"; -heapster_typecheck_fun_rename env mixed_struct_fmt "MixedStruct_fmt" "<'a, 'b> fn(&'a MixedStruct, f: &'b mut fmt::Formatter) -> fmt::Result"; +mixed_struct_fmt <- heapster_find_trait_method_symbol env + "core::fmt::Display::fmt"; +heapster_typecheck_fun_rename env mixed_struct_fmt "MixedStruct_fmt" + "<'a, 'b> fn(&'a MixedStruct, f: &'b mut fmt::Formatter) -> fmt::Result"; cycle_true_enum_sym <- heapster_find_symbol env "15cycle_true_enum"; -// NOTE: This typecheck requires full(er) support for disjunctive shapes, which Heapster currently lacks +// NOTE: This typecheck requires full(er) support for disjunctive shapes, which +// Heapster currently lacks // heapster_typecheck_fun_rename env cycle_true_enum_sym "cycle_true_enum" // "<'a> fn (te:&'a TrueEnum) -> TrueEnum"; -TrueEnum__fmt_sym <- heapster_find_trait_method_symbol env "core::fmt::Display::fmt"; +TrueEnum__fmt_sym <- heapster_find_trait_method_symbol env + "core::fmt::Display::fmt"; heapster_typecheck_fun_rename env TrueEnum__fmt_sym "TrueEnum__fmt" "<'a, 'b> fn (&'a TrueEnum, f: &'b mut fmt::Formatter) -> fmt::Result"; @@ -446,7 +430,10 @@ str_struct_new <- heapster_find_symbol env "9StrStruct3new"; // \\ ptr((W,8) |-> int64<>) * ptr((W,16) |-> eq(llvmword(len')))"; // FIXME: this is the correct version, with the String shape -//heapster_typecheck_fun_rename env str_struct_new "str_struct_new" "(len:bv 64).arg0:memblock(W,0,24,emptysh), arg1:array(0, int8<>]), arg2:eq(llvmword(len)) -o arg0:memblock(W,0,24,String<>)"; +//heapster_typecheck_fun_rename env str_struct_new "str_struct_new" +// "(len:bv 64).arg0:memblock(W,0,24,emptysh), \ +// \ arg1:array(0, int8<>]), \ +// \ arg2:eq(llvmword(len)) -o arg0:memblock(W,0,24,String<>)"; heapster_typecheck_fun_rename env str_struct_new "str_struct_new" "<'a> fn (name:&'a str) -> StrStruct<>"; From 4c28f0f47ba25f56dc5141de7020692721b203f6 Mon Sep 17 00:00:00 2001 From: Eddy Westbrook Date: Tue, 19 Oct 2021 15:09:30 -0700 Subject: [PATCH 98/98] whoops, updated the ArgumentV1 type incorrectly in the last commit --- heapster-saw/examples/rust_data.saw | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/heapster-saw/examples/rust_data.saw b/heapster-saw/examples/rust_data.saw index 8136b2df29..02f249c3ea 100644 --- a/heapster-saw/examples/rust_data.saw +++ b/heapster-saw/examples/rust_data.saw @@ -184,9 +184,14 @@ heapster_define_rust_type_qual env "fmt" // fmt::ArgumentV1 type heapster_define_rust_type_qual env "fmt" - "pub struct ArgumentV1<'a> { \ - \ value: &'a Void, \ - \ formatter: for <'b> fn(&'b Void, &'b mut fmt::Formatter) -> fmt::Result, }"; + "pub struct ArgumentV1 { value: Box, formatter: Box }"; + +// FIXME: this is the correct type, but Heapster cannot yet handle lifetime +// arguments for types +// heapster_define_rust_type_qual env "fmt" +// "pub struct ArgumentV1<'a> { \ +// \ value: &'a Void, \ +// \ formatter: for <'b> fn(&'b Void, &'b mut fmt::Formatter) -> fmt::Result, }"; // fmt::Arguments type //heapster_define_rust_type_qual env "fmt"