\myheading{Arithmetical shift bit twiddling hack} Prove that \verb|((x+0x80000000) >>u n) - (0x80000000 >>u n)| works like arithmetical shift (\verb|bvashr| function in SMT-LIB or \verb|SAR| x86 instruction). See: Henry Warren 2ed: "2-7 Shift Right Signed from Unsigned". Also, check if I implemented signed shift right correctly in my MK85: % FIXME: move this to the MK85 section \begin{lstlisting}[style=customc] // direction=false for shift left // direction=true for shift right // arith=true is for bvashr (only for shifting right) // for 8-bit left shifter, this is: // X=ITE(cnt&1, X<<1, X) // X=ITE((cnt>>1)&1, X<<2, X) // X=ITE((cnt>>2)&1, X<<4, X) // i.e., if the bit is set in cnt, shift X by that amount of bits, or do nothing otherwise struct SMT_var* gen_shifter_real (struct ctx* ctx, struct SMT_var* X, struct SMT_var* cnt, bool direction, bool arith) { int w=X->width; struct SMT_var* in=X; struct SMT_var* out; struct SMT_var* tmp; // bit vector must have width=2^x, i.e., 8, 16, 32, 64, etc // FIXME better func name: assert (popcount64c (w)==1); int bits_in_selector=mylog2(w); for (int i=0; ivar_always_false->SAT_var); out=create_internal_variable(ctx, "tmp", TY_BITVEC, w); add_Tseitin_ITE_BV (ctx, cnt->SAT_var+i, tmp->SAT_var, in->SAT_var, out->SAT_var, w); in=out; }; // if any bit is set in high part of "cnt" variable, result is 0 // i.e., if a 8-bit bitvector is shifted by cnt>8, give a zero struct SMT_var *disable_shifter=create_internal_variable(ctx, "...", TY_BOOL, 1); add_Tseitin_OR_list(ctx, cnt->SAT_var+bits_in_selector, w-bits_in_selector, disable_shifter->SAT_var); // 0x80 >>s cnt, where cnt>8, must be 0xff! so fill result with MSB(input) struct SMT_var *default_val; if (arith==false) default_val=gen_const(ctx, 0, w); else default_val=gen_repeat_from_SAT_var(ctx, MSB_of_SMT_var(X), 1, w); return gen_ITE(ctx, disable_shifter, default_val, in); }; struct SMT_var* gen_shifter (struct ctx* ctx, struct SMT_var* X, struct SMT_var* cnt, bool direction, bool arith) { int w=X->width; // FIXME: better func name: if (popcount64c (w)!=1) { // X is not in 2^n form, so extend it // RATIONALE: input must be in $2^n$ form, so the shift count will be $n$ //printf ("%s() width=%d\n", __FUNCTION__, w); int new_w=1<<(mylog2(w)+1); //printf ("%s() extending it to width=%d\n", __FUNCTION__, new_w); X=gen_zero_extend(ctx, X, new_w-w); cnt=gen_zero_extend(ctx, cnt, new_w-w); } struct SMT_var* rt=gen_shifter_real(ctx, X, cnt, direction, arith); if (popcount64c (w)!=1) { // if X is not in 2^n form rt=gen_extract (ctx, rt, 0, w); }; return rt; }; struct SMT_var* gen_BVASHR (struct ctx* ctx, struct SMT_var* X, struct SMT_var* cnt) { return gen_shifter (ctx, X, cnt, true, true); }; \end{lstlisting} ( \url{\MKURL} ) In other words, we prove equivalence of the expression above and my implementation. \lstinputlisting[style=customsmt]{proofs/bvashr.smt}