HANDLING BIT-PROPAGATING OPERATIONS IN BIT-VECTOR REASONING Alexander Nadel, Intel, Israel SMT’13 Workshop Helsinki, Finland July 8th, 2013 Outline • We identify and define a class of Bit-Vector (BV) operations, called Bit-Propagating (BP) • We propose an algorithm for efficiently handling BP operations during online preprocessing in eager BV solving • We demonstrate a performance boost when our algorithms are applied over SMT-LIB 2.0 instances Bit-Vector (BV) Reasoning • Bit-vector reasoning is widely applied for HW and SW formal validation and other domains. • Over 48% out of more than 93,000 benchmarks in SMT- LIB are BV-based, that is either: • Plain bit-vector (QF_BV), or • Bit-vectors and arrays combined (QF_ABV) • Some BV Solvers: Boolector, Mathsat, STP, CVC, Z3, Intel’s new solver Hazel, … BV Operations in SMT-LIB 2.0 Core Bit-wise Arithmetic Comparison Bit-prop. =/bvcomp distinct ite and**/bvand or**/bvor xor**/bvxor =>** bvnot bvnand bvnor bvxnor bvneg bvadd bvmul bvudiv bvurem bvsub bvsdiv bvsrem bvsmod bvshl* bvlshr* bvashr* bvult bvule bvugt bvuge bvslt bvsle bvsgt bvsge concat extract bvshl* bvlshr* bvashr* repeat zero_extend sign_extend rotate_left rotate_right * Shift by a constant is bit-propagating; shift by a non-constant is arithmetic ** We consider Bool’s to be bit-vectors of width 1 Eager BV Solving 1. Apply word-level preprocessing (rewriting, constant propagation, …) • Local/online: applied once a new operation is fed into the solver • Global: applied after the whole formula is fed into the solver 2. Optionally, bit-blast to bit-level AIG and apply AIG simplifications 3. Bit-blast to CNF and solve with a SAT solver [0] 0 0 ¬π£4 ∨ π£1 ∨ π£2 [0] [0] 0 ¬π£4 ∨ ¬π£1 ∨ ¬π£2 Eager BV Solving Example [0] [0] [0] 0 π£4 = π£1 ⊕ π£2 [0] 0 π = π£1 ∧ π£2 [1] [1] 1 π£4 = π£1 ⊕ π£2 ⊕ π Online [0] ¬π£Preprocessing 4 [1] ¬π£4 v3,v4: bvadd [0] 0 π£4 ∨ ¬π£1 ∨ π£2 [0] [0] 0 π£4 ∨ π£1 ∨ ¬π£2 (define-fun (declare-fun (check-sat) () (v4 ( v1 v2 BitVec ()(bvadd ( BitVec 2)2)) (bvadd (define-fun v4 (assert () (v3 BitVec 2) (_ bv0 v32)) (_ v1 bv0v2)) 2))) 0 ¬π ∨ π£1 0 ¬π ∨ π£2 0 0 π ∨ ¬π£1 ∨ ¬π£2 1 SAT! 1 ¬π ∨ π£1 ∨ π£2 [1] 1 ¬π ∨ ¬π£1 ∨ ¬π£2 [1] 1 π ∨ ¬π£1 ∨ π£2 [1] 1 π ∨ π£1 ∨ ¬π£2 [1] ¬π£4 ∨ π ∨ π [1] ¬π£4 ∨ ¬π ∨ ¬π [1] π£4 ∨ ¬π ∨ π [1] π£4 v∨ π: ∨ ¬π bvadd 3 [0] ¬π£4 [1] ¬π£ 4 v 1 2 SMT Engine 0 SAT Engine Bit-Propagating (BP) Operations • We define an operation to be bit-propagating iff: • Each output bit is either a bit of one of the inputs or a constant, and • The mapping can be computed at the time the operation is applied. u = bvshl(v,2) = [v[1], v[0],0,0] v = [v[3], v[2], v[1], v[0]] t = bvshl(v,s) BP Operations in SMT-LIB 2.0 Bit-prop. concat extract bvshl* bvlshr* bvashr* repeat zero_extend sign_extend rotate_left rotate_right * Shift by a constant is bit-propagating; shift by a non-constant is arithmetic BP Operations in SMT-LIB 2.0 Bit-prop. u = concat(v,y) = [v[3], v[2], v[1], v[0], y[1], y[0]] v = [v[3], v[2], v[1], v[0]] y = [y[1], y[0]] concat extract bvshl* bvlshr* bvashr* repeat zero_extend sign_extend rotate_left rotate_right BP Operations in SMT-LIB 2.0 Bit-prop. u = extract(v,2,1) = [v[2], v[1]] v = [v[3], v[2], v[1], v[0]] concat extract bvshl* bvlshr* bvashr* repeat zero_extend sign_extend rotate_left rotate_right BP Operations in SMT-LIB 2.0 Bit-prop. u = bvshl(v,2) = [v[1], v[0],0,0] v = [v[3], v[2], v[1], v[0]] concat extract bvshl* bvlshr* bvashr* repeat zero_extend sign_extend rotate_left rotate_right * Shift by a constant is bit-propagating; shift by a non-constant is arithmetic BP Operations in SMT-LIB 2.0 Bit-prop. u = bvlshr(v,2) = [0,0,v[3], v[2]] v = [v[3], v[2], v[1], v[0]] concat extract bvshl* bvlshr* bvashr* repeat zero_extend sign_extend rotate_left rotate_right * Shift by a constant is bit-propagating; shift by a non-constant is arithmetic BP Operations in SMT-LIB 2.0 Bit-prop. u = bvashr(v,2) = [v[3],v[3],v[3], v[2]] v = [v[3], v[2], v[1], v[0]] concat extract bvshl* bvlshr* bvashr* repeat zero_extend sign_extend rotate_left rotate_right * Shift by a constant is bit-propagating; shift by a non-constant is arithmetic BP Operations in SMT-LIB 2.0 Bit-prop. u = repeat(v,2) = [v[3],v[2],v[1], v[0], v[3],v[2],v[1], v[0]] v = [v[3], v[2], v[1], v[0]] concat extract bvshl* bvlshr* bvashr* repeat zero_extend sign_extend rotate_left rotate_right BP Operations in SMT-LIB 2.0 Bit-prop. u = zero_extend(v,2) = [0,0,v[3],v[2],v[1], v[0]] v = [v[3], v[2], v[1], v[0]] concat extract bvshl* bvlshr* bvashr* repeat zero_extend sign_extend rotate_left rotate_right BP Operations in SMT-LIB 2.0 Bit-prop. u = sign_extend(v,2) = [v[3], v[3],v[3],v[2],v[1], v[0]] v = [v[3], v[2], v[1], v[0]] concat extract bvshl* bvlshr* bvashr* repeat zero_extend sign_extend rotate_left rotate_right BP Operations in SMT-LIB 2.0 Bit-prop. u = rotate_left(v,1) = [v[2],v[1],v[0],v[3]] v = [v[3], v[2], v[1], v[0]] concat extract bvshl* bvlshr* bvashr* repeat zero_extend sign_extend rotate_left rotate_right BP Operations in SMT-LIB 2.0 Bit-prop. u = rotate_right(v,1) = [v[0],v[3],v[2],v[1]] v = [v[3], v[2], v[1], v[0]] concat extract bvshl* bvlshr* bvashr* repeat zero_extend sign_extend rotate_left rotate_right The Portion of BP Operations in SMT-LIB 2.0 Families in QF_BV Logic Family uclid/tcas calypto sage/app11 bruttomesso/core bench_ab sage/app10 bruttomesso/lfsr brummayerbiere2 uum check crafted sage/app6 sage/app12 Pipe wienand-cav2008/Booth stp_samples sage/app2 check2 sage/app7 brummayerbiere sage/app5 sage/app8 sage/app9 Bench’s BP Ops in % 2 61 23 56 611 50 672 49 285 44 51 42 240 38 65 37 8 36 5 35 21 35 245 34 5784 29 1 25 6 25 426 24 1417 22 6 21 8663 19 52 17 1103 16 2756 16 3301 16 Family galois spear/openldap_v2.3.35 sage/app1 bruttomesso/simple_processor uclid_contrib_smtcomp09 spear/inn_v2.4.3 spear/samba_v3.0.24 spear/wget_v1.10.2 wienand-cav2008/Commute uclid wienand-cav2008/Distrib spear/xinetd_v2.3.14 brummayerbiere3 spear/zebra_v0.95a stp rubik spear/cvs_v1.11.22 brummayerbiere4 dwp_formulas asp gulwani-pldi08 tacas07 VS3 Bench’s BP Ops in % 4 14 8 14 2676 14 64 13 7 219 1386 42 6 416 6 2 79 9 1 13 8 8 8 8 7 7 6 5 5 5 7 29 10 332 501 6 5 11 4 3 2 1 0 0 0 0 Our Approach to Handling BP Ops • Handle BP Operations explicitly during online preprocessing using Bit-Propagating Normal Form (BPNF)based reasoning • Each variable is associated with a BPNF: a sequence of segments, where each segment is either: • A constant, or • A bit-range over a non-propagating variable • Goals: • Word-level hashing: one word-level variable per BPNF • CNF minimization: CNF variables are created only for non-BP ops (assert (v8 (_ bv0 3)) (check-sat) Notwas a pair BPNF, mergeable! The new Merging neighbor essential of segments for proper washashing! merged! Segments s2 and s1 (in the specified The are CNF: Online order) mergeable if [0] s and s are constants, or Preprocessing Both οv 2 1 1 [2-1],v[2-0] [1-0]} [2-0] v = v concat(v = concat(v , v )={v , v )={v } } 7 6 5 1 1 8 7 6 5 1 [1] s and s are bit-ranges, οvBoth 2 1 1 [2] thatNo s2 =CNF v[k:j+1] and s1 = v[j:i]required! οvsuch 1 clauses/vars BPNF: a sequence of non-mergeable Bit-blasted addition segments v6 = extract(v4, 6, 5)={v1[2-1]} v8 = extract(v2, 3, 1)={v1[2-0]} BPNF Usage Example [1-0]}[1-0] v53 = extract(v v3=extract(v 2, 1)={v } 2, 2,2,1)={v 1 1 v2 = bvshl(v1,1)={v1[2-0],0} v5 = extract(v4, 5, 4)={v1[1-0]} v4 = repeat(v1, 2)={v1[3-0], v1[3-0]} v1 = bvadd(u1, u2)={v1[3:0]} u1={u1[3:0]}, where |u1|=4 u2={u2[3:0]}, where |u2|=4 Implementation Tips: Segment Threshold • Maintaining too many segments might inflate the memory and lead to a performance degradation • Solution: impose a user-given threshold T on a number of segments in BPNF • A variable with too many segments in BPNF is considered non-BP. • New CNF variables are created to represent it in the SAT solver Implementation Tips: Rewriting assertbased Definitions • Using assert to define new variables is incompatible with BPNF reasoning Rewriting assert-based Definitions: Problem Example v = repeat(u,2)={u[31-0],u[31-0]} (declare-fun 64)) (assert (= v (repeat 2)) (declare-fun uv () ( BitVecu32)) u = {u[31-0]} SMT Engine 0 [31-0]}} [0-0]} [31-0],u[31-0]} ztvu== repeat(u,2)={u {v (v=t)={z {u[63-0] Implementation Tips: Rewriting Assertbased Definitions • Using assert to define new variables is incomparable with BPNF reasoning • Solution: rewrite assert-based definitions into define-fun- based definitions (using look-ahead): (declare-fun u () Type) (declare-fun v () Type) (assert (= (v (f u)))) (declare-fun u () Type) (define-fun v (f u)) • Our example: (declare-fun u () ( BitVec 32)) (declare-fun v () ( BitVec 64)) (assert (= (v (repeat u 2)))) (declare-fun u () ( BitVec 32)) (define-fun v (repeat u 2)) Implementation Tips: Apply Constant Propagation • Constant propagation is a commonly applied preprocessing technique • Essential in our setting in order not to miss shifts by constants • Example: (declare-fun u () ( BitVec 32)) (define-fun x () ( BitVec 32)) (assert (= x (bvadd (_ bv3 32) (_ bv2 32)))) (define-fun v (bvshl u x)) (declare-fun u () ( BitVec 32)) (define-fun v (bvshl u (_ bv5 32))) Experimental Results • We implemented BPNF reasoning on top of a new Intel’s eager SMT solver Hazel • Main experiment: show the impact of BPNF reasoning on Hazel performance • We used 37 SMT-LIB families having at least 5% BP operations • Families solved in less than 1 sec. and most of the (huge) sage sub-families were dismissed • We used different values for the segments threshold in BPNF • The base version creates a new CNF variable for every word-level variable • Secondary experiment: demonstrate that Hazel can compete with state- of-the-art solvers over families where BPNF reasoning is the most helpful • Environment: machines with Intel® Xeon® processors, 3Ghz CPU frequency, 32Gb of memory. • Time-out: 600 sec. Run-time Family Base spear/openldap_v2.3.35 pipe brummayerbiere wienand-cav2008/Booth uum brutomesso/simple_proces sor uclid_contrib_smtcomp09 uclid/catchconv brummayerbiere3 brutomesso/lfsr spear/samba_v3.0.24 spear/inn_v2.4.3 stp spear/wget_v1.10.2 brummayerbiere2 calypto brutomesso/core Thr. 10 Time Ratio 10 to Thr. 1000 Base 1800 600 1649 43 18 600 155 709 26 12 19 600 711 26 12 374 226 9 2921 8039 3516 624 11 308 719 213 19355 266 200 8 2600 7435 3359 607 10 319 801 254 24307 266 169 7 2885 7439 3433 708 11 306 799 253 24307 1000 to Base 3.000 96.774 3.872 1.000 2.326 2.321 1.643 1.626 1.535 1.534 1.404 1.130 1.115 1.123 1.081 1.047 1.027 1.023 0.966 0.899 0.838 0.796 1.405 1.340 1.312 1.012 1.081 1.024 0.880 1.000 1.006 0.901 0.843 0.796 Solved Base Thr. 1000 Thr. 10 5 0 40 2 2 7 1 41 2 2 8 0 41 2 2 64 7 414 42 230 1386 219 1 42 32 11 933 64 7 414 42 227 1386 219 1 42 33 11 925 64 7 414 42 227 1386 219 1 42 33 11 925 Run-time Family Base Thr. 10 Time Ratio 10 to Thr. 1000 Base spear/openldap_v2.3.35 1800 600 19 pipe 600 155 600 brummayerbiere 1649 709 711 wienand-cav2008/Booth 43 26 26 uum 18 12 12 brutomesso/simple_proces sor 374 266 266 uclid_contrib_smtcomp09 226 200 169 uclid/catchconv 9 8 7 brummayerbiere3 2921 2600 2885 brutomesso/lfsr 8039 7435 7439 spear/samba_v3.0.24 3516 3433 8 families with at least 30% 3359 speed-up spear/inn_v2.4.3 624 607 708 stp 11 10 11 spear/wget_v1.10.2 308 319 306 brummayerbiere2 719 801 799 calypto 213 254 253 brutomesso/core 19355 24307 24307 1000 to Base 3.000 96.774 3.872 1.000 2.326 2.321 1.643 1.626 1.535 1.534 1.404 1.130 1.115 1.123 1.081 1.047 1.027 1.023 0.966 0.899 0.838 0.796 1.405 1.340 1.312 1.012 1.081 1.024 0.880 1.000 1.006 0.901 0.843 0.796 Solved Base Thr. 1000 Thr. 10 5 0 40 2 2 7 1 41 2 2 8 0 41 2 2 64 7 414 42 230 1386 219 1 42 32 11 933 64 7 414 42 227 1386 219 1 42 33 11 925 64 7 414 42 227 1386 219 1 42 33 11 925 - Significant reduction in CNF size Segment Thr. 10 Marginal reduction in the ops num. => hints that Base word-level hashing may not be Family critical SMT CNF is CNF Clss Vars Correlation between the CNF size and performance not absoluteOpt Ops spear/openldap_v2.3.35 Clss Vars Ratio Ratio Ratio Segment Thr. 1000 Clss Opt Ratio Ratio Vars Ratio 12469 3.86M 0.93M 1.0236 1.0986 1.2593 1.0236 1.1012 1.2661 1048 0.19M 92478 1.0029 2.7350 2.9764 1.0640 3.2986 3.6959 35351 14.5M 6.86M 1.0012 1.2373 1.2994 1.0012 1.2381 1.3004 542 13471 3393 1.0000 1.5158 1.3218 1.0000 1.5199 1.3280 1076 12605 5932 1.0000 1.3812 1.3873 1.0000 1.3812 1.3873 brutomesso/simple_processor 41736 1.66M 0.58M 1.0000 1.3726 1.6326 1.0000 1.3726 1.6326 uclid_contrib_smtcomp09 46156 1.84M 0.61M 1.0057 1.0584 1.0906 1.0068 1.0720 1.1125 uclid/catchconv 5.03M 63.5M 34.8M 1.0002 1.0711 1.0619 1.0002 1.0748 1.0631 brummayerbiere3 24289 2.46M 0.83M 1.0000 1.0144 1.0137 1.0000 1.0169 1.0175 brutomesso/lfsr 0.8M 71.9M 28.7M 1.0000 1.2367 1.3153 1.0038 1.2399 1.3188 spear/samba_v3.0.24 9.4M 993M 338M 1.0000 1.0322 1.0480 1.0000 1.0380 1.0568 spear/inn_v2.4.3 0.11M 216M 46.4M 1.0048 1.0024 1.0055 1.0067 1.0040 1.0071 stp 0.32M 5.2M 3.39M 1.0000 1.0025 1.0021 1.0000 1.0025 1.0021 spear/wget_v1.10.2 15364 85.8M 19.6M 1.0000 1.0006 1.0013 1.0017 1.0053 1.0019 brummayerbiere2 62564 71.9M 12.8M 1.0000 1.3639 1.0038 1.0000 1.3639 1.0038 calypto 11786 0.74M 0.29M 1.0448 1.3839 1.4321 1.0448 1.3963 1.4375 brutomesso/core 6.49M 106M 40.9M 1.0370 1.3788 1.5262 pipe brummayerbiere wienand-cav2008/Booth uum 1.0111 1.3442 1.4920 Run-time in seconds Solved Instances Family Boolector Mathsat STP spear/openldap_v 2.3.35 Hazel10 Boolector Mathsat STP Hazel1000 Hazel10 Hazel1000 1924 1200 1204 600 19 5 6 6 7 8 pipe 325 600 600 155 600 1 0 0 1 0 brummayerbiere wienandcav2008/Booth 907 4994 736 709 711 41 36 40 41 41 21 19 45 26 26 2 2 2 2 2 16 29 15 12 12 2 2 2 2 2 1908 22488 5156 266 266 64 29 59 64 64 7 7 7 7 414 414 414 414 uum brutomesso/simpl e_processor uclid_contrib_smt comp09 uclid/catchconv 783 268 770 200 169 7 9015 201 19 8 7 414 Related Work • Normal forms for concat/extract are well-known (see ref’s in the paper) • Our work identifies and defines the class of BP operations; our approach is integrated into a modern eager SMT solver • A DPLL(T) theory solver for extract, concat and equality applied within lazy SMT solving was proposed in ICCAD’09, Brottomesso&Sharygina • Our algorithms are integrated into an eager SMT solver; we define and handle 10 BP ops, but not equalities. • Bit-level sharing of CNF variables for concat/extract is known in the community and applied by various solvers, but AFAIK not published • Any bit-level solution lacks the word-level hashing ability • Essential algorithms used in BV preprocessing are often unpublishedο Conclusion • We identified and defined a class of Bit-Vector (BV) operations, called Bit-Propagating (BP) • We proposed an algorithm for handling BP operations efficiently during online preprocessing in eager BV solving • We demonstrated a performance boost across various SMT-LIB families Bit-Propagating Normal Form (BPNF) • A variable is bit-propagating iff it was created by a bit- propagating operation, otherwise it’s non-bit-propagating • A segment is either • A constant, e.g., 0100100, or • A bit-range, that is a sequence of consecutive bits of a non-bit- propagating variable, e.g., v[3:1]=[v[3], v[2], v[1]] • Segments s2 and s1 (in the specified order) are mergeable if • Both s2 and s1 are constants, or • Both s2 and s1 are bit-ranges, such that s2 = v[k:j+1] and s1 = v[j:i] • BPNF(v) is a sequence of segments, where each pair of neighbor segments is non-mergeable Calculating a BPNF for BP Operations Bit-prop. M(s,t) = s,t for non-mergeable s,t M(c1, c2) = concat(c1, c2) if c1,c2 are constants e.g., M(10,01) = 1001 M(v[k:j+1], v[j:i]) = v[k,i] Merge operation u=concat(v,y)={vs(v),…,v1,M(v0,ys(y)), ys(y)-1…,y1, y0} v = {vs(v),…,v1, v0} y = {ys(y),…,y1, y0} concat extract bvshl* bvlshr* bvashr* repeat zero_extend sign_extend rotate_left rotate_right Calculating a BPNF for BP Operations Bit-prop. The number of bit i in its segment The segment number of bit i u=extract(v,j,i)={vsn(j)[sb(j):0] ,vsn(j)-1,…,vsn(i)+1,vsn(i)[end:sb(i)]} concat extract bvshl* bvlshr* bvashr* repeat zero_extend sign_extend rotate_left rotate_right v = {vs(v),…,v1, v0} The last defined bit in vsn(i) Calculating a BPNF for BP Operations Bit-prop. The remaining operations can be reduced to concat/extract (see the paper for details) concat extract bvshl* bvlshr* bvashr* repeat zero_extend sign_extend rotate_left rotate_right * Shift by a constant is bit-propagating; shift by a non-constant is arithmetic