From: Julian Seward Date: Sat, 6 Nov 2004 13:56:36 +0000 (+0000) Subject: Delete all the old UCode stuff. X-Git-Tag: svn/VALGRIND_3_0_1^2~824 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=79e1d19fa6b235777d1200dfb3b18a10ab16d0cd;p=thirdparty%2Fvalgrind.git Delete all the old UCode stuff. git-svn-id: svn://svn.valgrind.org/vex/trunk@510 --- diff --git a/VEX/head20041019/memcheck/mc_translate.c b/VEX/head20041019/memcheck/mc_translate.c index d39f959b95..f4701c7351 100644 --- a/VEX/head20041019/memcheck/mc_translate.c +++ b/VEX/head20041019/memcheck/mc_translate.c @@ -1,6 +1,6 @@ /*--------------------------------------------------------------------*/ -/*--- Instrument UCode to perform memory checking operations. ---*/ +/*--- Instrument IR to perform memory checking operations. ---*/ /*--- mc_translate.c ---*/ /*--------------------------------------------------------------------*/ @@ -31,1618 +31,6 @@ #include "mc_include.h" -/* --------------------------------------------------------------------- - Template functions for extending UCode - ------------------------------------------------------------------ */ - -/* Compare this with the restrictions on core instructions in - vg_translate.c:is_sane_UInstr(). Everything general said there - applies here too. -*/ -Bool SK_(sane_XUInstr)(Bool beforeRA, Bool beforeLiveness, UInstr* u) -{ -// SSS: duplicating these macros really sucks -# define LIT0 (u->lit32 == 0) -# define LIT1 (!(LIT0)) -# define LITm (u->tag1 == Literal ? True : LIT0 ) -# define SZ0 (u->size == 0) -# define SZi (u->size == 4 || u->size == 2 || u->size == 1) -# define SZj (u->size == 4 || u->size == 2 || u->size == 1 || u->size == 0) -# define CC0 (u->flags_r == FlagsEmpty && u->flags_w == FlagsEmpty) -# define TR1 (beforeRA ? (u->tag1 == TempReg) : (u->tag1 == RealReg)) -# define TR2 (beforeRA ? (u->tag2 == TempReg) : (u->tag2 == RealReg)) -# define A1 (u->tag1 == ArchReg) -# define A2 (u->tag2 == ArchReg) -# define L1 (u->tag1 == Literal && u->val1 == 0) -# define Ls1 (u->tag1 == Lit16) -# define Ls3 (u->tag3 == Lit16) -# define TRL1 (TR1 || L1) -# define N2 (u->tag2 == NoValue) -# define N3 (u->tag3 == NoValue) -# define COND0 (u->cond == 0) -# define EXTRA4b0 (u->extra4b == 0) -# define SG_WD0 (u->signed_widen == 0) -# define JMPKIND0 (u->jmpkind == 0) -# define CCALL0 (u->argc==0 && u->regparms_n==0 && u->has_ret_val==0 && \ - ( beforeLiveness \ - ? u->regs_live_after == ALL_RREGS_LIVE \ - : True )) -# define XOTHER (COND0 && EXTRA4b0 && SG_WD0 && JMPKIND0 && CCALL0) - - Int n_lits = 0; - if (u->tag1 == Literal) n_lits++; - if (u->tag2 == Literal) n_lits++; - if (u->tag3 == Literal) n_lits++; - if (n_lits > 1) - return False; - - /* Fields not checked: val1, val2, val3 */ - - switch (u->opcode) { - - /* Fields checked: lit32 size flags_r/w tag1 tag2 tag3 (rest) */ - case LOADV: return LIT0 && SZi && CC0 && TR1 && TR2 && N3 && XOTHER; - case STOREV: return LITm && SZi && CC0 && TRL1 && TR2 && N3 && XOTHER; - case GETV: return LIT0 && SZi && CC0 && A1 && TR2 && N3 && XOTHER; - case PUTV: return LITm && SZi && CC0 && TRL1 && A2 && N3 && XOTHER; - case GETVF: - case PUTVF: return LIT0 && SZ0 && CC0 && TR1 && N2 && N3 && XOTHER; - case TESTV: - case SETV: return LIT0 && SZj && CC0 && TR1 && N2 && N3 && XOTHER; - case TAG1: return LIT0 && SZ0 && CC0 && TR1 && N2 && Ls3 && XOTHER; - case TAG2: return LIT0 && SZ0 && CC0 && TR1 && TR2 && Ls3 && XOTHER; - default: - VG_(printf)("unhandled opcode: %u\n", u->opcode); - VG_(skin_panic)("SK_(sane_XUInstr): unhandled opcode"); - } -# undef LIT0 -# undef LIT1 -# undef LITm -# undef SZ0 -# undef SZi -# undef SZj -# undef CC0 -# undef TR1 -# undef TR2 -# undef A1 -# undef A2 -# undef L1 -# undef Ls1 -# undef Ls3 -# undef TRL1 -# undef N2 -# undef N3 -# undef COND0 -# undef EXTRA4b0 -# undef JMPKIND0 -# undef CCALL0 -# undef XOTHER -} - -static Char* nameOfTagOp ( TagOp h ) -{ - switch (h) { - case Tag_PCast40: return "PCast40"; - case Tag_PCast20: return "PCast20"; - case Tag_PCast10: return "PCast10"; - case Tag_PCast01: return "PCast01"; - case Tag_PCast02: return "PCast02"; - case Tag_PCast04: return "PCast04"; - case Tag_PCast14: return "PCast14"; - case Tag_PCast12: return "PCast12"; - case Tag_PCast11: return "PCast11"; - case Tag_Left4: return "Left4"; - case Tag_Left2: return "Left2"; - case Tag_Left1: return "Left1"; - case Tag_SWiden14: return "SWiden14"; - case Tag_SWiden24: return "SWiden24"; - case Tag_SWiden12: return "SWiden12"; - case Tag_ZWiden14: return "ZWiden14"; - case Tag_ZWiden24: return "ZWiden24"; - case Tag_ZWiden12: return "ZWiden12"; - case Tag_UifU4: return "UifU4"; - case Tag_UifU2: return "UifU2"; - case Tag_UifU1: return "UifU1"; - case Tag_UifU0: return "UifU0"; - case Tag_DifD4: return "DifD4"; - case Tag_DifD2: return "DifD2"; - case Tag_DifD1: return "DifD1"; - case Tag_ImproveAND4_TQ: return "ImproveAND4_TQ"; - case Tag_ImproveAND2_TQ: return "ImproveAND2_TQ"; - case Tag_ImproveAND1_TQ: return "ImproveAND1_TQ"; - case Tag_ImproveOR4_TQ: return "ImproveOR4_TQ"; - case Tag_ImproveOR2_TQ: return "ImproveOR2_TQ"; - case Tag_ImproveOR1_TQ: return "ImproveOR1_TQ"; - case Tag_DebugFn: return "DebugFn"; - default: VG_(skin_panic)("vg_nameOfTagOp"); - } -} - - -Char* SK_(name_XUOpcode)(Opcode opc) -{ - switch (opc) { - case GETVF: return "GETVF"; - case PUTVF: return "PUTVF"; - case TAG1: return "TAG1"; - case TAG2: return "TAG2"; - case LOADV: return "LOADV"; - case STOREV: return "STOREV"; - case GETV: return "GETV"; - case PUTV: return "PUTV"; - case TESTV: return "TESTV"; - case SETV: return "SETV"; - default: - VG_(printf)("unhandled opcode: %u\n", opc); - VG_(skin_panic)("SK_(name_XUOpcode): unhandled case"); - } -} - -/* --------------------------------------------------------------------- - Debugging stuff. - ------------------------------------------------------------------ */ - -void SK_(pp_XUInstr)(UInstr* u) -{ - switch (u->opcode) { - case TAG1: - VG_(pp_UOperand)(u, 1, 4, False); - VG_(printf)(" = %s ( ", nameOfTagOp( u->val3 )); - VG_(pp_UOperand)(u, 1, 4, False); - VG_(printf)(" )"); - break; - - case TAG2: - VG_(pp_UOperand)(u, 2, 4, False); - VG_(printf)(" = %s ( ", nameOfTagOp( u->val3 )); - VG_(pp_UOperand)(u, 1, 4, False); - VG_(printf)(", "); - VG_(pp_UOperand)(u, 2, 4, False); - VG_(printf)(" )"); - break; - - case STOREV: case LOADV: - VG_(pp_UOperand)(u, 1, u->size, u->opcode==LOADV); - VG_(printf)(", "); - VG_(pp_UOperand)(u, 2, u->size, u->opcode==STOREV); - break; - - case PUTVF: case GETVF: - VG_(pp_UOperand)(u, 1, 0, False); - break; - - case GETV: case PUTV: - VG_(pp_UOperand)(u, 1, u->opcode==PUTV ? 4 : u->size, False); - VG_(printf)(", "); - VG_(pp_UOperand)(u, 2, u->opcode==GETV ? 4 : u->size, False); - break; - - case TESTV: case SETV: - VG_(pp_UOperand)(u, 1, u->size, False); - break; - - default: - VG_(printf)("unhandled opcode: %u\n", u->opcode); - VG_(skin_panic)("SK_(pp_XUInstr): unhandled opcode"); - } - -} - -Int SK_(get_Xreg_usage)(UInstr* u, Tag tag, Int* regs, Bool* isWrites) -{ -# define RD(ono) VG_UINSTR_READS_REG(ono, regs, isWrites) -# define WR(ono) VG_UINSTR_WRITES_REG(ono, regs, isWrites) - - Int n = 0; - switch (u->opcode) { - case TAG1: RD(1); WR(1); break; - case TAG2: RD(1); RD(2); WR(2); break; - case LOADV: RD(1); WR(2); break; - case STOREV: RD(1); RD(2); break; - case GETV: WR(2); break; - case PUTV: RD(1); break; - case TESTV: RD(1); break; - case SETV: WR(1); break; - case PUTVF: RD(1); break; - case GETVF: WR(1); break; - - default: - VG_(printf)("unhandled opcode: %u\n", u->opcode); - VG_(skin_panic)("SK_(get_Xreg_usage): unhandled opcode"); - } - return n; - -# undef RD -# undef WR -} - -/*------------------------------------------------------------*/ -/*--- New instrumentation machinery. ---*/ -/*------------------------------------------------------------*/ -#if 0 -static -TagOp get_Tag_ImproveOR_TQ ( Int sz ) -{ - switch (sz) { - case 4: return Tag_ImproveOR4_TQ; - case 2: return Tag_ImproveOR2_TQ; - case 1: return Tag_ImproveOR1_TQ; - default: VG_(skin_panic)("get_Tag_ImproveOR_TQ"); - } -} - - -static -TagOp get_Tag_ImproveAND_TQ ( Int sz ) -{ - switch (sz) { - case 4: return Tag_ImproveAND4_TQ; - case 2: return Tag_ImproveAND2_TQ; - case 1: return Tag_ImproveAND1_TQ; - default: VG_(skin_panic)("get_Tag_ImproveAND_TQ"); - } -} - - -static -TagOp get_Tag_Left ( Int sz ) -{ - switch (sz) { - case 4: return Tag_Left4; - case 2: return Tag_Left2; - case 1: return Tag_Left1; - default: VG_(skin_panic)("get_Tag_Left"); - } -} - - -static -TagOp get_Tag_UifU ( Int sz ) -{ - switch (sz) { - case 4: return Tag_UifU4; - case 2: return Tag_UifU2; - case 1: return Tag_UifU1; - case 0: return Tag_UifU0; - default: VG_(skin_panic)("get_Tag_UifU"); - } -} - - -static -TagOp get_Tag_DifD ( Int sz ) -{ - switch (sz) { - case 4: return Tag_DifD4; - case 2: return Tag_DifD2; - case 1: return Tag_DifD1; - default: VG_(skin_panic)("get_Tag_DifD"); - } -} - - -static -TagOp get_Tag_PCast ( Int szs, Int szd ) -{ - if (szs == 4 && szd == 0) return Tag_PCast40; - if (szs == 2 && szd == 0) return Tag_PCast20; - if (szs == 1 && szd == 0) return Tag_PCast10; - if (szs == 0 && szd == 1) return Tag_PCast01; - if (szs == 0 && szd == 2) return Tag_PCast02; - if (szs == 0 && szd == 4) return Tag_PCast04; - if (szs == 1 && szd == 4) return Tag_PCast14; - if (szs == 1 && szd == 2) return Tag_PCast12; - if (szs == 1 && szd == 1) return Tag_PCast11; - VG_(printf)("get_Tag_PCast(%d,%d)\n", szs, szd); - VG_(skin_panic)("get_Tag_PCast"); -} - - -static -TagOp get_Tag_Widen ( Bool syned, Int szs, Int szd ) -{ - if (szs == 1 && szd == 2 && syned) return Tag_SWiden12; - if (szs == 1 && szd == 2 && !syned) return Tag_ZWiden12; - - if (szs == 1 && szd == 4 && syned) return Tag_SWiden14; - if (szs == 1 && szd == 4 && !syned) return Tag_ZWiden14; - - if (szs == 2 && szd == 4 && syned) return Tag_SWiden24; - if (szs == 2 && szd == 4 && !syned) return Tag_ZWiden24; - - VG_(printf)("get_Tag_Widen(%d,%d,%d)\n", (Int)syned, szs, szd); - VG_(skin_panic)("get_Tag_Widen"); -} - -/* Pessimally cast the spec'd shadow from one size to another. */ -static -void create_PCast ( UCodeBlock* cb, Int szs, Int szd, Int tempreg ) -{ - if (szs == 0 && szd == 0) - return; - uInstr3(cb, TAG1, 0, TempReg, tempreg, - NoValue, 0, - Lit16, get_Tag_PCast(szs,szd)); -} - - -/* Create a signed or unsigned widen of the spec'd shadow from one - size to another. The only allowed size transitions are 1->2, 1->4 - and 2->4. */ -static -void create_Widen ( UCodeBlock* cb, Bool signed_widen, - Int szs, Int szd, Int tempreg ) -{ - if (szs == szd) return; - uInstr3(cb, TAG1, 0, TempReg, tempreg, - NoValue, 0, - Lit16, get_Tag_Widen(signed_widen,szs,szd)); -} - - -/* Get the condition codes into a new shadow, at the given size. */ -static -Int create_GETVF ( UCodeBlock* cb, Int sz ) -{ - Int tt = newShadow(cb); - uInstr1(cb, GETVF, 0, TempReg, tt); - create_PCast(cb, 0, sz, tt); - return tt; -} - - -/* Save the condition codes from the spec'd shadow. */ -static -void create_PUTVF ( UCodeBlock* cb, Int sz, Int tempreg ) -{ - if (sz == 0) { - uInstr1(cb, PUTVF, 0, TempReg, tempreg); - } else { - Int tt = newShadow(cb); - uInstr2(cb, MOV, 4, TempReg, tempreg, TempReg, tt); - create_PCast(cb, sz, 0, tt); - uInstr1(cb, PUTVF, 0, TempReg, tt); - } -} - - -/* Do Left on the spec'd shadow. */ -static -void create_Left ( UCodeBlock* cb, Int sz, Int tempreg ) -{ - uInstr3(cb, TAG1, 0, - TempReg, tempreg, - NoValue, 0, - Lit16, get_Tag_Left(sz)); -} - - -/* Do UifU on ts and td, putting the result in td. */ -static -void create_UifU ( UCodeBlock* cb, Int sz, Int ts, Int td ) -{ - uInstr3(cb, TAG2, 0, TempReg, ts, TempReg, td, - Lit16, get_Tag_UifU(sz)); -} - - -/* Do DifD on ts and td, putting the result in td. */ -static -void create_DifD ( UCodeBlock* cb, Int sz, Int ts, Int td ) -{ - uInstr3(cb, TAG2, 0, TempReg, ts, TempReg, td, - Lit16, get_Tag_DifD(sz)); -} - - -/* Do HelpAND on value tval and tag tqqq, putting the result in - tqqq. */ -static -void create_ImproveAND_TQ ( UCodeBlock* cb, Int sz, Int tval, Int tqqq ) -{ - uInstr3(cb, TAG2, 0, TempReg, tval, TempReg, tqqq, - Lit16, get_Tag_ImproveAND_TQ(sz)); -} - - -/* Do HelpOR on value tval and tag tqqq, putting the result in - tqqq. */ -static -void create_ImproveOR_TQ ( UCodeBlock* cb, Int sz, Int tval, Int tqqq ) -{ - uInstr3(cb, TAG2, 0, TempReg, tval, TempReg, tqqq, - Lit16, get_Tag_ImproveOR_TQ(sz)); -} - - -/* Get the shadow for an operand described by (tag, val). Emit code - to do this and return the identity of the shadow holding the - result. The result tag is always copied into a new shadow, so it - can be modified without trashing the original.*/ -static -Int /* TempReg */ getOperandShadow ( UCodeBlock* cb, - Int sz, Int tag, Int val ) -{ - Int sh; - sh = newShadow(cb); - if (tag == TempReg) { - uInstr2(cb, MOV, 4, TempReg, SHADOW(val), TempReg, sh); - return sh; - } - if (tag == Literal) { - uInstr1(cb, SETV, sz, TempReg, sh); - return sh; - } - if (tag == ArchReg) { - uInstr2(cb, GETV, sz, ArchReg, val, TempReg, sh); - return sh; - } - VG_(skin_panic)("getOperandShadow"); -} - -/* Create and return an instrumented version of cb_in. Free cb_in - before returning. */ -static UCodeBlock* memcheck_instrument ( UCodeBlock* cb_in ) -{ - UCodeBlock* cb; - Int i, j; - UInstr* u_in; - Int qs, qd, qt, qtt; - Bool bogusLiterals; - - cb = VG_(setup_UCodeBlock)(cb_in); - - /* Scan the block to look for bogus literals. These are magic - numbers which particularly appear in hand-optimised / inlined - implementations of strlen() et al which cause so much trouble - (spurious reports of uninit-var uses). Purpose of this horrible - hack is to disable some checks any such literals are present in - this basic block. */ - bogusLiterals = False; - - if (MC_(clo_avoid_strlen_errors)) { - for (i = 0; i < VG_(get_num_instrs)(cb_in); i++) { - u_in = VG_(get_instr)(cb_in, i); - switch (u_in->opcode) { - case ADD: case SUB: case MOV: - if (u_in->size == 4 && u_in->tag1 == Literal) - goto literal; - break; - case LEA1: - sk_assert(u_in->size == 4); - goto literal; - default: - break; - } - continue; - literal: - if (u_in->lit32 == 0xFEFEFEFF || - u_in->lit32 == 0x80808080 || - u_in->lit32 == 0x00008080) { - bogusLiterals = True; - break; - } - } - } - - for (i = 0; i < VG_(get_num_instrs)(cb_in); i++) { - u_in = VG_(get_instr)(cb_in, i); - qs = qd = qt = qtt = INVALID_TEMPREG; - - switch (u_in->opcode) { - - case LOCK: - case NOP: - break; - - case INCEIP: - VG_(copy_UInstr)(cb, u_in); - break; - - /* The segment registers do not have their definedness - tracked. We therefore make fake shadows on GETSEG and - test them on PUTSEG. This will catch writing garbage to a - segment register; therefore we can assume it to be defined - when read (GETSEGd). Since the first arg of USESEG is - fetched by GETSEG, we can assume it to be defined, and so - the definedness of the result is simply the definedness of - the second (virtual_address) arg of USESEG. The upshot of - all this is that instrumentation of USESEG is a no-op! */ - - case PUTSEG: - sk_assert(u_in->tag1 == TempReg); - uInstr1(cb, TESTV, 2, TempReg, SHADOW(u_in->val1)); - uInstr1(cb, SETV, 2, TempReg, SHADOW(u_in->val1)); - VG_(copy_UInstr)(cb, u_in); - break; - - case GETSEG: - sk_assert(u_in->tag2 == TempReg); - uInstr1(cb, SETV, 2, TempReg, SHADOW(u_in->val2)); - VG_(copy_UInstr)(cb, u_in); - break; - - case USESEG: - VG_(copy_UInstr)(cb, u_in); - break; - - /* Loads and stores. Test the V bits for the address. 24 - Mar 02: since the address is A-checked anyway, there's not - really much point in doing the V-check too, unless you - think that you might use addresses which are undefined but - still addressible. Hence the optionalisation of the V - check. 15 Dec 02: optionalisation removed, since it no - longer makes much sense given we also have an addrcheck - tool. - - The LOADV/STOREV does an addressibility check for the - address. */ - - case LOAD: - uInstr1(cb, TESTV, 4, TempReg, SHADOW(u_in->val1)); - uInstr1(cb, SETV, 4, TempReg, SHADOW(u_in->val1)); - uInstr2(cb, LOADV, u_in->size, - TempReg, u_in->val1, - TempReg, SHADOW(u_in->val2)); - VG_(copy_UInstr)(cb, u_in); - break; - - case STORE: - uInstr1(cb, TESTV, 4, TempReg, SHADOW(u_in->val2)); - uInstr1(cb, SETV, 4, TempReg, SHADOW(u_in->val2)); - uInstr2(cb, STOREV, u_in->size, - TempReg, SHADOW(u_in->val1), - TempReg, u_in->val2); - VG_(copy_UInstr)(cb, u_in); - break; - - /* Moving stuff around. Make the V bits follow accordingly, - but don't do anything else. */ - - case GET: - uInstr2(cb, GETV, u_in->size, - ArchReg, u_in->val1, - TempReg, SHADOW(u_in->val2)); - VG_(copy_UInstr)(cb, u_in); - break; - - case PUT: - uInstr2(cb, PUTV, u_in->size, - TempReg, SHADOW(u_in->val1), - ArchReg, u_in->val2); - VG_(copy_UInstr)(cb, u_in); - break; - - case GETF: - /* This is not the smartest way to do it, but should work. */ - qd = create_GETVF(cb, u_in->size); - uInstr2(cb, MOV, 4, TempReg, qd, TempReg, SHADOW(u_in->val1)); - VG_(copy_UInstr)(cb, u_in); - break; - - case PUTF: - create_PUTVF(cb, u_in->size, SHADOW(u_in->val1)); - VG_(copy_UInstr)(cb, u_in); - break; - - case MOV: - switch (u_in->tag1) { - case TempReg: - uInstr2(cb, MOV, 4, - TempReg, SHADOW(u_in->val1), - TempReg, SHADOW(u_in->val2)); - break; - case Literal: - uInstr1(cb, SETV, u_in->size, - TempReg, SHADOW(u_in->val2)); - break; - default: - VG_(skin_panic)("memcheck_instrument: MOV"); - } - VG_(copy_UInstr)(cb, u_in); - break; - - /* Special case of add, where one of the operands is a literal. - lea1(t) = t + some literal. - Therefore: lea1#(qa) = left(qa) - */ - case LEA1: - sk_assert(u_in->size == 4 && !VG_(any_flag_use)(u_in)); - qs = SHADOW(u_in->val1); - qd = SHADOW(u_in->val2); - uInstr2(cb, MOV, 4, TempReg, qs, TempReg, qd); - create_Left(cb, u_in->size, qd); - VG_(copy_UInstr)(cb, u_in); - break; - - /* Another form of add. - lea2(ts,tt,shift) = ts + (tt << shift); shift is a literal - and is 0,1,2 or 3. - lea2#(qs,qt) = left(qs `UifU` (qt << shift)). - Note, subtly, that the shift puts zeroes at the bottom of qt, - meaning Valid, since the corresponding shift of tt puts - zeroes at the bottom of tb. - */ - case LEA2: { - Int shift; - sk_assert(u_in->size == 4 && !VG_(any_flag_use)(u_in)); - switch (u_in->extra4b) { - case 1: shift = 0; break; - case 2: shift = 1; break; - case 4: shift = 2; break; - case 8: shift = 3; break; - default: VG_(skin_panic)( "memcheck_instrument(LEA2)" ); - } - qs = SHADOW(u_in->val1); - qt = SHADOW(u_in->val2); - qd = SHADOW(u_in->val3); - uInstr2(cb, MOV, 4, TempReg, qt, TempReg, qd); - if (shift > 0) { - uInstr2(cb, SHL, 4, Literal, 0, TempReg, qd); - uLiteral(cb, shift); - } - create_UifU(cb, 4, qs, qd); - create_Left(cb, u_in->size, qd); - VG_(copy_UInstr)(cb, u_in); - break; - } - - /* inc#/dec#(qd) = q `UifU` left(qd) = left(qd) */ - case INC: case DEC: - qd = SHADOW(u_in->val1); - create_Left(cb, u_in->size, qd); - if (u_in->flags_w != FlagsEmpty) - create_PUTVF(cb, u_in->size, qd); - VG_(copy_UInstr)(cb, u_in); - break; - - /* This is a HACK (approximation :-) */ - /* rcl#/rcr#(qs,qd) - = let q0 = pcast-sz-0(qd) `UifU` pcast-sz-0(qs) `UifU` eflags# - eflags# = q0 - qd =pcast-0-sz(q0) - Ie, cast everything down to a single bit, then back up. - This assumes that any bad bits infect the whole word and - the eflags. - */ - case RCL: case RCR: - sk_assert(u_in->flags_r != FlagsEmpty); - /* The following assertion looks like it makes sense, but is - actually wrong. Consider this: - rcll %eax - imull %eax, %eax - The rcll writes O and C but so does the imull, so the O and C - write of the rcll is annulled by the prior improvement pass. - Noticed by Kevin Ryde - */ - /* sk_assert(u_in->flags_w != FlagsEmpty); */ - qs = getOperandShadow(cb, 1, u_in->tag1, u_in->val1); - /* We can safely modify qs; cast it to 0-size. */ - create_PCast(cb, 1, 0, qs); - qd = SHADOW(u_in->val2); - create_PCast(cb, u_in->size, 0, qd); - /* qs is cast-to-0(shift count#), and qd is cast-to-0(value#). */ - create_UifU(cb, 0, qs, qd); - /* qs is now free; reuse it for the flag definedness. */ - qs = create_GETVF(cb, 0); - create_UifU(cb, 0, qs, qd); - create_PUTVF(cb, 0, qd); - create_PCast(cb, 0, u_in->size, qd); - VG_(copy_UInstr)(cb, u_in); - break; - - /* for OP in shl shr sar rol ror - (qs is shift count#, qd is value to be OP#d) - OP(ts,td) - OP#(qs,qd) - = pcast-1-sz(qs) `UifU` OP(ts,qd) - So we apply OP to the tag bits too, and then UifU with - the shift count# to take account of the possibility of it - being undefined. - - A bit subtle: - ROL/ROR rearrange the tag bits as per the value bits. - SHL/SHR shifts zeroes into the value, and corresponding - zeroes indicating Definedness into the tag. - SAR copies the top bit of the value downwards, and therefore - SAR also copies the definedness of the top bit too. - So in all five cases, we just apply the same op to the tag - bits as is applied to the value bits. Neat! - */ - case SHL: - case SHR: case SAR: - case ROL: case ROR: { - Int t_amount = INVALID_TEMPREG; - sk_assert(u_in->tag1 == TempReg || u_in->tag1 == Literal); - sk_assert(u_in->tag2 == TempReg); - qd = SHADOW(u_in->val2); - - /* Make qs hold shift-count# and make - t_amount be a TempReg holding the shift count. */ - if (u_in->tag1 == Literal) { - t_amount = newTemp(cb); - uInstr2(cb, MOV, 4, Literal, 0, TempReg, t_amount); - uLiteral(cb, u_in->lit32); - qs = SHADOW(t_amount); - uInstr1(cb, SETV, 1, TempReg, qs); - } else { - t_amount = u_in->val1; - qs = SHADOW(u_in->val1); - } - - uInstr2(cb, u_in->opcode, - u_in->size, - TempReg, t_amount, - TempReg, qd); - qt = newShadow(cb); - uInstr2(cb, MOV, 4, TempReg, qs, TempReg, qt); - create_PCast(cb, 1, u_in->size, qt); - create_UifU(cb, u_in->size, qt, qd); - VG_(copy_UInstr)(cb, u_in); - break; - } - - /* One simple tag operation. */ - case WIDEN: - sk_assert(u_in->tag1 == TempReg); - create_Widen(cb, u_in->signed_widen, u_in->extra4b, u_in->size, - SHADOW(u_in->val1)); - VG_(copy_UInstr)(cb, u_in); - break; - - /* not#(x) = x (since bitwise independent) */ - case NOT: - sk_assert(u_in->tag1 == TempReg); - VG_(copy_UInstr)(cb, u_in); - break; - - /* neg#(x) = left(x) (derivable from case for SUB) */ - case NEG: - sk_assert(u_in->tag1 == TempReg); - create_Left(cb, u_in->size, SHADOW(u_in->val1)); - VG_(copy_UInstr)(cb, u_in); - break; - - /* bswap#(x) = bswap(x) */ - case BSWAP: - sk_assert(u_in->tag1 == TempReg); - sk_assert(u_in->size == 4); - qd = SHADOW(u_in->val1); - uInstr1(cb, BSWAP, 4, TempReg, qd); - VG_(copy_UInstr)(cb, u_in); - break; - - /* cc2val#(qd) = pcast-0-to-size(eflags#) */ - case CC2VAL: - sk_assert(u_in->tag1 == TempReg); - sk_assert(u_in->flags_r != FlagsEmpty); - qt = create_GETVF(cb, u_in->size); - uInstr2(cb, MOV, 4, TempReg, qt, TempReg, SHADOW(u_in->val1)); - VG_(copy_UInstr)(cb, u_in); - break; - - /* cmov#(qs,qd) = cmov(qs,qd) - That is, do the cmov of tags using the same flags as for - the data (obviously). However, first do a test on the - validity of the flags. - */ - case CMOV: - sk_assert(u_in->size == 4); - sk_assert(u_in->tag1 == TempReg); - sk_assert(u_in->tag2 == TempReg); - sk_assert(u_in->flags_r != FlagsEmpty); - sk_assert(u_in->flags_w == FlagsEmpty); - qs = SHADOW(u_in->val1); - qd = SHADOW(u_in->val2); - qt = create_GETVF(cb, 0); - uInstr1(cb, TESTV, 0, TempReg, qt); - /* qt should never be referred to again. Nevertheless - ... */ - uInstr1(cb, SETV, 0, TempReg, qt); - - uInstr2(cb, CMOV, 4, TempReg, qs, TempReg, qd); - uCond(cb, u_in->cond); - uFlagsRWU(cb, u_in->flags_r, u_in->flags_w, FlagsEmpty); - - VG_(copy_UInstr)(cb, u_in); - break; - - /* add#/sub#(qs,qd) - = qs `UifU` qd `UifU` left(qs) `UifU` left(qd) - = left(qs) `UifU` left(qd) - = left(qs `UifU` qd) - adc#/sbb#(qs,qd) - = left(qs `UifU` qd) `UifU` pcast(eflags#) - Second arg (dest) is TempReg. - First arg (src) is Literal or TempReg or ArchReg. - */ - case ADD: case SUB: - case ADC: case SBB: - case MUL: - qd = SHADOW(u_in->val2); - qs = getOperandShadow(cb, u_in->size, u_in->tag1, u_in->val1); - create_UifU(cb, u_in->size, qs, qd); - create_Left(cb, u_in->size, qd); - if (u_in->opcode == ADC || u_in->opcode == SBB) { - sk_assert(u_in->flags_r != FlagsEmpty); - qt = create_GETVF(cb, u_in->size); - create_UifU(cb, u_in->size, qt, qd); - } - if (u_in->flags_w != FlagsEmpty) { - create_PUTVF(cb, u_in->size, qd); - } - VG_(copy_UInstr)(cb, u_in); - break; - - /* xor#(qs,qd) = qs `UifU` qd */ - case XOR: - qd = SHADOW(u_in->val2); - qs = getOperandShadow(cb, u_in->size, u_in->tag1, u_in->val1); - create_UifU(cb, u_in->size, qs, qd); - if (u_in->flags_w != FlagsEmpty) { - create_PUTVF(cb, u_in->size, qd); - } - VG_(copy_UInstr)(cb, u_in); - break; - - /* and#/or#(qs,qd) - = (qs `UifU` qd) `DifD` improve(vs,qs) - `DifD` improve(vd,qd) - where improve is the relevant one of - Improve{AND,OR}_TQ - Use the following steps, with qt as a temp: - qt = improve(vd,qd) - qd = qs `UifU` qd - qd = qt `DifD` qd - qt = improve(vs,qs) - qd = qt `DifD` qd - */ - case AND: case OR: - sk_assert(u_in->tag1 == TempReg); - sk_assert(u_in->tag2 == TempReg); - qd = SHADOW(u_in->val2); - qs = SHADOW(u_in->val1); - qt = newShadow(cb); - - /* qt = improve(vd,qd) */ - uInstr2(cb, MOV, 4, TempReg, qd, TempReg, qt); - if (u_in->opcode == AND) - create_ImproveAND_TQ(cb, u_in->size, u_in->val2, qt); - else - create_ImproveOR_TQ(cb, u_in->size, u_in->val2, qt); - /* qd = qs `UifU` qd */ - create_UifU(cb, u_in->size, qs, qd); - /* qd = qt `DifD` qd */ - create_DifD(cb, u_in->size, qt, qd); - /* qt = improve(vs,qs) */ - uInstr2(cb, MOV, 4, TempReg, qs, TempReg, qt); - if (u_in->opcode == AND) - create_ImproveAND_TQ(cb, u_in->size, u_in->val1, qt); - else - create_ImproveOR_TQ(cb, u_in->size, u_in->val1, qt); - /* qd = qt `DifD` qd */ - create_DifD(cb, u_in->size, qt, qd); - /* So, finally qd is the result tag. */ - if (u_in->flags_w != FlagsEmpty) { - create_PUTVF(cb, u_in->size, qd); - } - VG_(copy_UInstr)(cb, u_in); - break; - - /* Machinery to do with supporting CALLM. Copy the start and - end markers only to make the result easier to read - (debug); they generate no code and have no effect. - */ - case CALLM_S: case CALLM_E: - VG_(copy_UInstr)(cb, u_in); - break; - - /* Copy PUSH and POP verbatim. Arg/result absval - calculations are done when the associated CALL is - processed. CLEAR has no effect on absval calculations but - needs to be copied. - */ - case PUSH: case POP: case CLEAR: - VG_(copy_UInstr)(cb, u_in); - break; - - /* In short: - callm#(a1# ... an#) = (a1# `UifU` ... `UifU` an#) - We have to decide on a size to do the computation at, - although the choice doesn't affect correctness. We will - do a pcast to the final size anyway, so the only important - factor is to choose a size which minimises the total - number of casts needed. Valgrind: just use size 0, - regardless. It may not be very good for performance - but does simplify matters, mainly by reducing the number - of different pessimising casts which have to be implemented. - */ - case CALLM: { - UInstr* uu; - Bool res_used; - - /* Now generate the code. Get the final result absval - into qt. */ - qt = newShadow(cb); - qtt = newShadow(cb); - uInstr1(cb, SETV, 0, TempReg, qt); - for (j = i-1; VG_(get_instr)(cb_in, j)->opcode != CALLM_S; j--) { - uu = VG_(get_instr)(cb_in, j); - if (uu->opcode != PUSH) continue; - /* cast via a temporary */ - uInstr2(cb, MOV, 4, TempReg, SHADOW(uu->val1), - TempReg, qtt); - create_PCast(cb, uu->size, 0, qtt); - create_UifU(cb, 0, qtt, qt); - } - /* Remembering also that flags read count as inputs. */ - if (u_in->flags_r != FlagsEmpty) { - qtt = create_GETVF(cb, 0); - create_UifU(cb, 0, qtt, qt); - } - - /* qt now holds the result tag. If any results from the - call are used, either by fetching with POP or - implicitly by writing the flags, we copy the result - absval to the relevant location. If not used, the call - must have been for its side effects, so we test qt here - and now. Note that this assumes that all values - removed by POP continue to be live. So dead args - *must* be removed with CLEAR, not by POPping them into - a dummy tempreg. - */ - res_used = False; - for (j = i+1; VG_(get_instr)(cb_in, j)->opcode != CALLM_E; j++) { - uu = VG_(get_instr)(cb_in, j); - if (uu->opcode != POP) continue; - /* Cast via a temp. */ - uInstr2(cb, MOV, 4, TempReg, qt, TempReg, qtt); - create_PCast(cb, 0, uu->size, qtt); - uInstr2(cb, MOV, 4, TempReg, qtt, - TempReg, SHADOW(uu->val1)); - res_used = True; - } - if (u_in->flags_w != FlagsEmpty) { - create_PUTVF(cb, 0, qt); - res_used = True; - } - if (!res_used) { - uInstr1(cb, TESTV, 0, TempReg, qt); - /* qt should never be referred to again. Nevertheless - ... */ - uInstr1(cb, SETV, 0, TempReg, qt); - } - VG_(copy_UInstr)(cb, u_in); - break; - } - /* Whew ... */ - - case JMP: - if (u_in->tag1 == TempReg) { - uInstr1(cb, TESTV, 4, TempReg, SHADOW(u_in->val1)); - uInstr1(cb, SETV, 4, TempReg, SHADOW(u_in->val1)); - } else { - sk_assert(u_in->tag1 == Literal); - } - if (u_in->cond != CondAlways) { - sk_assert(u_in->flags_r != FlagsEmpty); - qt = create_GETVF(cb, 0); - if (/* HACK */ bogusLiterals) { - if (0) - VG_(printf)("ignore TESTV due to bogus literal\n"); - } else { - uInstr1(cb, TESTV, 0, TempReg, qt); - } - /* qt should never be referred to again. Nevertheless - ... */ - uInstr1(cb, SETV, 0, TempReg, qt); - } - VG_(copy_UInstr)(cb, u_in); - break; - - case JIFZ: - uInstr1(cb, TESTV, 4, TempReg, SHADOW(u_in->val1)); - uInstr1(cb, SETV, 4, TempReg, SHADOW(u_in->val1)); - VG_(copy_UInstr)(cb, u_in); - break; - - /* Emit a check on the address used. The value loaded into the - FPU is checked by the call to fpu_{read/write}_check(). */ - case MMX2_MemRd: case MMX2_MemWr: - case FPU_R: case FPU_W: { - Int t_size = INVALID_TEMPREG; - Bool is_load; - - if (u_in->opcode == MMX2_MemRd || u_in->opcode == MMX2_MemWr) - sk_assert(u_in->size == 4 || u_in->size == 8); - - is_load = u_in->opcode==FPU_R || u_in->opcode==MMX2_MemRd; - sk_assert(u_in->tag2 == TempReg); - uInstr1(cb, TESTV, 4, TempReg, SHADOW(u_in->val2)); - uInstr1(cb, SETV, 4, TempReg, SHADOW(u_in->val2)); - - t_size = newTemp(cb); - uInstr2(cb, MOV, 4, Literal, 0, TempReg, t_size); - uLiteral(cb, u_in->size); - uInstr2(cb, CCALL, 0, TempReg, u_in->val2, TempReg, t_size); - uCCall(cb, is_load ? (Addr) & MC_(fpu_read_check) - : (Addr) & MC_(fpu_write_check), - 2, 2, False); - - VG_(copy_UInstr)(cb, u_in); - break; - } - - case MMX2a1_MemRd: { - Int t_size = INVALID_TEMPREG; - - sk_assert(u_in->size == 8); - - sk_assert(u_in->tag3 == TempReg); - uInstr1(cb, TESTV, 4, TempReg, SHADOW(u_in->val3)); - uInstr1(cb, SETV, 4, TempReg, SHADOW(u_in->val3)); - - t_size = newTemp(cb); - uInstr2(cb, MOV, 4, Literal, 0, TempReg, t_size); - uLiteral(cb, u_in->size); - uInstr2(cb, CCALL, 0, TempReg, u_in->val3, TempReg, t_size); - uCCall(cb, (Addr) & MC_(fpu_read_check), 2, 2, False); - - VG_(copy_UInstr)(cb, u_in); - break; - } - - /* SSE ins referencing scalar integer registers */ - case SSE2g_RegWr: - case SSE2g1_RegWr: - case SSE2e1_RegRd: - case SSE3g_RegWr: - case SSE3e_RegRd: - case SSE3e_RegWr: - case SSE3g1_RegWr: - case SSE3e1_RegRd: - sk_assert(u_in->tag3 == TempReg); - - if (u_in->opcode == SSE2e1_RegRd || u_in->opcode == SSE3e1_RegRd) { - sk_assert(u_in->size == 2); - } else { - sk_assert(u_in->size == 4); - } - - /* Is it a read ? Better check the V bits right now. */ - if ( u_in->opcode == SSE2e1_RegRd - || u_in->opcode == SSE3e_RegRd - || u_in->opcode == SSE3e1_RegRd ) - uInstr1(cb, TESTV, u_in->size, - TempReg, SHADOW(u_in->val3)); - - /* And for both read and write, set the register to be - defined. */ - uInstr1(cb, SETV, u_in->size, - TempReg, SHADOW(u_in->val3)); - - VG_(copy_UInstr)(cb, u_in); - break; - - /* ... and the same deal for SSE insns referencing memory */ - case SSE3a_MemRd: - case SSE3a_MemWr: - case SSE2a_MemWr: - case SSE2a_MemRd: - case SSE3a1_MemRd: - case SSE2a1_MemRd: { - Bool is_load; - Int t_size; - - sk_assert(u_in->size == 4 || u_in->size == 8 - || u_in->size == 16 || u_in->size == 512); - - t_size = INVALID_TEMPREG; - is_load = u_in->opcode==SSE2a_MemRd - || u_in->opcode==SSE3a_MemRd - || u_in->opcode==SSE2a1_MemRd - || u_in->opcode==SSE3a1_MemRd; - - sk_assert(u_in->tag3 == TempReg); - - uInstr1(cb, TESTV, 4, TempReg, SHADOW(u_in->val3)); - uInstr1(cb, SETV, 4, TempReg, SHADOW(u_in->val3)); - t_size = newTemp(cb); - uInstr2(cb, MOV, 4, Literal, 0, TempReg, t_size); - uLiteral(cb, u_in->size); - uInstr2(cb, CCALL, 0, TempReg, u_in->val3, TempReg, t_size); - uCCall(cb, is_load ? (Addr) & MC_(fpu_read_check) - : (Addr) & MC_(fpu_write_check), - 2, 2, False); - - VG_(copy_UInstr)(cb, u_in); - break; - } - - case SSE3ag_MemRd_RegWr: - { - Int t_size; - - sk_assert(u_in->size == 4 || u_in->size == 8); - sk_assert(u_in->tag1 == TempReg); - uInstr1(cb, TESTV, 4, TempReg, SHADOW(u_in->val1)); - uInstr1(cb, SETV, 4, TempReg, SHADOW(u_in->val1)); - t_size = newTemp(cb); - uInstr2(cb, MOV, 4, Literal, 0, TempReg, t_size); - uLiteral(cb, u_in->size); - uInstr2(cb, CCALL, 0, TempReg, u_in->val1, TempReg, t_size); - uCCall(cb, (Addr) MC_(fpu_read_check), 2, 2, False ); - uInstr1(cb, SETV, 4, TempReg, SHADOW(u_in->val2)); - VG_(copy_UInstr)(cb, u_in); - break; - } - - /* For MMX and SSE insns not referencing memory, just - make sure the eflags are defined if the instruction - read them, and make them defined it it writes them. */ - case SSE5: case SSE4: case SSE3: - case MMX1: case MMX2: case MMX3: - case FPU: - if (u_in->flags_r != FlagsEmpty) { - qt = create_GETVF(cb, 0); - uInstr1(cb, TESTV, 0, TempReg, qt); - /* qt should never be referred to again. Nevertheless - ... */ - uInstr1(cb, SETV, 0, TempReg, qt); - } - if (u_in->flags_w != FlagsEmpty) { - qd = newTemp(cb); - uInstr2(cb, MOV, 4, Literal, 0, TempReg, qd); - uLiteral(cb, 0); - create_PUTVF(cb, 0, qd); - } - VG_(copy_UInstr)(cb, u_in); - break; - - /* Since we don't track definedness of values inside the - MMX state, we'd better check that the (int) reg being - read here is defined. */ - case MMX2_ERegRd: - sk_assert(u_in->tag2 == TempReg); - sk_assert(u_in->size == 4); - uInstr1(cb, TESTV, 4, TempReg, SHADOW(u_in->val2)); - uInstr1(cb, SETV, 4, TempReg, SHADOW(u_in->val2)); - VG_(copy_UInstr)(cb, u_in); - break; - - /* The MMX register is assumed to be fully defined, so - that's what this register becomes. */ - case MMX2_ERegWr: - sk_assert(u_in->tag2 == TempReg); - sk_assert(u_in->size == 4); - uInstr1(cb, SETV, 4, TempReg, SHADOW(u_in->val2)); - VG_(copy_UInstr)(cb, u_in); - break; - - default: - VG_(pp_UInstr)(0, u_in); - VG_(skin_panic)( "memcheck_instrument: unhandled case"); - - } /* end of switch (u_in->opcode) */ - - } /* end of for loop */ - - VG_(free_UCodeBlock)(cb_in); - return cb; -} - -/*------------------------------------------------------------*/ -/*--- Clean up mem check instrumentation. ---*/ -/*------------------------------------------------------------*/ - -#define dis VG_(print_codegen) - - -#define VGC_IS_SHADOW(tempreg) ((tempreg % 2) == 1) -#define VGC_UNDEF ((UChar)100) -#define VGC_VALUE ((UChar)101) - -#define NOP_no_msg(uu) \ - do { VG_(new_NOP)(uu); } while (False) - -#define NOP_tag1_op(uu) \ - do { VG_(new_NOP)(uu); \ - if (dis) \ - VG_(printf)(" at %2d: delete %s due to defd arg\n", \ - i, nameOfTagOp(u->val3)); \ - } while (False) - -#define SETV_tag1_op(uu,newsz) \ - do { uu->opcode = SETV; \ - uu->size = newsz; \ - uu->tag2 = uu->tag3 = NoValue; \ - if (dis) \ - VG_(printf)(" at %2d: convert %s to SETV%d " \ - "due to defd arg\n", \ - i, nameOfTagOp(u->val3), newsz); \ - } while (False) - - - -/* Run backwards and delete SETVs on shadow temps for which the next - action is a write. Needs an env saying whether or not the next - action is a write. The supplied UCodeBlock is destructively - modified. -*/ -static void vg_delete_redundant_SETVs ( UCodeBlock* cb ) -{ - Int i, j, k; - Int n_temps = VG_(get_num_temps)(cb); - Bool* next_is_write; - UInstr* u; - Int tempUse[VG_MAX_REGS_USED]; - Bool isWrites[VG_MAX_REGS_USED]; - - if (n_temps == 0) return; - - next_is_write = VG_(malloc)(n_temps * sizeof(Bool)); - - for (i = 0; i < n_temps; i++) next_is_write[i] = True; - - for (i = VG_(get_num_instrs)(cb) - 1; i >= 0; i--) { - u = VG_(get_instr)(cb, i); - - /* Occasionally there will be GETVs, TAG1s and TAG2s calculating - values which are never used. These first three cases get rid - of them. */ - - if (u->opcode == GETV && VGC_IS_SHADOW(u->val2) - && next_is_write[u->val2]) { - sk_assert(u->val2 < n_temps); - VG_(new_NOP)(u); - if (dis) - VG_(printf)(" at %2d: delete GETV\n", i); - } else - - if (u->opcode == TAG1 && VGC_IS_SHADOW(u->val1) - && next_is_write[u->val1]) { - sk_assert(u->val1 < n_temps); - VG_(new_NOP)(u); - if (dis) - VG_(printf)(" at %2d: delete TAG1\n", i); - } else - - if (u->opcode == TAG2 && VGC_IS_SHADOW(u->val2) - && next_is_write[u->val2]) { - sk_assert(u->val2 < n_temps); - VG_(new_NOP)(u); - if (dis) - VG_(printf)(" at %2d: delete TAG2\n", i); - } else - - /* The bulk of the cleanup work of this function is done by - the code from here downwards. */ - - if (u->opcode == MOV && VGC_IS_SHADOW(u->val2) - && next_is_write[u->val2]) { - /* This MOV is pointless because the target is dead at this - point. Delete it. */ - VG_(new_NOP)(u); - if (dis) - VG_(printf)(" at %2d: delete MOV\n", i); - } else - - if (u->opcode == SETV) { - if (u->tag1 == TempReg) { - sk_assert(VGC_IS_SHADOW(u->val1)); - if (next_is_write[u->val1]) { - /* This write is pointless, so annul it. */ - VG_(new_NOP)(u); - if (dis) - VG_(printf)(" at %2d: delete SETV\n", i); - } else { - /* This write has a purpose; don't annul it, but do - notice that we did it. */ - next_is_write[u->val1] = True; - } - - } - - } else { - /* Find out what this insn does to the temps. */ - k = VG_(get_reg_usage)(u, TempReg, &tempUse[0], &isWrites[0]); - sk_assert(0 <= k && k <= VG_MAX_REGS_USED); - for (j = k-1; j >= 0; j--) { - next_is_write[ tempUse[j] ] = isWrites[j]; - } - } - } -} - - -/* Run forwards, propagating and using the is-completely-defined - property. This removes a lot of redundant tag-munging code. - Unfortunately it requires intimate knowledge of how each uinstr and - tagop modifies its arguments. This duplicates knowledge of uinstr - tempreg uses embodied in VG_(get_reg_usage)(), which is unfortunate. - The supplied UCodeBlock* is modified in-place. - - For each value temp, def[] should hold VGC_VALUE. - - For each shadow temp, def[] may hold 4,2,1 or 0 iff that shadow is - definitely known to be fully defined at that size. In all other - circumstances a shadow's def[] entry is VGC_UNDEF, meaning possibly - undefined. In cases of doubt, VGC_UNDEF is always safe. -*/ -static void vg_propagate_definedness ( UCodeBlock* cb ) -{ - Int i, j, k, t; - Int n_temps = VG_(get_num_temps)(cb); - UChar* def; - UInstr* u; - Int tempUse[VG_MAX_REGS_USED]; - Bool isWrites[VG_MAX_REGS_USED]; - - if (n_temps == 0) return; - - def = VG_(malloc)(n_temps * sizeof(UChar)); - - for (i = 0; i < n_temps; i++) - def[i] = VGC_IS_SHADOW(i) ? VGC_UNDEF : VGC_VALUE; - - /* Run forwards, detecting and using the all-defined property. */ - - for (i = 0; i < VG_(get_num_instrs)(cb); i++) { - u = VG_(get_instr)(cb, i); - switch (u->opcode) { - - /* Tag-handling uinstrs. */ - - /* Deal with these quickly. */ - case NOP: - case LOCK: - case INCEIP: - break; - - /* Make a tag defined. */ - case SETV: - sk_assert(u->tag1 == TempReg && VGC_IS_SHADOW(u->val1)); - def[u->val1] = u->size; - break; - - /* Check definedness of a tag. */ - case TESTV: - sk_assert(u->tag1 == TempReg && VGC_IS_SHADOW(u->val1)); - if (def[u->val1] <= 4) { - sk_assert(def[u->val1] == u->size); - NOP_no_msg(u); - if (dis) - VG_(printf)(" at %2d: delete TESTV on defd arg\n", i); - } - break; - - /* Applies to both values and tags. Propagate Definedness - property through copies. Note that this isn't optional; - we *have* to do this to keep def[] correct. */ - case MOV: - sk_assert(u->tag2 == TempReg); - if (u->tag1 == TempReg) { - if (VGC_IS_SHADOW(u->val1)) { - sk_assert(VGC_IS_SHADOW(u->val2)); - def[u->val2] = def[u->val1]; - } - } - break; - - case PUTV: - sk_assert(u->tag1 == TempReg && VGC_IS_SHADOW(u->val1)); - if (def[u->val1] <= 4) { - sk_assert(def[u->val1] == u->size); - u->tag1 = Literal; - u->val1 = 0; - switch (u->size) { - case 4: u->lit32 = 0x00000000; break; - case 2: u->lit32 = 0xFFFF0000; break; - case 1: u->lit32 = 0xFFFFFF00; break; - default: VG_(skin_panic)("vg_cleanup(PUTV)"); - } - if (dis) - VG_(printf)( - " at %2d: propagate definedness into PUTV\n", i); - } - break; - - case STOREV: - sk_assert(u->tag1 == TempReg && VGC_IS_SHADOW(u->val1)); - if (def[u->val1] <= 4) { - sk_assert(def[u->val1] == u->size); - u->tag1 = Literal; - u->val1 = 0; - switch (u->size) { - case 4: u->lit32 = 0x00000000; break; - case 2: u->lit32 = 0xFFFF0000; break; - case 1: u->lit32 = 0xFFFFFF00; break; - default: VG_(skin_panic)("vg_cleanup(STOREV)"); - } - if (dis) - VG_(printf)( - " at %2d: propagate definedness into STandV\n", i); - } - break; - - /* Nothing interesting we can do with this, I think. */ - case PUTVF: - break; - - /* Tag handling operations. */ - case TAG2: - sk_assert(u->tag2 == TempReg && VGC_IS_SHADOW(u->val2)); - sk_assert(u->tag3 == Lit16); - /* Ultra-paranoid "type" checking. */ - switch (u->val3) { - case Tag_ImproveAND4_TQ: case Tag_ImproveAND2_TQ: - case Tag_ImproveAND1_TQ: case Tag_ImproveOR4_TQ: - case Tag_ImproveOR2_TQ: case Tag_ImproveOR1_TQ: - sk_assert(u->tag1 == TempReg && !VGC_IS_SHADOW(u->val1)); - break; - default: - sk_assert(u->tag1 == TempReg && VGC_IS_SHADOW(u->val1)); - break; - } - switch (u->val3) { - Int sz; - case Tag_UifU4: - sz = 4; goto do_UifU; - case Tag_UifU2: - sz = 2; goto do_UifU; - case Tag_UifU1: - sz = 1; goto do_UifU; - case Tag_UifU0: - sz = 0; goto do_UifU; - do_UifU: - sk_assert(u->tag1 == TempReg && VGC_IS_SHADOW(u->val1)); - sk_assert(u->tag2 == TempReg && VGC_IS_SHADOW(u->val2)); - if (def[u->val1] <= 4) { - /* UifU. The first arg is defined, so result is - simply second arg. Delete this operation. */ - sk_assert(def[u->val1] == sz); - NOP_no_msg(u); - if (dis) - VG_(printf)( - " at %2d: delete UifU%d due to defd arg1\n", - i, sz); - } - else - if (def[u->val2] <= 4) { - /* UifU. The second arg is defined, so result is - simply first arg. Copy to second. */ - sk_assert(def[u->val2] == sz); - u->opcode = MOV; - u->size = 4; - u->tag3 = NoValue; - def[u->val2] = def[u->val1]; - if (dis) - VG_(printf)( - " at %2d: change UifU%d to MOV due to defd" - " arg2\n", - i, sz); - } - break; - case Tag_ImproveAND4_TQ: - sz = 4; goto do_ImproveAND; - case Tag_ImproveAND1_TQ: - sz = 1; goto do_ImproveAND; - do_ImproveAND: - /* Implements Q = T AND Q. So if Q is entirely defined, - ie all 0s, we get MOV T, Q. */ - if (def[u->val2] <= 4) { - sk_assert(def[u->val2] == sz); - u->size = 4; /* Regardless of sz */ - u->opcode = MOV; - u->tag3 = NoValue; - def[u->val2] = VGC_UNDEF; - if (dis) - VG_(printf)( - " at %2d: change ImproveAND%d_TQ to MOV due " - "to defd arg2\n", - i, sz); - } - break; - default: - goto unhandled; - } - break; - - case TAG1: - sk_assert(u->tag1 == TempReg && VGC_IS_SHADOW(u->val1)); - if (def[u->val1] > 4) break; - /* We now know that the arg to the op is entirely defined. - If the op changes the size of the arg, we must replace - it with a SETV at the new size. If it doesn't change - the size, we can delete it completely. */ - switch (u->val3) { - /* Maintain the same size ... */ - case Tag_Left4: - sk_assert(def[u->val1] == 4); - NOP_tag1_op(u); - break; - case Tag_PCast11: - sk_assert(def[u->val1] == 1); - NOP_tag1_op(u); - break; - /* Change size ... */ - case Tag_PCast40: - sk_assert(def[u->val1] == 4); - SETV_tag1_op(u,0); - def[u->val1] = 0; - break; - case Tag_PCast14: - sk_assert(def[u->val1] == 1); - SETV_tag1_op(u,4); - def[u->val1] = 4; - break; - case Tag_PCast12: - sk_assert(def[u->val1] == 1); - SETV_tag1_op(u,2); - def[u->val1] = 2; - break; - case Tag_PCast10: - sk_assert(def[u->val1] == 1); - SETV_tag1_op(u,0); - def[u->val1] = 0; - break; - case Tag_PCast02: - sk_assert(def[u->val1] == 0); - SETV_tag1_op(u,2); - def[u->val1] = 2; - break; - default: - goto unhandled; - } - if (dis) - VG_(printf)( - " at %2d: delete TAG1 %s due to defd arg\n", - i, nameOfTagOp(u->val3)); - break; - - default: - unhandled: - /* We don't know how to handle this uinstr. Be safe, and - set to VGC_VALUE or VGC_UNDEF all temps written by it. */ - k = VG_(get_reg_usage)(u, TempReg, &tempUse[0], &isWrites[0]); - sk_assert(0 <= k && k <= VG_MAX_REGS_USED); - for (j = 0; j < k; j++) { - t = tempUse[j]; - sk_assert(t >= 0 && t < n_temps); - if (!isWrites[j]) { - /* t is read; ignore it. */ - if (0&& VGC_IS_SHADOW(t) && def[t] <= 4) - VG_(printf)("ignoring def %d at %s %s\n", - def[t], - VG_(name_UOpcode)(True, u->opcode), - (u->opcode == TAG1 || u->opcode == TAG2) - ? nameOfTagOp(u->val3) - : (Char*)""); - } else { - /* t is written; better nullify it. */ - def[t] = VGC_IS_SHADOW(t) ? VGC_UNDEF : VGC_VALUE; - } - } - } - } -} - - -/* Top level post-MemCheck-instrumentation cleanup function. */ -static void vg_cleanup ( UCodeBlock* cb ) -{ - vg_propagate_definedness ( cb ); - vg_delete_redundant_SETVs ( cb ); -} -#endif - - -#undef dis - -//////////////////////////////////////////////////////////////////////// -//////////////////////////////////////////////////////////////////////// -//////////////////////////////////////////////////////////////////////// -//////////////////////////////////////////////////////////////////////// /*------------------------------------------------------------*/ /*--- Forward decls ---*/