up to x86 front and back ends.
git-svn-id: svn://svn.valgrind.org/vex/trunk@697
&& epartIsReg(insn[2]) && gregOfRM(insn[2]) == 7) {
vassert(sz == 4);
delta += 3;
- /* nothing to do */
+ /* Insert a memory fence. It's sometimes important that these
+ are carried through to the generated code. */
+ stmt( IRStmt_MFence() );
DIP("sfence\n");
goto decode_success;
}
&& (gregOfRM(insn[2]) == 5 || gregOfRM(insn[2]) == 6)) {
vassert(sz == 4);
delta += 3;
- /* nothing to do */
+ /* Insert a memory fence. It's sometimes important that these
+ are carried through to the generated code. */
+ stmt( IRStmt_MFence() );
DIP("%sfence\n", gregOfRM(insn[2])==5 ? "l" : "m");
goto decode_success;
}
i->Xin.Bsfr32.dst = dst;
return i;
}
+X86Instr* X86Instr_MFence ( VexSubArch subarch )
+{
+ X86Instr* i = LibVEX_Alloc(sizeof(X86Instr));
+ i->tag = Xin_MFence;
+ i->Xin.MFence.subarch = subarch;
+ vassert(subarch == VexSubArchX86_sse0
+ || subarch == VexSubArchX86_sse1
+ || subarch == VexSubArchX86_sse2);
+ return i;
+}
+
X86Instr* X86Instr_FpUnary ( X86FpOp op, HReg src, HReg dst ) {
X86Instr* i = LibVEX_Alloc(sizeof(X86Instr));
i->tag = Xin_FpUnary;
vex_printf(",");
ppHRegX86(i->Xin.Bsfr32.dst);
return;
+ case Xin_MFence:
+ vex_printf("mfence(%s)",
+ LibVEX_ppVexSubArch(i->Xin.MFence.subarch));
+ return;
case Xin_FpUnary:
vex_printf("g%sD ", showX86FpOp(i->Xin.FpUnary.op));
ppHRegX86(i->Xin.FpUnary.src);
addHRegUse(u, HRmRead, i->Xin.Bsfr32.src);
addHRegUse(u, HRmWrite, i->Xin.Bsfr32.dst);
return;
+ case Xin_MFence:
+ return;
case Xin_FpUnary:
addHRegUse(u, HRmRead, i->Xin.FpUnary.src);
addHRegUse(u, HRmWrite, i->Xin.FpUnary.dst);
mapReg(m, &i->Xin.Bsfr32.src);
mapReg(m, &i->Xin.Bsfr32.dst);
return;
+ case Xin_MFence:
+ return;
case Xin_FpUnary:
mapReg(m, &i->Xin.FpUnary.src);
mapReg(m, &i->Xin.FpUnary.dst);
p = doAMode_R(p, i->Xin.Bsfr32.dst, i->Xin.Bsfr32.src);
goto done;
+ case Xin_MFence:
+ /* see comment in hdefs.h re this insn */
+vex_printf("EMIT FENCE\n");
+ switch (i->Xin.MFence.subarch) {
+ case VexSubArchX86_sse0:
+ vassert(0); /* awaiting test case */
+ /* lock addl $0,0(%esp) */
+ *p++ = 0xF0; *p++ = 0x83; *p++ = 0x44;
+ *p++ = 0x24; *p++ = 0x00; *p++ = 0x00;
+ goto done;
+ case VexSubArchX86_sse1:
+ /* sfence */
+ *p++ = 0x0F; *p++ = 0xAE; *p++ = 0xF8;
+ /* lock addl $0,0(%esp) */
+ *p++ = 0xF0; *p++ = 0x83; *p++ = 0x44;
+ *p++ = 0x24; *p++ = 0x00; *p++ = 0x00;
+ goto done;
+ case VexSubArchX86_sse2:
+ vassert(0); /* awaiting test case */
+ /* mfence */
+ *p++ = 0x0F; *p++ = 0xAE; *p++ = 0xF0;
+ goto done;
+ default:
+ vpanic("emit_X86Instr:mfence:subarch");
+ }
+ break;
+
case Xin_Store:
if (i->Xin.Store.sz == 2) {
/* This case, at least, is simple, given that we can
Xin_Store, /* store 16/8 bit value in memory */
Xin_Set32, /* convert condition code to 32-bit value */
Xin_Bsfr32, /* 32-bit bsf/bsr */
+ Xin_MFence, /* mem fence (not just sse2, but sse0 and 1 too) */
Xin_FpUnary, /* FP fake unary op */
Xin_FpBinary, /* FP fake binary op */
HReg src;
HReg dst;
} Bsfr32;
+ /* Mem fence (not just sse2, but sse0 and 1 too). In short,
+ an insn which flushes all preceding loads and stores as
+ much as possible before continuing. On SSE2 we emit a
+ real "mfence", on SSE1 "sfence ; lock addl $0,0(%esp)" and
+ on SSE0 "lock addl $0,0(%esp)". This insn therefore
+ carries the subarch so the assembler knows what to
+ emit. */
+ struct {
+ VexSubArch subarch;
+ } MFence;
/* X86 Floating point (fake 3-operand, "flat reg file" insns) */
struct {
extern X86Instr* X86Instr_Store ( UChar sz, HReg src, X86AMode* dst );
extern X86Instr* X86Instr_Set32 ( X86CondCode cond, HReg dst );
extern X86Instr* X86Instr_Bsfr32 ( Bool isFwds, HReg src, HReg dst );
+extern X86Instr* X86Instr_MFence ( VexSubArch );
extern X86Instr* X86Instr_FpUnary ( X86FpOp op, HReg src, HReg dst );
extern X86Instr* X86Instr_FpBinary ( X86FpOp op, HReg srcL, HReg srcR, HReg dst );
break;
}
+ /* --------- MEM FENCE --------- */
+ case Ist_MFence:
+ addInstr(env, X86Instr_MFence(env->subarch));
+ return;
+
/* --------- EXIT --------- */
case Ist_Exit: {
X86RI* dst;
void ppIRType ( IRType ty )
{
- switch (ty) {
- case Ity_INVALID: vex_printf("Ity_INVALID"); break;
- case Ity_I1: vex_printf( "I1"); break;
- case Ity_I8: vex_printf( "I8"); break;
- case Ity_I16: vex_printf( "I16"); break;
- case Ity_I32: vex_printf( "I32"); break;
- case Ity_I64: vex_printf( "I64"); break;
- case Ity_F32: vex_printf( "F32"); break;
- case Ity_F64: vex_printf( "F64"); break;
- case Ity_V128: vex_printf( "V128"); break;
- default: vex_printf("ty = 0x%x\n", (Int)ty);
- vpanic("ppIRType");
- }
+ switch (ty) {
+ case Ity_INVALID: vex_printf("Ity_INVALID"); break;
+ case Ity_I1: vex_printf( "I1"); break;
+ case Ity_I8: vex_printf( "I8"); break;
+ case Ity_I16: vex_printf( "I16"); break;
+ case Ity_I32: vex_printf( "I32"); break;
+ case Ity_I64: vex_printf( "I64"); break;
+ case Ity_F32: vex_printf( "F32"); break;
+ case Ity_F64: vex_printf( "F64"); break;
+ case Ity_V128: vex_printf( "V128"); break;
+ default: vex_printf("ty = 0x%x\n", (Int)ty);
+ vpanic("ppIRType");
+ }
}
void ppIRConst ( IRConst* con )
case Ist_Dirty:
ppIRDirty(s->Ist.Dirty.details);
break;
+ case Ist_MFence:
+ vex_printf("IRMemoryFence");
+ break;
case Ist_Exit:
vex_printf( "if (" );
ppIRExpr(s->Ist.Exit.guard);
s->Ist.Dirty.details = d;
return s;
}
+IRStmt* IRStmt_MFence ( void )
+{
+ IRStmt* s = LibVEX_Alloc(sizeof(IRStmt));
+ s->tag = Ist_MFence;
+ return s;
+}
IRStmt* IRStmt_Exit ( IRExpr* guard, IRJumpKind jk, IRConst* dst ) {
IRStmt* s = LibVEX_Alloc(sizeof(IRStmt));
s->tag = Ist_Exit;
if (di->mAddr && !isAtom(di->mAddr))
return False;
return True;
+ case Ist_MFence:
+ return True;
case Ist_Exit:
return isAtom(st->Ist.Exit.guard);
default:
if (d->mFx != Ifx_None)
useBeforeDef_Expr(bb,stmt,d->mAddr,def_counts);
break;
+ case Ist_MFence:
+ break;
case Ist_Exit:
useBeforeDef_Expr(bb,stmt,stmt->Ist.Exit.guard,def_counts);
break;
break;
bad_dirty:
sanityCheckFail(bb,stmt,"IRStmt.Dirty: ill-formed");
-
+ case Ist_MFence:
+ break;
case Ist_Exit:
tcExpr( bb, stmt, stmt->Ist.Exit.guard, gWordTy );
if (typeOfIRExpr(tyenv,stmt->Ist.Exit.guard) != Ity_I1)
d2->args[i] = flatten_Expr(bb, d2->args[i]);
addStmtToIRBB(bb, IRStmt_Dirty(d2));
break;
+ case Ist_MFence:
+ addStmtToIRBB(bb, st);
+ break;
case Ist_Exit:
e1 = flatten_Expr(bb, st->Ist.Exit.guard);
addStmtToIRBB(bb, IRStmt_Exit(e1, st->Ist.Exit.jk,
state requiring precise exceptions needs to be flushed. The
crude solution is just to flush everything; we could easily
enough do a lot better if needed. */
+ /* Probably also overly-conservative, but also dump everything
+ if we hit a memory fence. */
+ case Ist_MFence:
case Ist_Dirty:
for (j = 0; j < env->used; j++)
env->inuse[j] = False;
return IRStmt_Dirty(d2);
}
+ case Ist_MFence:
+ return IRStmt_MFence();
+
case Ist_Exit: {
IRExpr* fcond;
vassert(isAtom(st->Ist.Exit.guard));
for (i = 0; d->args[i] != NULL; i++)
addUses_Expr(set, d->args[i]);
return;
+ case Ist_MFence:
+ return;
case Ist_Exit:
addUses_Expr(set, st->Ist.Exit.guard);
return;
for (i = 0; d->args[i]; i++)
occCount_Expr(env, d->args[i]);
return;
+ case Ist_MFence:
+ return;
case Ist_Exit:
occCount_Expr(env, st->Ist.Exit.guard);
return;
st->Ist.Exit.jk,
st->Ist.Exit.dst
);
+ case Ist_MFence:
+ return IRStmt_MFence();
case Ist_Dirty:
d = st->Ist.Dirty.details;
d2 = emptyIRDirty();
appeared. (Stupid algorithm): first, mark all bindings which
need to be dumped. Then, dump them in the order in which
they were defined. */
+
invPut = st->tag == Ist_Put
- || st->tag == Ist_PutI || st->tag == Ist_Dirty;
+ || st->tag == Ist_PutI
+ || st->tag == Ist_Dirty;
+
invStore = st->tag == Ist_STle
|| st->tag == Ist_Dirty;
if (!ti->expr)
continue;
- /* We have to invalidate this binding. */
+ /* Do we have to invalidate this binding? */
+
ti->invalidateMe
= /* a store invalidates loaded data */
(ti->eDoesLoad && invStore)
invalidate trees containing loads if the Put in
question is marked as requiring precise
exceptions. */
- || (ti->eDoesLoad && invPut);
+ || (ti->eDoesLoad && invPut)
+ /* probably overly conservative: a memory fence
+ invalidates absolutely everything, so that all
+ computation prior to it is forced to complete before
+ proceeding with the fence. */
+ || st->tag == Ist_MFence;
/*
if (ti->invalidateMe)
- vex_printf("SET INVAL\n");
- */
+ vex_printf("SET INVAL\n");
+ */
}
dumpInvalidated ( env, bb, &j );
vassert(isAtom(st->Ist.STle.addr));
vassert(isAtom(st->Ist.STle.data));
break;
- case Ist_Exit:
- vassert(isAtom(st->Ist.Exit.guard));
- break;
case Ist_Dirty:
d = st->Ist.Dirty.details;
vassert(isAtom(d->guard));
if (d->mFx != Ifx_None)
vassert(isAtom(d->mAddr));
break;
+ case Ist_MFence:
+ break;
+ case Ist_Exit:
+ vassert(isAtom(st->Ist.Exit.guard));
+ break;
default:
ppIRStmt(st);
vpanic("hasGetIorPutI");
Ist_Tmp, /* assign value to temporary */
Ist_STle, /* little-endian write to memory */
Ist_Dirty, /* call complex ("dirty") helper function */
+ Ist_MFence, /* memory fence */
Ist_Exit /* conditional exit from BB */
}
IRStmtTag;
struct {
IRDirty* details;
} Dirty;
+ struct {
+ } MFence;
struct {
IRExpr* guard;
IRJumpKind jk;
}
IRStmt;
-extern IRStmt* IRStmt_Put ( Int off, IRExpr* data );
-extern IRStmt* IRStmt_PutI ( IRArray* descr, IRExpr* ix, Int bias,
- IRExpr* data );
-extern IRStmt* IRStmt_Tmp ( IRTemp tmp, IRExpr* data );
-extern IRStmt* IRStmt_STle ( IRExpr* addr, IRExpr* data );
-extern IRStmt* IRStmt_Dirty ( IRDirty* details );
-extern IRStmt* IRStmt_Exit ( IRExpr* guard, IRJumpKind jk, IRConst* dst );
+extern IRStmt* IRStmt_Put ( Int off, IRExpr* data );
+extern IRStmt* IRStmt_PutI ( IRArray* descr, IRExpr* ix, Int bias,
+ IRExpr* data );
+extern IRStmt* IRStmt_Tmp ( IRTemp tmp, IRExpr* data );
+extern IRStmt* IRStmt_STle ( IRExpr* addr, IRExpr* data );
+extern IRStmt* IRStmt_Dirty ( IRDirty* details );
+extern IRStmt* IRStmt_MFence ( void );
+extern IRStmt* IRStmt_Exit ( IRExpr* guard, IRJumpKind jk, IRConst* dst );
extern IRStmt* dopyIRStmt ( IRStmt* );