]> git.ipfire.org Git - thirdparty/valgrind.git/commitdiff
Complete first pass thru x86 instruction selector.
authorJulian Seward <jseward@acm.org>
Mon, 19 Jul 2004 12:48:11 +0000 (12:48 +0000)
committerJulian Seward <jseward@acm.org>
Mon, 19 Jul 2004 12:48:11 +0000 (12:48 +0000)
git-svn-id: svn://svn.valgrind.org/vex/trunk@97

VEX/priv/host-x86/isel_x86.c
VEX/priv/host-x86/x86h_defs.c
VEX/priv/host-x86/x86h_defs.h

index 1842395cc207a5fbfe7a04eee40b06e46b7e8732..33d84cf53fd429098cbfaf874c3d653672c845d0 100644 (file)
@@ -282,8 +282,8 @@ static HReg iselIntExpr_R ( ISelEnv* env, IRExpr* e )
          case Iop_Sub8: case Iop_Sub16: case Iop_Sub32: 
             aluOp = Xalu_SUB; break;
 
-         case Iop_And8:
-         case Iop_And32: aluOp = Xalu_AND; break;
+         case Iop_And8: case Iop_And16: case Iop_And32: 
+            aluOp = Xalu_AND; break;
          case Iop_Or8: case Iop_Or32:  
             aluOp = Xalu_OR; break;
 
@@ -305,7 +305,8 @@ static HReg iselIntExpr_R ( ISelEnv* env, IRExpr* e )
       /* Perhaps a shift op? */
       switch (e->Iex.Binop.op) {
          case Iop_Shl32: shOp = Xsh_SHL; break;
-         case Iop_Shr32: shOp = Xsh_SHR; break;
+         case Iop_Shr8: case Iop_Shr32: 
+            shOp = Xsh_SHR; break;
          case Iop_Sar32: shOp = Xsh_SAR; break;
          default:        shOp = Xsh_INVALID; break;
       }
@@ -315,6 +316,19 @@ static HReg iselIntExpr_R ( ISelEnv* env, IRExpr* e )
          HReg regR   = iselIntExpr_R(env, e->Iex.Binop.arg2);
          addInstr(env, mk_MOVsd_RR(regL,dst));
          addInstr(env, mk_MOVsd_RR(regR,hregX86_ECX()));
+         /* Do any necessary widening for 16/8 bit operands */
+         switch (e->Iex.Binop.op) {
+            case Iop_Shr8:
+               addInstr(env, X86Instr_Alu32R(
+                                Xalu_AND, X86RMI_Imm(0xFF), dst));
+               break;
+            case Iop_Shr16:
+               addInstr(env, X86Instr_Alu32R(
+                                Xalu_AND, X86RMI_Imm(0xFFFF), dst));
+               break;
+            case Iop_Sar8: case Iop_Sar16: vassert(0); // fill this in!
+            default: break;
+         }
          addInstr(env, X86Instr_Sh32(shOp, 0/* %cl */, X86RM_Reg(dst)));
          return dst;
       }
@@ -445,7 +459,7 @@ static HReg iselIntExpr_R ( ISelEnv* env, IRExpr* e )
        HReg r8 = iselIntExpr_R(env, e->Iex.Mux0X.cond);
        addInstr(env, X86Instr_Alu32R(Xalu_TEST,
                                      X86RMI_Imm(0xFF), r8));
-       addInstr(env, X86Instr_CMovZ(r0,dst));
+       addInstr(env, X86Instr_CMov32(Xcc_Z,r0,dst));
        return dst;
       }
       break;
@@ -688,6 +702,76 @@ static void iselIntExpr64 ( HReg* rHi, HReg* rLo, ISelEnv* env, IRExpr* e )
       return;
    }
 
+   /* 64 x 32 -> (32(rem),32(div)) division */
+   if (e->tag == Iex_Binop
+      && (e->Iex.Binop.op == Iop_DivModU64to32
+          || e->Iex.Binop.op == Iop_DivModS64to32)) {
+      /* Get the 64-bit operand into edx:eax, and the other
+         into any old R/M. */
+      HReg sHi, sLo;
+      Bool   syned   = e->Iex.Binop.op == Iop_MullS32;
+      X86RM* rmRight = iselIntExpr_RM(env, e->Iex.Binop.arg2);
+      iselIntExpr64(&sHi,&sLo, env, e->Iex.Binop.arg1);
+      addInstr(env, mk_MOVsd_RR(sHi, hregX86_EDX()));
+      addInstr(env, mk_MOVsd_RR(sLo, hregX86_EAX()));
+      addInstr(env, X86Instr_Div(syned, Xss_32, rmRight));
+      *rHi = hregX86_EDX();
+      *rLo = hregX86_EAX();
+      return;
+   }
+
+   /* 32HLto64(e1,e2) */
+   if (e->tag == Iex_Binop
+       && e->Iex.Binop.op == Iop_32HLto64) {
+      *rHi = iselIntExpr_R(env, e->Iex.Binop.arg1);
+      *rLo = iselIntExpr_R(env, e->Iex.Binop.arg2);
+      return;
+   }
+
+   /* 64-bit shifts */
+   if (e->tag == Iex_Binop
+       && e->Iex.Binop.op == Iop_Shl64) {
+      /* We use the same ingenious scheme as gcc.  Put the value
+         to be shifted into %hi:%lo, and the shift amount into %cl.
+         Then (dsts on right, a la ATT syntax):
+            shldl %cl, %lo, %hi   -- make %hi be right for the shift amt
+                                  -- %cl % 32
+            shll  %cl, %lo        -- make %lo be right for the shift amt
+                                  -- %cl % 32
+
+         Now, if (shift amount % 64) is in the range 32 .. 63, we have 
+         to do a fixup, which puts the result low half into the result
+         high half, and zeroes the low half:
+
+            testl $32, %ecx
+
+            cmovnz %lo, %hi
+            movl $0, %tmp         -- sigh; need yet another reg
+            cmovnz %tmp, %lo
+      */
+      HReg rAmt, sHi, sLo, tHi, tLo, tTemp;
+      tLo = newVRegI(env);
+      tHi = newVRegI(env);
+      tTemp = newVRegI(env);
+      rAmt = iselIntExpr_R(env, e->Iex.Binop.arg2);
+      iselIntExpr64(&sHi,&sLo, env, e->Iex.Binop.arg1);
+      addInstr(env, mk_MOVsd_RR(rAmt, hregX86_ECX()));
+      addInstr(env, mk_MOVsd_RR(sHi, tHi));
+      addInstr(env, mk_MOVsd_RR(sLo, tLo));
+      /* Ok.  Now shift amt is in %ecx, and value is in tHi/tLo and
+         those regs are legitimately modifiable. */
+      addInstr(env, X86Instr_Sh3232(Xsh_SHL, 0/*%cl*/, tHi, tLo));
+      addInstr(env, X86Instr_Sh32(Xsh_SHL, 0/*%cl*/, X86RM_Reg(tLo)));
+      addInstr(env, X86Instr_Alu32R(Xalu_TEST, X86RMI_Imm(32), hregX86_ECX()));
+      addInstr(env, X86Instr_CMov32(Xcc_NZ, X86RM_Reg(tLo), tHi));
+      addInstr(env, X86Instr_Alu32R(Xalu_MOV, X86RMI_Imm(0), tTemp));
+      addInstr(env, X86Instr_CMov32(Xcc_NZ, X86RM_Reg(tTemp), tLo));
+      *rHi = tHi;
+      *rLo = tLo;
+      return;
+   }
+
    ppIRExpr(e);
    vpanic("iselIntExpr64");
 }
index fc81014582a13653c4a7d62029606e8d4ea2a96c..dc4fde7bfba46244795e3d8cf8eef6a45a2383f3 100644 (file)
@@ -428,6 +428,14 @@ X86Instr* X86Instr_MulL ( Bool syned, X86ScalarSz ssz , X86RM* src ) {
    i->Xin.MulL.src    = src;
    return i;
 }
+X86Instr* X86Instr_Div ( Bool syned, X86ScalarSz ssz, X86RM* src ) {
+   X86Instr* i        = LibVEX_Alloc(sizeof(X86Instr));
+   i->tag             = Xin_Div;
+   i->Xin.Div.syned   = syned;
+   i->Xin.Div.ssz     = ssz;
+   i->Xin.Div.src     = src;
+   return i;
+}
 X86Instr* X86Instr_Sh32 ( X86ShiftOp op, UInt src, X86RM* dst ) {
    X86Instr* i     = LibVEX_Alloc(sizeof(X86Instr));
    i->tag          = Xin_Sh32;
@@ -436,6 +444,16 @@ X86Instr* X86Instr_Sh32 ( X86ShiftOp op, UInt src, X86RM* dst ) {
    i->Xin.Sh32.dst = dst;
    return i;
 }
+X86Instr* X86Instr_Sh3232  ( X86ShiftOp op, UInt amt, HReg rHi, HReg rLo ) {
+   X86Instr* i       = LibVEX_Alloc(sizeof(X86Instr));
+   i->tag            = Xin_Sh3232;
+   i->Xin.Sh3232.op  = op;
+   i->Xin.Sh3232.amt = amt;
+   i->Xin.Sh3232.rHi = rHi;
+   i->Xin.Sh3232.rLo = rLo;
+   vassert(op == Xsh_SHL || op == Xsh_SHR);
+   return i;
+}
 X86Instr* X86Instr_Push( X86RMI* src ) {
    X86Instr* i     = LibVEX_Alloc(sizeof(X86Instr));
    i->tag          = Xin_Push;
@@ -455,11 +473,13 @@ X86Instr* X86Instr_Goto ( X86CondCode cond, X86RI* dst ) {
    i->Xin.Goto.dst  = dst;
    return i;
 }
-X86Instr* X86Instr_CMovZ  ( X86RM* src, HReg dst ) {
-   X86Instr* i      = LibVEX_Alloc(sizeof(X86Instr));
-   i->tag           = Xin_CMovZ;
-   i->Xin.CMovZ.src = src;
-   i->Xin.CMovZ.dst = dst;
+X86Instr* X86Instr_CMov32  ( X86CondCode cond, X86RM* src, HReg dst ) {
+   X86Instr* i        = LibVEX_Alloc(sizeof(X86Instr));
+   i->tag             = Xin_CMov32;
+   i->Xin.CMov32.cond = cond;
+   i->Xin.CMov32.src  = src;
+   i->Xin.CMov32.dst  = dst;
+   vassert(cond != Xcc_ALWAYS);
    return i;
 }
 X86Instr* X86Instr_LoadEX ( UChar szSmall, Bool syned,
@@ -508,6 +528,12 @@ void ppX86Instr ( X86Instr* i ) {
                     showX86ScalarSz(i->Xin.MulL.ssz));
          ppX86RM(i->Xin.MulL.src);
          return;
+      case Xin_Div:
+         vex_printf("%cdiv%s ",
+                    i->Xin.Div.syned ? 's' : 'u',
+                    showX86ScalarSz(i->Xin.Div.ssz));
+         ppX86RM(i->Xin.Div.src);
+         return;
       case Xin_Sh32:
          vex_printf("%sl ", showX86ShiftOp(i->Xin.Sh32.op));
          if (i->Xin.Sh32.src == 0)
@@ -516,6 +542,16 @@ void ppX86Instr ( X86Instr* i ) {
             vex_printf(" $%d,", i->Xin.Sh32.src);
          ppX86RM(i->Xin.Sh32.dst);
          return;
+      case Xin_Sh3232:
+         vex_printf("%sdl ", showX86ShiftOp(i->Xin.Sh3232.op));
+         if (i->Xin.Sh3232.amt == 0)
+          vex_printf(" %%cl,"); 
+         else 
+            vex_printf(" $%d,", i->Xin.Sh3232.amt);
+         ppHRegX86(i->Xin.Sh3232.rLo);
+         vex_printf(",");
+         ppHRegX86(i->Xin.Sh3232.rHi);
+         return;
       case Xin_Push:
          vex_printf("pushl ");
          ppX86RMI(i->Xin.Push.src);
@@ -536,11 +572,11 @@ void ppX86Instr ( X86Instr* i ) {
             vex_printf(",%%eax ; ret }");
          }
          return;
-      case Xin_CMovZ:
-         vex_printf("cmovz ");
-         ppX86RM(i->Xin.CMovZ.src);
+      case Xin_CMov32:
+         vex_printf("cmovl%s ", showX86CondCode(i->Xin.CMov32.cond));
+         ppX86RM(i->Xin.CMov32.src);
          vex_printf(",");
-         ppHRegX86(i->Xin.CMovZ.dst);
+         ppHRegX86(i->Xin.CMov32.dst);
          return;
       case Xin_LoadEX:
          vex_printf("mov%c%cl ",
index c09fabb6649a473f812b8d1780bc507b41077c84..eb8231796c4f54fe8a989003551f7bcecb8073da 100644 (file)
@@ -250,11 +250,13 @@ typedef
       Xin_Alu32M,    /* 32-bit mov/arith/logical, dst=MEM */
       Xin_Unary32,   /* 32-bit not and neg */
       Xin_MulL,      /* widening multiply */
+      Xin_Div,       /* div and mod */
       Xin_Sh32,      /* 32-bit shift/rotate, dst=REG or MEM */
+      Xin_Sh3232,    /* shldl or shrdl */
       Xin_Push,      /* push (32-bit?) value on stack */
       Xin_Call,      /* call to address in register */
       Xin_Goto,      /* conditional/unconditional jmp to dst */
-      Xin_CMovZ,     /* conditional move when Z flag set */
+      Xin_CMov32,    /* conditional move */
       Xin_LoadEX,    /* mov{s,z}{b,w}l from mem to reg */
       Xin_Store      /* store 16/8 bit value in memory */
    }
@@ -287,11 +289,24 @@ typedef
             X86ScalarSz ssz;
             X86RM*      src;
          } MulL;
+         /* x86 div/idiv instruction */
+         struct {
+            Bool        syned;
+            X86ScalarSz ssz;
+            X86RM*      src;
+         } Div;
          struct {
             X86ShiftOp op;
             UInt       src;  /* shift amount, or 0 means %cl */
             X86RM*     dst;
          } Sh32;
+         /* shld/shrd.  op may only be Xsh_SHL or Xsh_SHR */
+         struct {
+            X86ShiftOp op;
+            UInt amt;   /* shift amount, or 0 means %cl */
+            HReg rHi;
+            HReg rLo;
+         } Sh3232;
          struct {
             X86RMI* src;
          } Push;
@@ -304,12 +319,13 @@ typedef
             X86CondCode cond;
             X86RI*      dst;
          } Goto;
-         /* Mov src to dst (both 32-bit regs?) when the Z flag is
-            set. */
+         /* Mov src to dst on the given condition, which may not
+            be the bogus Xcc_ALWAYS. */
          struct {
+            X86CondCode cond;
             X86RM* src;
             HReg   dst;
-         } CMovZ;
+         } CMov32;
          /* Sign/Zero extending loads.  Dst size is always 32 bits. */
          struct {
             UChar     szSmall;
@@ -332,11 +348,13 @@ extern X86Instr* X86Instr_Alu32R  ( X86AluOp, X86RMI*, HReg );
 extern X86Instr* X86Instr_Alu32M  ( X86AluOp, X86RI*,  X86AMode* );
 extern X86Instr* X86Instr_Unary32 ( X86UnaryOp op, X86RM* dst );
 extern X86Instr* X86Instr_MulL    ( Bool syned, X86ScalarSz, X86RM* );
+extern X86Instr* X86Instr_Div     ( Bool syned, X86ScalarSz, X86RM* );
 extern X86Instr* X86Instr_Sh32    ( X86ShiftOp, UInt, X86RM* );
+extern X86Instr* X86Instr_Sh3232  ( X86ShiftOp, UInt amt, HReg rHi, HReg rLo );
 extern X86Instr* X86Instr_Push    ( X86RMI* );
 extern X86Instr* X86Instr_Call    ( HReg );
 extern X86Instr* X86Instr_Goto    ( X86CondCode cond, X86RI* dst );
-extern X86Instr* X86Instr_CMovZ   ( X86RM* src, HReg dst );
+extern X86Instr* X86Instr_CMov32  ( X86CondCode, X86RM* src, HReg dst );
 extern X86Instr* X86Instr_LoadEX  ( UChar szSmall, Bool syned,
                                     X86AMode* src, HReg dst );
 extern X86Instr* X86Instr_Store   ( UChar sz, HReg src, X86AMode* dst );