]> git.ipfire.org Git - thirdparty/valgrind.git/commitdiff
Add a new kind of IR stmt: "instruction marks" (IRStmt_IMark), so as
authorJulian Seward <jseward@acm.org>
Wed, 16 Mar 2005 18:19:10 +0000 (18:19 +0000)
committerJulian Seward <jseward@acm.org>
Wed, 16 Mar 2005 18:19:10 +0000 (18:19 +0000)
to support profiling.  It is the responsibility of front ends (toIR.c)
to generate these.  For each instruction, the first IR stmt emitted
should be an IMark, stating the guest address and length of the guest
instruction represented by the IR that follows.  All IR stmts
following the IMark but before the next IMark are then assumed to
'belong to' the guest insn described by the first IMark.  IMarks do
not denote executable code and can be ignored at any point in the
proceedings; they are an optional addition which help
profiling-annotators to navigate the IR stmt stream.

This commit adds IR level infrastructure for IMarks and IMark
generation in the x86 front end.  The amd64 and ppc32 front end are
not yet done.

git-svn-id: svn://svn.valgrind.org/vex/trunk@1046

VEX/priv/guest-x86/toIR.c
VEX/priv/host-x86/isel.c
VEX/priv/ir/irdefs.c
VEX/priv/ir/iropt.c
VEX/pub/libvex_ir.h

index 9ea356599d4d72790d6704f6f8618de98b95f21b..76d7c51d0ff654700365b3c74c35eef4571e78ab 100644 (file)
@@ -246,6 +246,7 @@ IRBB* bbToIR_X86 ( UChar*           x86code,
    Addr64     guest_next;
    Bool       resteerOK;
    DisResult  dres;
+   IRStmt*    imark;
    static Int n_resteers = 0;
    Int        d_resteers = 0;
 
@@ -290,20 +291,41 @@ IRBB* bbToIR_X86 ( UChar*           x86code,
               && vge->n_used < 3
            );
 
+      /* This is the %EIP of the instruction we're just about to deal
+         with. */
+      guest_eip_curr_instr = guest_eip_bbstart + delta;
+
+      /* This is the irbb statement array index of the first stmt in
+         this insn.  That will always be the instruction-mark
+         descriptor. */
       first_stmt_idx = irbb->stmts_used;
 
+      /* Add an instruction-mark statement.  We won't know until after
+         disInstr how long the instruction is, so just put in a zero
+         length and we'll fix it up later. */
+      stmt( IRStmt_IMark( (Addr64)guest_eip_curr_instr, 0 ));
+
       if (n_instrs > 0) {
          /* for the first insn, the dispatch loop will have set
             %EIP, but for all the others we have to do it ourselves. */
-         stmt( IRStmt_Put( OFFB_EIP, mkU32(guest_eip_bbstart + delta)) );
+         stmt( IRStmt_Put( OFFB_EIP, mkU32(guest_eip_curr_instr)) );
       }
 
-      guest_eip_curr_instr = guest_eip_bbstart + delta;
-
+      /* Do the instruction.  This may set insn_verbose to True, which
+         needs to be annulled. */
+      size = 0; /* just in case disInstr doesn't set it */
       dres = disInstr( resteerOK, chase_into_ok, 
                        delta, subarch_guest, &size, &guest_next );
       insn_verbose = False;
 
+      /* Fill in the insn-mark length field. */
+      vassert(first_stmt_idx >= 0 && first_stmt_idx < irbb->stmts_used);
+      imark = irbb->stmts[first_stmt_idx];
+      vassert(imark);
+      vassert(imark->tag == Ist_IMark);
+      vassert(imark->Ist.IMark.len == 0);
+      imark->Ist.IMark.len = size;
+
       /* Print the resulting IR, if needed. */
       if (vex_traceflags & VEX_TRACE_FE) {
          for (i = first_stmt_idx; i < irbb->stmts_used; i++) {
index 662af10683f9e92ec461cf7e3f48f5f5bf3f39e8..1ba1af1d231a75564ddf4d2d3f8975bfea47f4eb 100644 (file)
@@ -3372,6 +3372,11 @@ static void iselStmt ( ISelEnv* env, IRStmt* stmt )
       addInstr(env, X86Instr_MFence(env->subarch));
       return;
 
+   /* --------- INSTR MARK --------- */
+   /* Doesn't generate any executable code ... */
+   case Ist_IMark:
+       return;
+
    /* --------- EXIT --------- */
    case Ist_Exit: {
       X86RI*      dst;
index 45f5975907b4c5be3e1200ce9bd467e1b8902f03..d7ffcdbc738b5c35b4faa38f57dcac9de3ae63ca 100644 (file)
@@ -577,6 +577,10 @@ void ppIRJumpKind ( IRJumpKind kind )
 void ppIRStmt ( IRStmt* s )
 {
    switch (s->tag) {
+      case Ist_IMark:
+         vex_printf("IMark(0x%llx, %d)", s->Ist.IMark.addr, 
+                                         s->Ist.IMark.len);
+         break;
       case Ist_Put:
          vex_printf( "PUT(%d) = ", s->Ist.Put.offset);
          ppIRExpr(s->Ist.Put.data);
@@ -900,6 +904,13 @@ IRDirty* emptyIRDirty ( void ) {
 
 /* Constructors -- IRStmt */
 
+IRStmt* IRStmt_IMark ( Addr64 addr, Int len ) {
+   IRStmt* s         = LibVEX_Alloc(sizeof(IRStmt));
+   s->tag            = Ist_IMark;
+   s->Ist.IMark.addr = addr;
+   s->Ist.IMark.len  = len;
+   return s;
+}
 IRStmt* IRStmt_Put ( Int off, IRExpr* data ) {
    IRStmt* s         = LibVEX_Alloc(sizeof(IRStmt));
    s->tag            = Ist_Put;
@@ -1102,6 +1113,8 @@ IRDirty* dopyIRDirty ( IRDirty* d )
 IRStmt* dopyIRStmt ( IRStmt* s )
 {
    switch (s->tag) {
+      case Ist_IMark:
+         return IRStmt_IMark(s->Ist.IMark.addr, s->Ist.IMark.len);
       case Ist_Put: 
          return IRStmt_Put(s->Ist.Put.offset, 
                            dopyIRExpr(s->Ist.Put.data));
@@ -1612,6 +1625,7 @@ Bool isFlatIRStmt ( IRStmt* st )
          if (di->mAddr && !isAtom(di->mAddr)) 
             return False;
          return True;
+      case Ist_IMark:
       case Ist_MFence:
          return True;
       case Ist_Exit:
@@ -1749,6 +1763,8 @@ void useBeforeDef_Stmt ( IRBB* bb, IRStmt* stmt, Int* def_counts )
    Int      i;
    IRDirty* d;
    switch (stmt->tag) {
+      case Ist_IMark:
+         break;
       case Ist_Put:
          useBeforeDef_Expr(bb,stmt,stmt->Ist.Put.data,def_counts);
          break;
@@ -1889,6 +1905,12 @@ void tcStmt ( IRBB* bb, IRStmt* stmt, IRType gWordTy )
    IRDirty*   d;
    IRTypeEnv* tyenv = bb->tyenv;
    switch (stmt->tag) {
+      case Ist_IMark:
+         /* Somewhat heuristic, but rule out totally implausible
+            instruction sizes. */
+         if (stmt->Ist.IMark.len < 0 || stmt->Ist.IMark.len > 20)
+            sanityCheckFail(bb,stmt,"IRStmt.IMark.len: implausible");
+         break;
       case Ist_Put:
          tcExpr( bb, stmt, stmt->Ist.Put.data, gWordTy );
          if (typeOfIRExpr(tyenv,stmt->Ist.Put.data) == Ity_I1)
index dc27ff3390629036e3e5da1bdb5cd2abc285b5e5..62a3b1fd235e7f4e2eabbac9dcaebc51818756db 100644 (file)
@@ -359,6 +359,9 @@ static void flatten_Stmt ( IRBB* bb, IRStmt* st )
    IRExpr  *e1, *e2;
    IRDirty *d,  *d2;
    switch (st->tag) {
+      case Ist_IMark:
+         addStmtToIRBB(bb, st);
+         break;
       case Ist_Put:
          if (isAtom(st->Ist.Put.data)) {
             /* optimisation to reduce the amount of heap wasted
@@ -692,6 +695,9 @@ static void handle_gets_Stmt (
          vassert(isAtom(st->Ist.PutI.data));
          break;
 
+      case Ist_IMark:
+         break;
+
       default:
          vex_printf("\n");
          ppIRStmt(st);
@@ -1440,6 +1446,9 @@ static IRStmt* subst_and_fold_Stmt ( IRExpr** env, IRStmt* st )
          return IRStmt_Dirty(d2);
       }
 
+      case Ist_IMark:
+         return IRStmt_IMark(st->Ist.IMark.addr, st->Ist.IMark.len);
+
       case Ist_MFence:
          return IRStmt_MFence();
 
@@ -1628,6 +1637,7 @@ static void addUses_Stmt ( Bool* set, IRStmt* st )
          for (i = 0; d->args[i] != NULL; i++)
             addUses_Expr(set, d->args[i]);
          return;
+      case Ist_IMark:
       case Ist_MFence:
          return;
       case Ist_Exit:
@@ -2453,6 +2463,9 @@ Bool guestAccessWhichMightOverlapPutI (
    getArrayBounds(pi->Ist.PutI.descr, &minoffP, &maxoffP);
    switch (s2->tag) {
 
+      case Ist_IMark:
+         return False;
+
       case Ist_MFence:
          /* just be paranoid ... this should be rare. */
          return True;
@@ -2682,6 +2695,8 @@ static void deltaIRStmt ( IRStmt* st, Int delta )
    Int      i;
    IRDirty* d;
    switch (st->tag) {
+      case Ist_IMark:
+         break;
       case Ist_Put:
          deltaIRExpr(st->Ist.Put.data, delta);
          break;
@@ -3067,6 +3082,7 @@ static void occCount_Stmt ( TmpInfo** env, IRStmt* st )
          for (i = 0; d->args[i]; i++)
             occCount_Expr(env, d->args[i]);
          return;
+      case Ist_IMark:
       case Ist_MFence:
          return;
       case Ist_Exit:
@@ -3199,6 +3215,8 @@ static IRStmt* tbSubst_Stmt ( TmpInfo** env, IRStmt* st )
                    st->Ist.Exit.jk,
                    st->Ist.Exit.dst
                 );
+      case Ist_IMark:
+         return IRStmt_IMark(st->Ist.IMark.addr, st->Ist.IMark.len);
       case Ist_MFence:
          return IRStmt_MFence();
       case Ist_Dirty:
@@ -3590,6 +3608,7 @@ static Bool hasGetIorPutI ( IRBB* bb )
             if (d->mFx != Ifx_None)
                vassert(isAtom(d->mAddr));
             break;
+         case Ist_IMark:
          case Ist_MFence:
             break;
          case Ist_Exit:
index dd4a9def47730333e540de68ac96f8605e5c0b63..7c3405b0760dac47892585863eaed27124747c9d 100644 (file)
@@ -837,6 +837,8 @@ IRDirty* unsafeIRDirty_1_N ( IRTemp dst,
 /* The possible kinds of statements are as follows: */
 typedef 
    enum { 
+      Ist_IMark,  /* instruction mark: describe addr/len of guest insn
+                     whose IR follows */
       Ist_Put,    /* write guest state, fixed offset */
       Ist_PutI,   /* write guest state, run-time offset */
       Ist_Tmp,    /* assign value to temporary */
@@ -851,6 +853,10 @@ typedef
    struct _IRStmt {
       IRStmtTag tag;
       union {
+         struct {
+            Addr64 addr;
+            Int    len;
+         } IMark;
          struct {
             Int     offset;
             IRExpr* data;
@@ -883,6 +889,7 @@ typedef
    }
    IRStmt;
 
+extern IRStmt* IRStmt_IMark  ( Addr64 addr, Int len );
 extern IRStmt* IRStmt_Put    ( Int off, IRExpr* data );
 extern IRStmt* IRStmt_PutI   ( IRArray* descr, IRExpr* ix, Int bias, 
                                IRExpr* data );