]> git.ipfire.org Git - thirdparty/valgrind.git/commitdiff
Implement regparm (1 to 3) in the x86 back end.
authorJulian Seward <jseward@acm.org>
Sat, 30 Oct 2004 20:39:01 +0000 (20:39 +0000)
committerJulian Seward <jseward@acm.org>
Sat, 30 Oct 2004 20:39:01 +0000 (20:39 +0000)
git-svn-id: svn://svn.valgrind.org/vex/trunk@462

VEX/priv/host-x86/hdefs.c
VEX/priv/host-x86/hdefs.h
VEX/priv/host-x86/isel.c
VEX/priv/ir/irdefs.c
VEX/pub/libvex_ir.h

index 81935ad5ba45c9bf1a8e993030e468481f567c47..cb83fcc2315eca30cff055a96f81a13107bfc2f4 100644 (file)
@@ -504,10 +504,12 @@ X86Instr* X86Instr_Push( X86RMI* src ) {
    i->Xin.Push.src = src;
    return i;
 }
-X86Instr* X86Instr_Call ( HReg target ) {
-   X86Instr* i        = LibVEX_Alloc(sizeof(X86Instr));
-   i->tag             = Xin_Call;
-   i->Xin.Call.target = target;
+X86Instr* X86Instr_Call ( HReg target, Int regparms ) {
+   X86Instr* i          = LibVEX_Alloc(sizeof(X86Instr));
+   i->tag               = Xin_Call;
+   i->Xin.Call.target   = target;
+   i->Xin.Call.regparms = regparms;
+   vassert(regparms >= 0 && regparms <= 3);
    return i;
 }
 X86Instr* X86Instr_Goto ( IRJumpKind jk, X86CondCode cond, X86RI* dst ) {
@@ -695,7 +697,7 @@ void ppX86Instr ( X86Instr* i ) {
          ppX86RMI(i->Xin.Push.src);
          return;
       case Xin_Call:
-         vex_printf("call *");
+         vex_printf("call[%d] *", i->Xin.Call.regparms);
          ppHRegX86(i->Xin.Call.target);
          break;
       case Xin_Goto:
@@ -875,6 +877,13 @@ void getRegUsage_X86Instr (HRegUsage* u, X86Instr* i)
          addHRegUse(u, HRmWrite, hregX86_EAX());
          addHRegUse(u, HRmWrite, hregX86_ECX());
          addHRegUse(u, HRmWrite, hregX86_EDX());
+         switch (i->Xin.Call.regparms) {
+            case 3: addHRegUse(u, HRmRead, hregX86_ECX()); /*fallthru*/
+            case 2: addHRegUse(u, HRmRead, hregX86_EDX()); /*fallthru*/
+            case 1: addHRegUse(u, HRmRead, hregX86_EAX()); break;
+            case 0: break;
+            default: vpanic("getRegUsage_X86Instr:Call:regparms");
+         }
          return;
       case Xin_Goto:
          addRegUsage_X86RI(u, i->Xin.Goto.dst);
index 768c8b9f25442c7b771c2f0fcd73b82cc62b61fa..e534416448c498b61fecde2515a61f603f00a9ca 100644 (file)
@@ -342,6 +342,7 @@ typedef
          } Push;
          struct {
             HReg target;
+            Int  regparms; /* 0 .. 3 */
          } Call;
          /* Pseudo-insn.  Goto dst, on given condition (which could be
             Xcc_ALWAYS).  Note importantly that if the jump is 
@@ -448,7 +449,7 @@ extern X86Instr* X86Instr_MulL      ( Bool syned, X86ScalarSz, X86RM* );
 extern X86Instr* X86Instr_Div       ( Bool syned, X86ScalarSz, X86RM* );
 extern X86Instr* X86Instr_Sh3232    ( X86ShiftOp, UInt amt, HReg src, HReg dst );
 extern X86Instr* X86Instr_Push      ( X86RMI* );
-extern X86Instr* X86Instr_Call      ( HReg );
+extern X86Instr* X86Instr_Call      ( HReg, Int );
 extern X86Instr* X86Instr_Goto      ( IRJumpKind, X86CondCode cond, X86RI* dst );
 extern X86Instr* X86Instr_CMov32    ( X86CondCode, X86RM* src, HReg dst );
 extern X86Instr* X86Instr_LoadEX    ( UChar szSmall, Bool syned,
index f3466a4c79693f1f694cc13ef1062d2a0b5307a0..8ddac164c094383b7361a2796997f87d16561590 100644 (file)
@@ -269,6 +269,7 @@ static X86Instr* mk_MOVsd_RR ( HReg src, HReg dst )
    return X86Instr_Alu32R(Xalu_MOV, X86RMI_Reg(src), dst);
 }
 
+
 /* Push an arg onto the host stack, in preparation for a call to a
    helper function of some kind.  Returns the number of 32-bit words
    pushed. */
@@ -298,18 +299,104 @@ static Int pushArg ( ISelEnv* env, IRExpr* arg )
 static 
 void callHelperAndClearArgs ( ISelEnv* env, IRCallee* cee, Int n_arg_ws )
 {
+   HReg freg;
+
+   /* Complication.  Need to decide which reg to use as the fn address
+      pointer, in a way that doesn't trash regparm-passed
+      parameters. */
    vassert(sizeof(HWord) == 4);
+
+   switch (cee->regparms) {
+      case 0: freg = hregX86_EAX(); break;
+      case 1: freg = hregX86_EDX(); break;
+      case 2: freg = hregX86_ECX(); break;
+      case 3: freg = hregX86_EDI(); break;
+      default: vpanic("callHelperAndClearArgs(x86): > 3 regparms");
+   }
+
    addInstr(env, X86Instr_Alu32R(
                     Xalu_MOV,
                     X86RMI_Imm(cee->addr),
-                    hregX86_EAX()));
-   addInstr(env, X86Instr_Call(hregX86_EAX()));
+                    freg));
+   addInstr(env, X86Instr_Call(freg, cee->regparms));
    if (n_arg_ws > 0)
       addInstr(env, X86Instr_Alu32R(Xalu_ADD,
                        X86RMI_Imm(4*n_arg_ws),
                        hregX86_ESP()));
 }
 
+
+/* Do a complete function call. */
+
+static
+void doHelperCall ( ISelEnv* env, 
+                    Bool passBBP, IRCallee* cee, IRExpr** args )
+{
+   HReg argregs[3];
+   Int n_args, n_arg_ws, stack_limit, i, argreg;
+
+   /* Marshal args for a call, do the call, and clear the stack.
+      Complexities to consider:
+
+      * if passBBP is True, %ebp (the baseblock pointer) is to be
+        passed as the first arg.
+
+      * If the callee claims regparmness of 1, 2 or 3, we must pass the
+        first 1, 2 or 3 args in registers (EAX, EDX, and ECX
+        respectively).  To keep things relatively simple, only args of
+        type I32 may be passed as regparms -- just bomb out if anything
+        else turns up.  Clearly this depends on the front ends not
+        trying to pass any other types as regparms.  
+   */
+
+   vassert(cee->regparms >= 0 && cee->regparms <= 3);
+
+   n_args = n_arg_ws = 0;
+   while (args[n_args]) n_args++;
+
+   stack_limit = cee->regparms;
+   if (cee->regparms > 0 && passBBP) stack_limit--;
+
+   /* Push the stack-passed args */
+   for (i = n_args-1; i >= stack_limit; i--)
+      n_arg_ws += pushArg(env, args[i]);
+
+   /* args [stack_limit-1 .. 0] and possibly %ebp are to be passed in
+      registers. */
+   vassert(stack_limit + (passBBP ? 1 : 0) == cee->regparms);
+
+   if (cee->regparms > 0) {
+      /* deal with regparms, not forgetting %ebp if needed. */
+      argregs[0] = hregX86_EAX();
+      argregs[1] = hregX86_EDX();
+      argregs[2] = hregX86_ECX();
+      argreg = cee->regparms;
+
+      for (i = stack_limit-1; i >= 0; i--) {
+         argreg--;
+         vassert(argreg >= 0);
+         vassert(typeOfIRExpr(env->type_env, args[i]) == Ity_I32);
+         addInstr(env, X86Instr_Alu32R(Xalu_MOV, 
+                                       iselIntExpr_RMI(env, args[i]),
+                                       argregs[argreg]));
+      }
+      if (passBBP) {
+         vassert(argreg == 1);
+         addInstr(env, mk_MOVsd_RR( hregX86_EBP(), argregs[0]));
+      }
+   } else {
+      /* No regparms.  Heave %ebp on the stack if needed. */
+      if (passBBP) {
+         addInstr(env, X86Instr_Push(X86RMI_Reg(hregX86_EBP())));
+         n_arg_ws++;
+      }
+   }
+
+   /* call the helper, and get the args off the stack afterwards. */
+   callHelperAndClearArgs( env, cee, n_arg_ws );
+}
+
+
 /* Given a guest-state array descriptor, an index expression and a
    bias, generate an X86AMode holding the relevant guest state
    offset. */
@@ -862,7 +949,6 @@ static HReg iselIntExpr_R_wrk ( ISelEnv* env, IRExpr* e )
 
    /* --------- CCALL --------- */
    case Iex_CCall: {
-      Int     i, n_args, n_arg_ws;
       HReg    dst = newVRegI(env);
       vassert(ty == Ity_I32);
 
@@ -871,15 +957,8 @@ static HReg iselIntExpr_R_wrk ( ISelEnv* env, IRExpr* e )
       if (e->Iex.CCall.retty != Ity_I32)
          goto irreducible;
 
-      /* push args on the stack, right to left. */
-      n_arg_ws = n_args = 0;
-      while (e->Iex.CCall.args[n_args]) n_args++;
-
-      for (i = n_args-1; i >= 0; i--)
-         n_arg_ws += pushArg(env, e->Iex.CCall.args[i]);
-
-      /* call the helper, and get the args off the stack afterwards. */
-      callHelperAndClearArgs( env, e->Iex.CCall.cee, n_arg_ws );
+      /* Marshal args, do the call, clear stack. */
+      doHelperCall( env, False, e->Iex.CCall.cee, e->Iex.CCall.args );
 
       addInstr(env, mk_MOVsd_RR(hregX86_EAX(), dst));
       return dst;
@@ -1602,19 +1681,11 @@ static void iselIntExpr64_wrk ( HReg* rHi, HReg* rLo, ISelEnv* env, IRExpr* e )
 
    /* --------- CCALL --------- */
    if (e->tag == Iex_CCall) {
-      Int     i, n_args, n_arg_ws;
-      HReg tLo  = newVRegI(env);
-      HReg tHi  = newVRegI(env);
-
-      /* push args on the stack, right to left. */
-      n_arg_ws = n_args = 0;
-      while (e->Iex.CCall.args[n_args]) n_args++;
-
-      for (i = n_args-1; i >= 0; i--)
-         n_arg_ws += pushArg(env, e->Iex.CCall.args[i]);
+      HReg tLo = newVRegI(env);
+      HReg tHi = newVRegI(env);
 
-      /* call the helper, and get the args off the stack afterwards. */
-      callHelperAndClearArgs( env, e->Iex.CCall.cee, n_arg_ws );
+      /* Marshal args, do the call, clear stack. */
+      doHelperCall( env, False, e->Iex.CCall.cee, e->Iex.CCall.args );
 
       addInstr(env, mk_MOVsd_RR(hregX86_EDX(), tHi));
       addInstr(env, mk_MOVsd_RR(hregX86_EAX(), tLo));
@@ -2112,28 +2183,16 @@ static void iselStmt ( ISelEnv* env, IRStmt* stmt )
 
    /* --------- Call to DIRTY helper --------- */
    case Ist_Dirty: {
-      Int      i, n_arg_ws, n_args;
       IRType   retty;
       IRDirty* d = stmt->Ist.Dirty.details;
-
-      /* push args on the stack, right to left. */
-      n_arg_ws = n_args = 0;
-      while (d->args[n_args] != NULL) n_args++;
-
-      for (i = n_args-1; i >= 0; i--)
-         n_arg_ws += pushArg(env, d->args[i]);
+      Bool     passBBP = False;
 
       if (d->nFxState == 0)
          vassert(!d->needsBBP);
-      if (d->nFxState > 0 && d->needsBBP) {
-         /* If the helper claims it accesses guest state, give it a
-            first argument which is the guest state pointer (%ebp). */
-         addInstr(env, X86Instr_Push(X86RMI_Reg(hregX86_EBP())));
-         n_arg_ws++;
-      }
+      passBBP = d->nFxState > 0 && d->needsBBP;
 
-      /* call the helper, and get the args off the stack afterwards. */
-      callHelperAndClearArgs( env, d->cee, n_arg_ws );
+      /* Marshal args, do the call, clear stack. */
+      doHelperCall( env, passBBP, d->cee, d->args );
 
       /* Now figure out what to do with the returned value, if any. */
       if (d->tmp == INVALID_IRTEMP)
index 19b30ec686ac0059d0bf2a54f2e2f49d754a36e4..68636cc1324433c10ec6ab7d38d1a84ddea73b1f 100644 (file)
@@ -51,8 +51,8 @@ void ppIRConst ( IRConst* con )
 void ppIRCallee ( IRCallee* ce )
 {
    vex_printf("%s", ce->name);
-   if (ce->regparm > 0)
-      vex_printf("[%d]", ce->regparm);
+   if (ce->regparms > 0)
+      vex_printf("[%d]", ce->regparms);
    vex_printf("{%p}", (void*)ce->addr);
 }
 
@@ -465,13 +465,13 @@ IRConst* IRConst_F64i ( ULong f64i )
 
 /* Constructors -- IRCallee */
 
-IRCallee* mkIRCallee ( Int regparm, Char* name, HWord addr )
+IRCallee* mkIRCallee ( Int regparms, Char* name, HWord addr )
 {
    IRCallee* ce = LibVEX_Alloc(sizeof(IRCallee));
-   ce->regparm = regparm;
-   ce->name = name;
-   ce->addr = addr;
-   vassert(regparm >= 0);
+   ce->regparms = regparms;
+   ce->name     = name;
+   ce->addr     = addr;
+   vassert(regparms >= 0 && regparms <= 3);
    vassert(name != NULL);
    vassert(addr != 0);
    return ce;
@@ -749,7 +749,7 @@ IRConst* dopyIRConst ( IRConst* c )
 
 IRCallee* dopyIRCallee ( IRCallee* ce )
 {
-   return mkIRCallee(ce->regparm, ce->name, ce->addr);
+   return mkIRCallee(ce->regparms, ce->name, ce->addr);
 }
 
 IRArray* dopyIRArray ( IRArray* d )
@@ -1180,7 +1180,7 @@ static Bool saneIRCallee ( IRCallee* cee )
       return False;
    if (cee->addr == 0)
       return False;
-   if (cee->regparm < 0 || cee->regparm > 3)
+   if (cee->regparms < 0 || cee->regparms > 3)
       return False;
    return True;
 }
index a6130d62c440f54c5d669b117be84933872dd687..0b7e0871bc4180123e00cc93df4c1541ad5cf5ce 100644 (file)
@@ -73,7 +73,7 @@ extern Bool eqIRConst ( IRConst*, IRConst* );
 /* ------------------ Call targets ------------------ */
 
 /* Describes a helper function to call.  The name part is purely for
-   pretty printing and not actually used.  regparm=n tells the back
+   pretty printing and not actually used.  regparms=n tells the back
    end that the callee has been declared
    "__attribute__((regparm(n)))".  On some targets (x86) the back end
    will need to construct a non-standard sequence to call a function
@@ -81,13 +81,13 @@ extern Bool eqIRConst ( IRConst*, IRConst* );
 
 typedef
    struct {
-      Int   regparm;
+      Int   regparms;
       Char* name;
       HWord addr;
    }
    IRCallee;
 
-extern IRCallee* mkIRCallee ( Int regparm, Char* name, HWord addr );
+extern IRCallee* mkIRCallee ( Int regparms, Char* name, HWord addr );
 
 extern IRCallee* dopyIRCallee ( IRCallee* );