]> git.ipfire.org Git - thirdparty/valgrind.git/commitdiff
Fix many instruction selection cases, including function calls.
authorJulian Seward <jseward@acm.org>
Fri, 4 Feb 2005 01:44:33 +0000 (01:44 +0000)
committerJulian Seward <jseward@acm.org>
Fri, 4 Feb 2005 01:44:33 +0000 (01:44 +0000)
git-svn-id: svn://svn.valgrind.org/vex/trunk@833

VEX/priv/host-amd64/hdefs.c
VEX/priv/host-amd64/hdefs.h
VEX/priv/host-amd64/isel.c
VEX/priv/host-generic/h_generic_regs.h

index b9a7a8fad60380bd5cf38f88a4564c5e95bdca58..e263bbcd572fd7a0a9322083080265f7c9c20aae 100644 (file)
@@ -408,12 +408,12 @@ AMD64RM* AMD64RM_Reg ( HReg reg ) {
    op->Arm.Reg.reg = reg;
    return op;
 }
-//.. AMD64RM* AMD64RM_Mem ( AMD64AMode* am ) {
-//..    AMD64RM* op      = LibVEX_Alloc(sizeof(AMD64RM));
-//..    op->tag        = Xrm_Mem;
-//..    op->Xrm.Mem.am = am;
-//..    return op;
-//.. }
+AMD64RM* AMD64RM_Mem ( AMD64AMode* am ) {
+   AMD64RM* op    = LibVEX_Alloc(sizeof(AMD64RM));
+   op->tag        = Arm_Mem;
+   op->Arm.Mem.am = am;
+   return op;
+}
 
 void ppAMD64RM ( AMD64RM* op ) {
    switch (op->tag) {
@@ -630,13 +630,13 @@ AMD64Instr* AMD64Instr_Sh64 ( AMD64ShiftOp op, UInt src, AMD64RM* dst ) {
    i->Ain.Sh64.dst = dst;
    return i;
 }
-//.. AMD64Instr* AMD64Instr_Test32  ( AMD64RI* src, AMD64RM* dst ) {
-//..    AMD64Instr* i       = LibVEX_Alloc(sizeof(AMD64Instr));
-//..    i->tag            = Xin_Test32;
-//..    i->Xin.Test32.src = src;
-//..    i->Xin.Test32.dst = dst;
-//..    return i;
-//.. }
+AMD64Instr* AMD64Instr_Test64 ( AMD64RI* src, AMD64RM* dst ) {
+   AMD64Instr* i     = LibVEX_Alloc(sizeof(AMD64Instr));
+   i->tag            = Ain_Test64;
+   i->Ain.Test64.src = src;
+   i->Ain.Test64.dst = dst;
+   return i;
+}
 //.. AMD64Instr* AMD64Instr_Unary32  ( AMD64UnaryOp op, AMD64RM* dst ) {
 //..    AMD64Instr* i        = LibVEX_Alloc(sizeof(AMD64Instr));
 //..    i->tag             = Xin_Unary32;
@@ -676,15 +676,15 @@ AMD64Instr* AMD64Instr_Sh64 ( AMD64ShiftOp op, UInt src, AMD64RM* dst ) {
 //..    i->Xin.Push.src = src;
 //..    return i;
 //.. }
-//.. AMD64Instr* AMD64Instr_Call ( AMD64CondCode cond, Addr32 target, Int regparms ) {
-//..    AMD64Instr* i          = LibVEX_Alloc(sizeof(AMD64Instr));
-//..    i->tag               = Xin_Call;
-//..    i->Xin.Call.cond     = cond;
-//..    i->Xin.Call.target   = target;
-//..    i->Xin.Call.regparms = regparms;
-//..    vassert(regparms >= 0 && regparms <= 3);
-//..    return i;
-//.. }
+AMD64Instr* AMD64Instr_Call ( AMD64CondCode cond, Addr64 target, Int regparms ) {
+   AMD64Instr* i        = LibVEX_Alloc(sizeof(AMD64Instr));
+   i->tag               = Ain_Call;
+   i->Ain.Call.cond     = cond;
+   i->Ain.Call.target   = target;
+   i->Ain.Call.regparms = regparms;
+   vassert(regparms >= 0 && regparms <= 6);
+   return i;
+}
 AMD64Instr* AMD64Instr_Goto ( IRJumpKind jk, AMD64CondCode cond, AMD64RI* dst ) {
    AMD64Instr* i    = LibVEX_Alloc(sizeof(AMD64Instr));
    i->tag           = Ain_Goto;
@@ -693,15 +693,15 @@ AMD64Instr* AMD64Instr_Goto ( IRJumpKind jk, AMD64CondCode cond, AMD64RI* dst )
    i->Ain.Goto.jk   = jk;
    return i;
 }
-//.. AMD64Instr* AMD64Instr_CMov32  ( AMD64CondCode cond, AMD64RM* src, HReg dst ) {
-//..    AMD64Instr* i        = LibVEX_Alloc(sizeof(AMD64Instr));
-//..    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;
-//.. }
+AMD64Instr* AMD64Instr_CMov64 ( AMD64CondCode cond, AMD64RM* src, HReg dst ) {
+   AMD64Instr* i      = LibVEX_Alloc(sizeof(AMD64Instr));
+   i->tag             = Ain_CMov64;
+   i->Ain.CMov64.cond = cond;
+   i->Ain.CMov64.src  = src;
+   i->Ain.CMov64.dst  = dst;
+   vassert(cond != Acc_ALWAYS);
+   return i;
+}
 AMD64Instr* AMD64Instr_MovZLQ ( HReg src, HReg dst ) {
    AMD64Instr* i     = LibVEX_Alloc(sizeof(AMD64Instr));
    i->tag            = Ain_MovZLQ;
@@ -942,12 +942,12 @@ void ppAMD64Instr ( AMD64Instr* i )
             vex_printf("$%d,", i->Ain.Sh64.src);
          ppAMD64RM(i->Ain.Sh64.dst);
          return;
-//..       case Xin_Test32:
-//..          vex_printf("testl ");
-//..          ppAMD64RI(i->Xin.Test32.src);
-//..          vex_printf(",");
-//..          ppAMD64RM(i->Xin.Test32.dst);
-//..          return;
+      case Ain_Test64:
+         vex_printf("testq ");
+         ppAMD64RI(i->Ain.Test64.src);
+         vex_printf(",");
+         ppAMD64RM(i->Ain.Test64.dst);
+         return;
 //..       case Xin_Unary32:
 //..          vex_printf("%sl ", showAMD64UnaryOp(i->Xin.Unary32.op));
 //..          ppAMD64RM(i->Xin.Unary32.dst);
@@ -978,13 +978,13 @@ void ppAMD64Instr ( AMD64Instr* i )
 //..          vex_printf("pushl ");
 //..          ppAMD64RMI(i->Xin.Push.src);
 //..          return;
-//..       case Xin_Call:
-//..          vex_printf("call%s[%d] ", 
-//..                     i->Xin.Call.cond==Xcc_ALWAYS 
-//..                        ? "" : showAMD64CondCode(i->Xin.Call.cond), 
-//..                     i->Xin.Call.regparms);
-//..          vex_printf("0x%x", i->Xin.Call.target);
-//..          break;
+      case Ain_Call:
+         vex_printf("call%s[%d] ", 
+                    i->Ain.Call.cond==Acc_ALWAYS 
+                       ? "" : showAMD64CondCode(i->Ain.Call.cond),
+                    i->Ain.Call.regparms );
+         vex_printf("0x%llx", i->Ain.Call.target);
+         break;
       case Ain_Goto:
          if (i->Ain.Goto.cond != Acc_ALWAYS) {
             vex_printf("if (%%rflags.%s) { ", 
@@ -1002,12 +1002,12 @@ void ppAMD64Instr ( AMD64Instr* i )
             vex_printf(" }");
          }
          return;
-//..       case Xin_CMov32:
-//..          vex_printf("cmov%s ", showAMD64CondCode(i->Xin.CMov32.cond));
-//..          ppAMD64RM(i->Xin.CMov32.src);
-//..          vex_printf(",");
-//..          ppHRegAMD64(i->Xin.CMov32.dst);
-//..          return;
+      case Ain_CMov64:
+         vex_printf("cmov%s ", showAMD64CondCode(i->Ain.CMov64.cond));
+         ppAMD64RM(i->Ain.CMov64.src);
+         vex_printf(",");
+         ppHRegAMD64(i->Ain.CMov64.dst);
+         return;
       case Ain_MovZLQ:
          vex_printf("movzlq ");
          ppHRegAMD64(i->Ain.MovZLQ.src);
@@ -1024,12 +1024,13 @@ void ppAMD64Instr ( AMD64Instr* i )
          vex_printf(",");
          ppHRegAMD64(i->Ain.LoadEX.dst);
          return;
-//..       case Xin_Store:
-//..          vex_printf("mov%c ", i->Xin.Store.sz==1 ? 'b' : 'w');
-//..          ppHRegAMD64(i->Xin.Store.src);
-//..          vex_printf(",");
-//..          ppAMD64AMode(i->Xin.Store.dst);
-//..          return;
+      case Ain_Store:
+         vex_printf("mov%c ", i->Ain.Store.sz==1 ? 'b' 
+                              : (i->Ain.Store.sz==2 ? 'w' : 'l'));
+         ppHRegAMD64(i->Ain.Store.src);
+         vex_printf(",");
+         ppAMD64AMode(i->Ain.Store.dst);
+         return;
 //..       case Xin_Set32:
 //..          vex_printf("setl%s ", showAMD64CondCode(i->Xin.Set32.cond));
 //..          ppHRegAMD64(i->Xin.Set32.dst);
@@ -1211,10 +1212,10 @@ void getRegUsage_AMD64Instr ( HRegUsage* u, AMD64Instr* i )
          if (i->Ain.Sh64.src == 0)
             addHRegUse(u, HRmRead, hregAMD64_RCX());
          return;
-//..       case Xin_Test32:
-//..          addRegUsage_AMD64RI(u, i->Xin.Test32.src);
-//..          addRegUsage_AMD64RM(u, i->Xin.Test32.dst, HRmRead);
-//..          return;
+      case Ain_Test64:
+         addRegUsage_AMD64RI(u, i->Ain.Test64.src);
+         addRegUsage_AMD64RM(u, i->Ain.Test64.dst, HRmRead);
+         return;
 //..       case Xin_Unary32:
 //..          addRegUsage_AMD64RM(u, i->Xin.Unary32.dst, HRmModify);
 //..          return;
@@ -1238,47 +1239,52 @@ void getRegUsage_AMD64Instr ( HRegUsage* u, AMD64Instr* i )
 //..          addRegUsage_AMD64RMI(u, i->Xin.Push.src);
 //..          addHRegUse(u, HRmModify, hregAMD64_ESP());
 //..          return;
-//..       case Xin_Call:
-//..          /* This is a bit subtle. */
-//..          /* First off, claim it trashes all the callee-saved regs */
-//..          /* which I believe to be %eax,%ecx,%edx. */
-//..          addHRegUse(u, HRmWrite, hregAMD64_EAX());
-//..          addHRegUse(u, HRmWrite, hregAMD64_ECX());
-//..          addHRegUse(u, HRmWrite, hregAMD64_EDX());
-//..          /* Now we have to state any parameter-carrying registers
-//..             which might be read.  This depends on the regparmness. */
-//..          switch (i->Xin.Call.regparms) {
-//..             case 3: addHRegUse(u, HRmRead, hregAMD64_ECX()); /*fallthru*/
-//..             case 2: addHRegUse(u, HRmRead, hregAMD64_EDX()); /*fallthru*/
-//..             case 1: addHRegUse(u, HRmRead, hregAMD64_EAX()); break;
-//..             case 0: break;
-//..             default: vpanic("getRegUsage_AMD64Instr:Call:regparms");
-//..          }
-//..          /* Finally, there is the issue that the insn trashes a
-//..             register because the literal target address has to be
-//..             loaded into a register.  Fortunately, for the 0/1/2
-//..             regparm case, we can use EAX, EDX and ECX respectively, so
-//..             this does not cause any further damage.  For the 3-regparm
-//..             case, we'll have to choose another register arbitrarily --
-//..             since A, D and C are used for parameters -- and so we might
-//..             as well choose EDI. */
-//..          if (i->Xin.Call.regparms == 3)
-//..             addHRegUse(u, HRmWrite, hregAMD64_EDI());
-//..          /* Upshot of this is that the assembler really must observe
-//..             the here-stated convention of which register to use as an
-//..             address temporary, depending on the regparmness: 0==EAX,
-//..             1==EDX, 2==ECX, 3==EDI. */
-//..          return;
+      case Ain_Call:
+         /* This is a bit subtle. */
+         /* First off, claim it trashes all the caller-saved regs
+            which fall within the register allocator's jurisdiction.
+            These I believe to be: rax rcx rdx rsi rdi r8 r9 r10 r11 
+         */
+         addHRegUse(u, HRmWrite, hregAMD64_RAX());
+         addHRegUse(u, HRmWrite, hregAMD64_RCX());
+         addHRegUse(u, HRmWrite, hregAMD64_RDX());
+         addHRegUse(u, HRmWrite, hregAMD64_RSI());
+         addHRegUse(u, HRmWrite, hregAMD64_RDI());
+         addHRegUse(u, HRmWrite, hregAMD64_R8());
+         addHRegUse(u, HRmWrite, hregAMD64_R9());
+         addHRegUse(u, HRmWrite, hregAMD64_R10());
+         addHRegUse(u, HRmWrite, hregAMD64_R11());
+
+         /* Now we have to state any parameter-carrying registers
+            which might be read.  This depends on the regparmness. */
+         switch (i->Ain.Call.regparms) {
+            case 6: addHRegUse(u, HRmRead, hregAMD64_R9());  /*fallthru*/
+            case 5: addHRegUse(u, HRmRead, hregAMD64_R8());  /*fallthru*/
+            case 4: addHRegUse(u, HRmRead, hregAMD64_RCX()); /*fallthru*/
+            case 3: addHRegUse(u, HRmRead, hregAMD64_RDX()); /*fallthru*/
+            case 2: addHRegUse(u, HRmRead, hregAMD64_RSI()); /*fallthru*/
+            case 1: addHRegUse(u, HRmRead, hregAMD64_RDI()); break;
+            case 0: break;
+            default: vpanic("getRegUsage_AMD64Instr:Call:regparms");
+         }
+         /* Finally, there is the issue that the insn trashes a
+            register because the literal target address has to be
+            loaded into a register.  Fortunately, r11 is stated in the
+            ABI as a scratch register, and so seems a suitable victim.  */
+         addHRegUse(u, HRmWrite, hregAMD64_R11());
+         /* Upshot of this is that the assembler really must use r11,
+            and no other, as a destination temporary. */
+         return;
       case Ain_Goto:
          addRegUsage_AMD64RI(u, i->Ain.Goto.dst);
          addHRegUse(u, HRmWrite, hregAMD64_RAX());
          if (i->Ain.Goto.jk != Ijk_Boring)
             addHRegUse(u, HRmWrite, hregAMD64_RBP());
          return;
-//..       case Xin_CMov32:
-//..          addRegUsage_AMD64RM(u, i->Xin.CMov32.src, HRmRead);
-//..          addHRegUse(u, HRmModify, i->Xin.CMov32.dst);
-//..          return;
+      case Ain_CMov64:
+         addRegUsage_AMD64RM(u, i->Ain.CMov64.src, HRmRead);
+         addHRegUse(u, HRmModify, i->Ain.CMov64.dst);
+         return;
       case Ain_MovZLQ:
          addHRegUse(u, HRmRead,  i->Ain.MovZLQ.src);
          addHRegUse(u, HRmWrite, i->Ain.MovZLQ.dst);
@@ -1287,10 +1293,10 @@ void getRegUsage_AMD64Instr ( HRegUsage* u, AMD64Instr* i )
          addRegUsage_AMD64AMode(u, i->Ain.LoadEX.src);
          addHRegUse(u, HRmWrite, i->Ain.LoadEX.dst);
          return;
-//..       case Xin_Store:
-//..          addHRegUse(u, HRmRead, i->Xin.Store.src);
-//..          addRegUsage_AMD64AMode(u, i->Xin.Store.dst);
-//..          return;
+      case Ain_Store:
+         addHRegUse(u, HRmRead, i->Ain.Store.src);
+         addRegUsage_AMD64AMode(u, i->Ain.Store.dst);
+         return;
 //..       case Xin_Set32:
 //..          addHRegUse(u, HRmWrite, i->Xin.Set32.dst);
 //..          return;
@@ -1434,10 +1440,10 @@ void mapRegs_AMD64Instr ( HRegRemap* m, AMD64Instr* i )
       case Ain_Sh64:
          mapRegs_AMD64RM(m, i->Ain.Sh64.dst);
          return;
-//..       case Xin_Test32:
-//..          mapRegs_AMD64RI(m, i->Xin.Test32.src);
-//..          mapRegs_AMD64RM(m, i->Xin.Test32.dst);
-//..          return;
+      case Ain_Test64:
+         mapRegs_AMD64RI(m, i->Ain.Test64.src);
+         mapRegs_AMD64RM(m, i->Ain.Test64.dst);
+         return;
 //..       case Xin_Unary32:
 //..          mapRegs_AMD64RM(m, i->Xin.Unary32.dst);
 //..          return;
@@ -1454,15 +1460,15 @@ void mapRegs_AMD64Instr ( HRegRemap* m, AMD64Instr* i )
 //..       case Xin_Push:
 //..          mapRegs_AMD64RMI(m, i->Xin.Push.src);
 //..          return;
-//..       case Xin_Call:
-//..          return;
+      case Ain_Call:
+         return;
       case Ain_Goto:
          mapRegs_AMD64RI(m, i->Ain.Goto.dst);
          return;
-//..       case Xin_CMov32:
-//..          mapRegs_AMD64RM(m, i->Xin.CMov32.src);
-//..          mapReg(m, &i->Xin.CMov32.dst);
-//..          return;
+      case Ain_CMov64:
+         mapRegs_AMD64RM(m, i->Ain.CMov64.src);
+         mapReg(m, &i->Ain.CMov64.dst);
+         return;
       case Ain_MovZLQ:
          mapReg(m, &i->Ain.MovZLQ.src);
          mapReg(m, &i->Ain.MovZLQ.dst);
@@ -1471,10 +1477,10 @@ void mapRegs_AMD64Instr ( HRegRemap* m, AMD64Instr* i )
          mapRegs_AMD64AMode(m, i->Ain.LoadEX.src);
          mapReg(m, &i->Ain.LoadEX.dst);
          return;
-//..       case Xin_Store:
-//..          mapReg(m, &i->Xin.Store.src);
-//..          mapRegs_AMD64AMode(m, i->Xin.Store.dst);
-//..          return;
+      case Ain_Store:
+         mapReg(m, &i->Ain.Store.src);
+         mapRegs_AMD64AMode(m, i->Ain.Store.dst);
+         return;
 //..       case Xin_Set32:
 //..          mapReg(m, &i->Xin.Set32.dst);
 //..          return;
index 1cd49792b6d839f31fe324f2602aa1caef606f4e..2787ede1b96949e0dfb13fb8ae32ea84698dc41e 100644 (file)
@@ -367,15 +367,15 @@ typedef
       Ain_Alu64R,    /* 64-bit mov/arith/logical, dst=REG */
       Ain_Alu64M,    /* 64-bit mov/arith/logical, dst=MEM */
       Ain_Sh64,      /* 64-bit shift/rotate, dst=REG or MEM */
-//..       Xin_Test32,    /* 32-bit test (AND, set flags, discard result) */
+      Ain_Test64,    /* 64-bit test (AND, set flags, discard result) */
 //..       Xin_Unary32,   /* 32-bit not and neg */
 //..       Xin_MulL,      /* widening multiply */
 //..       Xin_Div,       /* div and mod */
 //..       Xin_Sh3232,    /* shldl or shrdl */
 //..       Xin_Push,      /* push (32-bit?) value on stack */
-//..       Xin_Call,      /* call to address in register */
+      Ain_Call,      /* call to address in register */
       Ain_Goto,      /* conditional/unconditional jmp to dst */
-//..       Xin_CMov32,    /* conditional move */
+      Ain_CMov64,    /* conditional move */
       Ain_MovZLQ,    /* reg-reg move, zeroing out top half */
       Ain_LoadEX,    /* mov{s,z}{b,w,l}q from mem to reg */
       Ain_Store,     /* store 32/16/8 bit value in memory */
@@ -427,10 +427,10 @@ typedef
             UInt         src;  /* shift amount, or 0 means %cl */
             AMD64RM*     dst;
          } Sh64;
-//..          struct {
-//..             X86RI* src;
-//..             X86RM* dst;
-//..          } Test32;
+         struct {
+            AMD64RI* src;
+            AMD64RM* dst;
+         } Test64;
 //..          /* Not and Neg */
 //..          struct {
 //..             X86UnaryOp op;
@@ -458,13 +458,13 @@ typedef
 //..          struct {
 //..             X86RMI* src;
 //..          } Push;
-//..          /* Pseudo-insn.  Call target (an absolute address), on given
-//..             condition (which could be Xcc_ALWAYS). */
-//..          struct {
-//..             X86CondCode cond;
-//..             Addr32      target;
-//..             Int         regparms; /* 0 .. 3 */
-//..          } Call;
+         /* Pseudo-insn.  Call target (an absolute address), on given
+            condition (which could be Xcc_ALWAYS). */
+         struct {
+            AMD64CondCode cond;
+            Addr64        target;
+            Int           regparms; /* 0 .. 6 */
+         } Call;
          /* Pseudo-insn.  Goto dst, on given condition (which could be
             Acc_ALWAYS). */
          struct {
@@ -472,13 +472,13 @@ typedef
             AMD64CondCode cond;
             AMD64RI*      dst;
          } Goto;
-//..          /* Mov src to dst on the given condition, which may not
-//..             be the bogus Xcc_ALWAYS. */
-//..          struct {
-//..             X86CondCode cond;
-//..             X86RM*      src;
-//..             HReg        dst;
-//..          } CMov32;
+         /* Mov src to dst on the given condition, which may not
+            be the bogus Acc_ALWAYS. */
+         struct {
+            AMD64CondCode cond;
+            AMD64RM*      src;
+            HReg          dst;
+         } CMov64;
          /* reg-reg move, zeroing out top half */
          struct {
             HReg src;
@@ -639,14 +639,14 @@ extern AMD64Instr* AMD64Instr_Alu64R    ( AMD64AluOp, AMD64RMI*, HReg );
 extern AMD64Instr* AMD64Instr_Alu64M    ( AMD64AluOp, AMD64RI*,  AMD64AMode* );
 //.. extern AMD64Instr* AMD64Instr_Unary32   ( AMD64UnaryOp op, AMD64RM* dst );
 extern AMD64Instr* AMD64Instr_Sh64      ( AMD64ShiftOp, UInt, AMD64RM* );
-//.. extern AMD64Instr* AMD64Instr_Test32    ( AMD64RI* src, AMD64RM* dst );
+extern AMD64Instr* AMD64Instr_Test64    ( AMD64RI* src, AMD64RM* dst );
 //.. extern AMD64Instr* AMD64Instr_MulL      ( Bool syned, AMD64ScalarSz, AMD64RM* );
 //.. extern AMD64Instr* AMD64Instr_Div       ( Bool syned, AMD64ScalarSz, AMD64RM* );
 //.. extern AMD64Instr* AMD64Instr_Sh3232    ( AMD64ShiftOp, UInt amt, HReg src, HReg dst );
 //.. extern AMD64Instr* AMD64Instr_Push      ( AMD64RMI* );
-//.. extern AMD64Instr* AMD64Instr_Call      ( AMD64CondCode, Addr32, Int );
+extern AMD64Instr* AMD64Instr_Call      ( AMD64CondCode, Addr64, Int );
 extern AMD64Instr* AMD64Instr_Goto      ( IRJumpKind, AMD64CondCode cond, AMD64RI* dst );
-//.. extern AMD64Instr* AMD64Instr_CMov32    ( AMD64CondCode, AMD64RM* src, HReg dst );
+extern AMD64Instr* AMD64Instr_CMov64    ( AMD64CondCode, AMD64RM* src, HReg dst );
 extern AMD64Instr* AMD64Instr_MovZLQ    ( HReg src, HReg dst );
 extern AMD64Instr* AMD64Instr_LoadEX    ( UChar szSmall, Bool syned,
                                           AMD64AMode* src, HReg dst );
index e2ebad0bf8602d6fed628a1df48643b89263387c..dbb1cd99b022d8027a5a33ca41ccc0fc4cf77853 100644 (file)
@@ -37,7 +37,7 @@
 #include "libvex_ir.h"
 #include "libvex.h"
 
-//.. #include "ir/irmatch.h"
+#include "ir/irmatch.h"
 #include "main/vex_util.h"
 #include "main/vex_globals.h"
 #include "host-generic/h_generic_regs.h"
 //.. 
 //.. /* debugging only, do not use */
 //.. /* define DEFAULT_FPUCW 0x037F */
-//.. 
-//.. 
-//.. /*---------------------------------------------------------*/
-//.. /*--- misc helpers                                      ---*/
-//.. /*---------------------------------------------------------*/
-//.. 
-//.. /* These are duplicated in guest-x86/toIR.c */
-//.. static IRExpr* unop ( IROp op, IRExpr* a )
-//.. {
-//..    return IRExpr_Unop(op, a);
-//.. }
-//.. 
-//.. static IRExpr* binop ( IROp op, IRExpr* a1, IRExpr* a2 )
-//.. {
-//..    return IRExpr_Binop(op, a1, a2);
-//.. }
-//.. 
+
+
+/*---------------------------------------------------------*/
+/*--- misc helpers                                      ---*/
+/*---------------------------------------------------------*/
+
+/* These are duplicated in guest-amd64/toIR.c */
+static IRExpr* unop ( IROp op, IRExpr* a )
+{
+   return IRExpr_Unop(op, a);
+}
+
+static IRExpr* binop ( IROp op, IRExpr* a1, IRExpr* a2 )
+{
+   return IRExpr_Binop(op, a1, a2);
+}
+
 //.. static IRExpr* mkU64 ( ULong i )
 //.. {
 //..    return IRExpr_Const(IRConst_U64(i));
 //.. {
 //..    return IRExpr_Const(IRConst_U32(i));
 //.. }
-//.. 
-//.. static IRExpr* bind ( Int binder )
-//.. {
-//..    return IRExpr_Binder(binder);
-//.. }
+
+static IRExpr* bind ( Int binder )
+{
+   return IRExpr_Binder(binder);
+}
 
 
 
@@ -344,233 +344,214 @@ static AMD64Instr* mk_iMOVsd_RR ( HReg src, HReg dst )
 //..    ppIRExpr(arg);
 //..    vpanic("pushArg(x86): can't handle arg of this type");
 //.. }
-//.. 
-//.. 
-//.. /* Complete the call to a helper function, by calling the 
-//..    helper and clearing the args off the stack. */
-//.. 
-//.. static 
-//.. void callHelperAndClearArgs ( ISelEnv* env, X86CondCode cc, 
-//..                               IRCallee* cee, Int n_arg_ws )
-//.. {
-//..    /* 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(void*) == 4);
-//.. 
-//..    addInstr(env, X86Instr_Call( cc, (UInt)cee->addr, cee->regparms));
-//..    if (n_arg_ws > 0)
-//..       add_to_esp(env, 4*n_arg_ws);
-//.. }
-//.. 
-//.. 
-//.. /* Used only in doHelperCall.  See big comment in doHelperCall re
-//..    handling of regparm args.  This function figures out whether
-//..    evaluation of an expression might require use of a fixed register.
-//..    If in doubt return True (safe but suboptimal).  
-//.. */
-//.. static
-//.. Bool mightRequireFixedRegs ( IRExpr* e )
-//.. {
-//..    switch (e->tag) {
-//..       case Iex_Tmp: case Iex_Const: case Iex_Get: 
-//..          return False;
-//..       default:
-//..          return True;
-//..    }
-//.. }
-//.. 
-//.. 
-//.. /* Do a complete function call.  guard is a Ity_Bit expression
-//..    indicating whether or not the call happens.  If guard==NULL, the
-//..    call is unconditional. */
-//.. 
-//.. static
-//.. void doHelperCall ( ISelEnv* env, 
-//..                     Bool passBBP, 
-//..                     IRExpr* guard, IRCallee* cee, IRExpr** args )
-//.. {
-//..    X86CondCode cc;
-//..    HReg        argregs[3];
-//..    HReg        tmpregs[3];
-//..    Bool        danger;
-//..    Int         not_done_yet, n_args, n_arg_ws, stack_limit, 
-//..                i, argreg, argregX;
-//.. 
-//..    /* 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.  
-//..    */
-//.. 
-//..    /* 16 Nov 2004: the regparm handling is complicated by the
-//..       following problem.
-//.. 
-//..       Consider a call two a function with two regparm parameters:
-//..       f(e1,e2).  We need to compute e1 into %eax and e2 into %edx.
-//..       Suppose code is first generated to compute e1 into %eax.  Then,
-//..       code is generated to compute e2 into %edx.  Unfortunately, if
-//..       the latter code sequence uses %eax, it will trash the value of
-//..       e1 computed by the former sequence.  This could happen if (for
-//..       example) e2 itself involved a function call.  In the code below,
-//..       args are evaluated right-to-left, not left-to-right, but the
-//..       principle and the problem are the same.
-//.. 
-//..       One solution is to compute all regparm-bound args into vregs
-//..       first, and once they are all done, move them to the relevant
-//..       real regs.  This always gives correct code, but it also gives
-//..       a bunch of vreg-to-rreg moves which are usually redundant but 
-//..       are hard for the register allocator to get rid of.
-//.. 
-//..       A compromise is to first examine all regparm'd argument 
-//..       expressions.  If they are all so simple that it is clear 
-//..       they will be evaluated without use of any fixed registers,
-//..       use the old compute-directly-to-fixed-target scheme.  If not,
-//..       be safe and use the via-vregs scheme.
-//.. 
-//..       Note this requires being able to examine an expression and
-//..       determine whether or not evaluation of it might use a fixed
-//..       register.  That requires knowledge of how the rest of this
-//..       insn selector works.  Currently just the following 3 are 
-//..       regarded as safe -- hopefully they cover the majority of
-//..       arguments in practice: IRExpr_Tmp IRExpr_Const IRExpr_Get.
-//..    */
-//..    vassert(cee->regparms >= 0 && cee->regparms <= 3);
-//.. 
-//..    n_args = n_arg_ws = 0;
-//..    while (args[n_args]) n_args++;
-//.. 
-//..    not_done_yet = n_args;
-//..    if (passBBP)
-//..       not_done_yet++;
-//.. 
-//..    stack_limit = cee->regparms;
-//..    if (cee->regparms > 0 && passBBP) stack_limit--;
-//.. 
-//..    /* ------ BEGIN marshall all arguments ------ */
-//.. 
-//..    /* Push (R to L) the stack-passed args, [n_args-1 .. stack_limit] */
-//..    for (i = n_args-1; i >= stack_limit; i--) {
-//..       n_arg_ws += pushArg(env, args[i]);
-//..       not_done_yet--;
-//..    }
-//.. 
-//..    /* args [stack_limit-1 .. 0] and possibly %ebp are to be passed in
-//..       registers. */
-//.. 
-//..    if (cee->regparms > 0) {
-//.. 
-//..       /* ------ BEGIN deal with regparms ------ */
-//.. 
-//..       /* deal with regparms, not forgetting %ebp if needed. */
-//..       argregs[0] = hregX86_EAX();
-//..       argregs[1] = hregX86_EDX();
-//..       argregs[2] = hregX86_ECX();
-//..       tmpregs[0] = tmpregs[1] = tmpregs[2] = INVALID_HREG;
-//.. 
-//..       argreg = cee->regparms;
-//.. 
-//..       /* In keeping with big comment above, detect potential danger
-//..          and use the via-vregs scheme if needed. */
-//..       danger = False;
-//..       for (i = stack_limit-1; i >= 0; i--) {
-//..          if (mightRequireFixedRegs(args[i])) {
-//..             danger = True;
-//..             break;
-//..          }
-//..       }
-//.. 
-//..       if (danger) {
-//.. 
-//..          /* Move via temporaries */
-//..          argregX = argreg;
-//..          for (i = stack_limit-1; i >= 0; i--) {
-//.. 
-//..             if (0) {
-//..                vex_printf("x86 host: register param is complex: ");
-//..                ppIRExpr(args[i]);
-//..                vex_printf("\n");
-//..             }
-//.. 
-//..             argreg--;
-//..             vassert(argreg >= 0);
-//..             vassert(typeOfIRExpr(env->type_env, args[i]) == Ity_I32);
-//..             tmpregs[argreg] = iselIntExpr_R(env, args[i]);
-//..             not_done_yet--;
-//..          }
-//..          for (i = stack_limit-1; i >= 0; i--) {
-//..             argregX--;
-//..             vassert(argregX >= 0);
-//..             addInstr( env, mk_iMOVsd_RR( tmpregs[argregX], argregs[argregX] ) );
-//..          }
-//.. 
-//..       } else {
-//..          /* It's safe to compute all regparm args directly into their
-//..             target registers. */
-//..          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]));
-//..             not_done_yet--;
-//..          }
-//.. 
-//..       }
-//.. 
-//..       /* Not forgetting %ebp if needed. */
-//..       if (passBBP) {
-//..          vassert(argreg == 1);
-//..          addInstr(env, mk_iMOVsd_RR( hregX86_EBP(), argregs[0]));
-//..          not_done_yet--;
-//..       }
-//.. 
-//..       /* ------ END deal with regparms ------ */
-//.. 
-//..    } else {
-//.. 
-//..       /* No regparms.  Heave %ebp on the stack if needed. */
-//..       if (passBBP) {
-//..          addInstr(env, X86Instr_Push(X86RMI_Reg(hregX86_EBP())));
-//..          n_arg_ws++;
-//..          not_done_yet--;
-//..       }
-//.. 
-//..    }
-//.. 
-//..    vassert(not_done_yet == 0);
-//.. 
-//..    /* ------ END marshall all arguments ------ */
-//.. 
-//..    /* Now we can compute the condition.  We can't do it earlier
-//..       because the argument computations could trash the condition
-//..       codes.  Be a bit clever to handle the common case where the
-//..       guard is 1:Bit. */
-//..    cc = Xcc_ALWAYS;
-//..    if (guard) {
-//..       if (guard->tag == Iex_Const 
-//..           && guard->Iex.Const.con->tag == Ico_U1
-//..           && guard->Iex.Const.con->Ico.U1 == True) {
-//..          /* unconditional -- do nothing */
-//..       } else {
-//..          cc = iselCondCode( env, guard );
-//..       }
-//..    }
-//.. 
-//..    /* call the helper, and get the args off the stack afterwards. */
-//..    callHelperAndClearArgs( env, cc, cee, n_arg_ws );
-//.. }
-//.. 
-//.. 
+
+
+/* Used only in doHelperCall.  See big comment in doHelperCall re
+   handling of register-parameter args.  This function figures out
+   whether evaluation of an expression might require use of a fixed
+   register.  If in doubt return True (safe but suboptimal).
+*/
+static
+Bool mightRequireFixedRegs ( IRExpr* e )
+{
+   switch (e->tag) {
+      case Iex_Tmp: case Iex_Const: case Iex_Get: 
+         return False;
+      default:
+         return True;
+   }
+}
+
+
+/* Do a complete function call.  guard is a Ity_Bit expression
+   indicating whether or not the call happens.  If guard==NULL, the
+   call is unconditional. */
+
+static
+void doHelperCall ( ISelEnv* env, 
+                    Bool passBBP, 
+                    IRExpr* guard, IRCallee* cee, IRExpr** args )
+{
+   AMD64CondCode cc;
+   HReg          argregs[6];
+   HReg          tmpregs[6];
+   Bool          go_fast;
+   Int           n_args, i, argreg;
+
+   /* Marshal args for a call and do the call.
+
+      If passBBP is True, %rbp (the baseblock pointer) is to be passed
+      as the first arg.
+
+      This function only deals with a tiny set of possibilities, which
+      cover all helpers in practice.  The restrictions are that only
+      arguments in registers are supported, hence only 6x64 integer
+      bits in total can be passed.  In fact the only supported arg
+      type is I64.
+
+      Generating code which is both efficient and correct when
+      parameters are to be passed in registers is difficult, for the
+      reasons elaborated in detail in comments attached to
+      doHelperCall() in priv/host-x86/isel.c.  Here, we use a variant
+      of the method described in those comments.
+
+      The problem is split into two cases: the fast scheme and the
+      slow scheme.  In the fast scheme, arguments are computed
+      directly into the target (real) registers.  This is only safe
+      when we can be sure that computation of each argument will not
+      trash any real registers set by computation of any other
+      argument.
+
+      In the slow scheme, all args are first computed into vregs, and
+      once they are all done, they are moved to the relevant real
+      regs.  This always gives correct code, but it also gives a bunch
+      of vreg-to-rreg moves which are usually redundant but are hard
+      for the register allocator to get rid of.
+
+      To decide which scheme to use, all argument expressions are
+      first examined.  If they are all so simple that it is clear they
+      will be evaluated without use of any fixed registers, use the
+      fast scheme, else use the slow scheme.  Note also that only
+      unconditional calls may use the fast scheme, since having to
+      compute a condition expression could itself trash real
+      registers.
+
+      Note this requires being able to examine an expression and
+      determine whether or not evaluation of it might use a fixed
+      register.  That requires knowledge of how the rest of this insn
+      selector works.  Currently just the following 3 are regarded as
+      safe -- hopefully they cover the majority of arguments in
+      practice: IRExpr_Tmp IRExpr_Const IRExpr_Get.
+   */
+
+   /* Note that the cee->regparms field is meaningless on AMD64 host
+      (since there is only one calling convention) and so we always
+      ignore it. */
+
+   n_args = 0;
+   for (i = 0; args[i]; i++)
+      n_args++;
+
+   if (6 < n_args + (passBBP ? 1 : 0))
+      vpanic("doHelperCall(AMD64): cannot currently handle > 6 args");
+
+   argregs[0] = hregAMD64_RDI();
+   argregs[1] = hregAMD64_RSI();
+   argregs[2] = hregAMD64_RDX();
+   argregs[3] = hregAMD64_RCX();
+   argregs[4] = hregAMD64_R8();
+   argregs[5] = hregAMD64_R9();
+
+   tmpregs[0] = tmpregs[1] = tmpregs[2] =
+   tmpregs[3] = tmpregs[4] = tmpregs[5] = INVALID_HREG;
+
+   /* First decide which scheme (slow or fast) is to be used.  First
+      assume the fast scheme, and select slow if any contraindications
+      (wow) appear. */
+
+   go_fast = True;
+
+   if (guard) {
+      if (guard->tag == Iex_Const 
+          && guard->Iex.Const.con->tag == Ico_U1
+          && guard->Iex.Const.con->Ico.U1 == True) {
+         /* unconditional */
+      } else {
+         /* Not manifestly unconditional -- be conservative. */
+         go_fast = False;
+      }
+   }
+
+   if (go_fast) {
+      for (i = 0; i < n_args; i++) {
+         if (mightRequireFixedRegs(args[i])) {
+            go_fast = False;
+            break;
+         }
+      }
+   }
+
+   /* At this point the scheme to use has been established.  Generate
+      code to get the arg values into the argument rregs. */
+
+   if (go_fast) {
+
+      /* FAST SCHEME */
+      argreg = 0;
+      if (passBBP) {
+         addInstr(env, mk_iMOVsd_RR( hregAMD64_RBP(), argregs[argreg]));
+         argreg++;
+      }
+
+      for (i = 0; i < n_args; i++) {
+         vassert(argreg < 6);
+         vassert(typeOfIRExpr(env->type_env, args[i]) == Ity_I64);
+         addInstr(env, AMD64Instr_Alu64R(
+                          Aalu_MOV, 
+                          iselIntExpr_RMI(env, args[i]),
+                          argregs[argreg]
+                       )
+                 );
+         argreg++;
+      }
+
+      /* Fast scheme only applies for unconditional calls.  Hence: */
+      cc = Acc_ALWAYS;
+
+   } else {
+
+      /* SLOW SCHEME; move via temporaries */
+      argreg = 0;
+
+      if (passBBP) {
+         /* This is pretty stupid; better to move directly to rdi
+            after the rest of the args are done. */
+         tmpregs[argreg] = newVRegI(env);
+         addInstr(env, mk_iMOVsd_RR( hregAMD64_RBP(), tmpregs[argreg]));
+         argreg++;
+      }
+
+      for (i = 0; i < n_args; i++) {
+         vassert(argreg < 6);
+         vassert(typeOfIRExpr(env->type_env, args[i]) == Ity_I64);
+         tmpregs[argreg] = iselIntExpr_R(env, args[i]);
+         argreg++;
+      }
+
+      /* Now we can compute the condition.  We can't do it earlier
+         because the argument computations could trash the condition
+         codes.  Be a bit clever to handle the common case where the
+         guard is 1:Bit. */
+      cc = Acc_ALWAYS;
+      if (guard) {
+         if (guard->tag == Iex_Const 
+             && guard->Iex.Const.con->tag == Ico_U1
+             && guard->Iex.Const.con->Ico.U1 == True) {
+            /* unconditional -- do nothing */
+         } else {
+            cc = iselCondCode( env, guard );
+         }
+      }
+
+      /* Move the args to their final destinations. */
+      for (i = 0; i < argreg; i++) {
+         /* None of these insns, including any spill code that might
+            be generated, may alter the condition codes. */
+         addInstr( env, mk_iMOVsd_RR( tmpregs[i], argregs[i] ) );
+      }
+
+   }
+
+   /* Finally, the call itself. */
+   addInstr(env, AMD64Instr_Call( 
+                    cc, 
+                    (ULong)cee->addr, 
+                    n_args + (passBBP ? 1 : 0) 
+                 )
+   );
+}
+
+
 //.. /* Given a guest-state array descriptor, an index expression and a
 //..    bias, generate an X86AMode holding the relevant guest state
 //..    offset. */
@@ -728,7 +709,9 @@ static HReg iselIntExpr_R ( ISelEnv* env, IRExpr* e )
 /* DO NOT CALL THIS DIRECTLY ! */
 static HReg iselIntExpr_R_wrk ( ISelEnv* env, IRExpr* e )
 {
-//..    MatchInfo mi;
+   MatchInfo mi;
+   DECLARE_PATTERN(p_16Uto64);
+   DECLARE_PATTERN(p_1Uto8_32to1_64to32);
 //..    DECLARE_PATTERN(p_32to1_then_1Uto8);
 
    IRType ty = typeOfIRExpr(env->type_env,e);
@@ -754,10 +737,10 @@ static HReg iselIntExpr_R_wrk ( ISelEnv* env, IRExpr* e )
          addInstr(env, AMD64Instr_LoadEX(4,False,amode,dst));
          return dst;
       }
-//..       if (ty == Ity_I16) {
-//..          addInstr(env, X86Instr_LoadEX(2,False,amode,dst));
-//..          return dst;
-//..       }
+      if (ty == Ity_I16) {
+         addInstr(env, AMD64Instr_LoadEX(2,False,amode,dst));
+         return dst;
+      }
 //..       if (ty == Ity_I8) {
 //..          addInstr(env, X86Instr_LoadEX(1,False,amode,dst));
 //..          return dst;
@@ -783,10 +766,10 @@ static HReg iselIntExpr_R_wrk ( ISelEnv* env, IRExpr* e )
       switch (e->Iex.Binop.op) {
          case Iop_Add8: case Iop_Add16: case Iop_Add32: case Iop_Add64: 
             aluOp = Aalu_ADD; break;
-//..          case Iop_Sub8: case Iop_Sub16: case Iop_Sub32: 
-//..             aluOp = Xalu_SUB; break;
-//..          case Iop_And8: case Iop_And16: case Iop_And32
-//..             aluOp = Xalu_AND; break;
+         case Iop_Sub8: case Iop_Sub16: case Iop_Sub32: case Iop_Sub64:
+            aluOp = Aalu_SUB; break;
+         case Iop_And8: case Iop_And16: case Iop_And32: case Iop_And64
+            aluOp = Aalu_AND; break;
 //..          case Iop_Or8: case Iop_Or16: case Iop_Or32:  
 //..             aluOp = Xalu_OR; break;
 //..          case Iop_Xor8: case Iop_Xor16: case Iop_Xor32: 
@@ -813,8 +796,8 @@ static HReg iselIntExpr_R_wrk ( ISelEnv* env, IRExpr* e )
             shOp = Ash_SHL; break;
 //..          case Iop_Shr32: case Iop_Shr16: case Iop_Shr8: 
 //..             shOp = Xsh_SHR; break;
-//..          case Iop_Sar32: case Iop_Sar16: case Iop_Sar8: 
-//..             shOp = Xsh_SAR; break;
+         case Iop_Sar64: case Iop_Sar32: case Iop_Sar16: case Iop_Sar8: 
+            shOp = Ash_SAR; break;
          default:
             shOp = Ash_INVALID; break;
       }
@@ -827,8 +810,8 @@ static HReg iselIntExpr_R_wrk ( ISelEnv* env, IRExpr* e )
 
          /* Do any necessary widening for 32/16/8 bit operands */
          switch (e->Iex.Binop.op) {
-            case Iop_Shr64: case Iop_Shl64: case Iop_Sar64: break;
-            default: vassert(0);
+            case Iop_Shr64: case Iop_Shl64: case Iop_Sar64: 
+               break;
 //..             case Iop_Shr8:
 //..                addInstr(env, X86Instr_Alu32R(
 //..                                 Xalu_AND, X86RMI_Imm(0xFF), dst));
@@ -845,7 +828,12 @@ static HReg iselIntExpr_R_wrk ( ISelEnv* env, IRExpr* e )
 //..                addInstr(env, X86Instr_Sh32(Xsh_SHL, 16, X86RM_Reg(dst)));
 //..                addInstr(env, X86Instr_Sh32(Xsh_SAR, 16, X86RM_Reg(dst)));
 //..                break;
-//..             default: break;
+            case Iop_Sar32:
+               addInstr(env, AMD64Instr_Sh64(Ash_SHL, 32, AMD64RM_Reg(dst)));
+               addInstr(env, AMD64Instr_Sh64(Ash_SAR, 32, AMD64RM_Reg(dst)));
+               break;
+            default: 
+               vassert(0);
          }
 
          /* Now consider the shift amount.  If it's a literal, we
@@ -999,19 +987,33 @@ static HReg iselIntExpr_R_wrk ( ISelEnv* env, IRExpr* e )
 
    /* --------- UNARY OP --------- */
    case Iex_Unop: {
-//..       /* 1Uto8(32to1(expr32)) */
-//..       DEFINE_PATTERN(p_32to1_then_1Uto8,
-//..                      unop(Iop_1Uto8,unop(Iop_32to1,bind(0))));
-//..       if (matchIRExpr(&mi,p_32to1_then_1Uto8,e)) {
-//..          IRExpr* expr32 = mi.bindee[0];
-//..          HReg dst = newVRegI(env);
-//..          HReg src = iselIntExpr_R(env, expr32);
-//..          addInstr(env, mk_iMOVsd_RR(src,dst) );
-//..          addInstr(env, X86Instr_Alu32R(Xalu_AND,
-//..                                        X86RMI_Imm(1), dst));
-//..          return dst;
-//..       }
-//.. 
+      /* 32Uto64(16Uto32(expr16)) */
+      DEFINE_PATTERN(p_16Uto64,
+                     unop(Iop_32Uto64, unop(Iop_16Uto32, bind(0)) ) );
+      if (matchIRExpr(&mi,p_16Uto64,e)) {
+         IRExpr* expr16 = mi.bindee[0];
+         HReg dst = newVRegI(env);
+         HReg src = iselIntExpr_R(env, expr16);
+         addInstr(env, mk_iMOVsd_RR(src,dst) );
+         addInstr(env, AMD64Instr_Sh64(Ash_SHL, 48, AMD64RM_Reg(dst)));
+         addInstr(env, AMD64Instr_Sh64(Ash_SHR, 48, AMD64RM_Reg(dst)));
+         return dst;
+      }
+
+      /* 1Uto8(32to1(64to32(expr64))) */
+      DEFINE_PATTERN(p_1Uto8_32to1_64to32,
+                     unop(Iop_1Uto8, 
+                          unop(Iop_32to1, unop(Iop_64to32, bind(0)))));
+      if (matchIRExpr(&mi,p_1Uto8_32to1_64to32,e)) {
+         IRExpr* expr64 = mi.bindee[0];
+         HReg    dst    = newVRegI(env);
+         HReg    src    = iselIntExpr_R(env, expr64);
+         addInstr(env, mk_iMOVsd_RR(src,dst) );
+         addInstr(env, AMD64Instr_Alu64R(Aalu_AND,
+                                         AMD64RMI_Imm(1), dst));
+         return dst;
+      }
+
 //..       /* 16Uto32(LDle(expr32)) */
 //..       {
 //..          DECLARE_PATTERN(p_LDle16_then_16Uto32);
@@ -1032,6 +1034,15 @@ static HReg iselIntExpr_R_wrk ( ISelEnv* env, IRExpr* e )
             addInstr(env, AMD64Instr_MovZLQ(src,dst) );
             return dst;
          }
+         case Iop_32Sto64: {
+            HReg dst = newVRegI(env);
+            HReg src = iselIntExpr_R(env, e->Iex.Unop.arg);
+            UInt amt = 32;
+            addInstr(env, mk_iMOVsd_RR(src,dst) );
+            addInstr(env, AMD64Instr_Sh64(Ash_SHL, amt, AMD64RM_Reg(dst)));
+            addInstr(env, AMD64Instr_Sh64(Ash_SAR, amt, AMD64RM_Reg(dst)));
+            return dst;
+         }
 //..          case Iop_8Uto16:
 //..          case Iop_8Uto32:
 //..          case Iop_16Uto32: {
@@ -1181,24 +1192,24 @@ static HReg iselIntExpr_R_wrk ( ISelEnv* env, IRExpr* e )
 //..       }
 //..       break;
 //..    }
-//.. 
-//..    /* --------- CCALL --------- */
-//..    case Iex_CCall: {
-//..       HReg    dst = newVRegI(env);
-//..       vassert(ty == Ity_I32);
-//.. 
-//..       /* be very restrictive for now.  Only 32/64-bit ints allowed
-//..          for args, and 32 bits for return type. */
-//..       if (e->Iex.CCall.retty != Ity_I32)
-//..          goto irreducible;
-//.. 
-//..       /* Marshal args, do the call, clear stack. */
-//..       doHelperCall( env, False, NULL, e->Iex.CCall.cee, e->Iex.CCall.args );
-//.. 
-//..       addInstr(env, mk_iMOVsd_RR(hregX86_EAX(), dst));
-//..       return dst;
-//..    }
-//.. 
+
+   /* --------- CCALL --------- */
+   case Iex_CCall: {
+      HReg    dst = newVRegI(env);
+      vassert(ty == Ity_I64);
+
+      /* be very restrictive for now.  Only 64-bit ints allowed
+         for args, and 64 bits for return type. */
+      if (e->Iex.CCall.retty != Ity_I64)
+         goto irreducible;
+
+      /* Marshal args, do the call, clear stack. */
+      doHelperCall( env, False, NULL, e->Iex.CCall.cee, e->Iex.CCall.args );
+
+      addInstr(env, mk_iMOVsd_RR(hregAMD64_RAX(), dst));
+      return dst;
+   }
+
 //..    /* --------- LITERAL --------- */
 //..    /* 32/16/8-bit literals */
 //..    case Iex_Const: {
@@ -1207,23 +1218,23 @@ static HReg iselIntExpr_R_wrk ( ISelEnv* env, IRExpr* e )
 //..       addInstr(env, X86Instr_Alu32R(Xalu_MOV, rmi, r));
 //..       return r;
 //..    }
-//.. 
-//..    /* --------- MULTIPLEX --------- */
-//..    case Iex_Mux0X: {
-//..      if ((ty == Ity_I32 || ty == Ity_I16 || ty == Ity_I8)
-//..          && typeOfIRExpr(env->type_env,e->Iex.Mux0X.cond) == Ity_I8) {
-//..         HReg r8;
-//..         HReg rX   = iselIntExpr_R(env, e->Iex.Mux0X.exprX);
-//..         X86RM* r0 = iselIntExpr_RM(env, e->Iex.Mux0X.expr0);
-//..         HReg dst = newVRegI(env);
-//..         addInstr(env, mk_iMOVsd_RR(rX,dst));
-//..         r8 = iselIntExpr_R(env, e->Iex.Mux0X.cond);
-//..         addInstr(env, X86Instr_Test32(X86RI_Imm(0xFF), X86RM_Reg(r8)));
-//..         addInstr(env, X86Instr_CMov32(Xcc_Z,r0,dst));
-//..         return dst;
-//..       }
-//..       break;
-//..    }
+
+   /* --------- MULTIPLEX --------- */
+   case Iex_Mux0X: {
+     if ((ty == Ity_I64 || ty == Ity_I32 || ty == Ity_I16 || ty == Ity_I8)
+         && typeOfIRExpr(env->type_env,e->Iex.Mux0X.cond) == Ity_I8) {
+        HReg     r8;
+        HReg     rX  = iselIntExpr_R(env, e->Iex.Mux0X.exprX);
+        AMD64RM* r0  = iselIntExpr_RM(env, e->Iex.Mux0X.expr0);
+        HReg dst = newVRegI(env);
+        addInstr(env, mk_iMOVsd_RR(rX,dst));
+        r8 = iselIntExpr_R(env, e->Iex.Mux0X.cond);
+        addInstr(env, AMD64Instr_Test64(AMD64RI_Imm(0xFF), AMD64RM_Reg(r8)));
+        addInstr(env, AMD64Instr_CMov64(Acc_Z,r0,dst));
+        return dst;
+      }
+      break;
+   }
 
    default: 
    break;
@@ -1257,9 +1268,43 @@ static AMD64AMode* iselIntExpr_AMode ( ISelEnv* env, IRExpr* e )
 /* DO NOT CALL THIS DIRECTLY ! */
 static AMD64AMode* iselIntExpr_AMode_wrk ( ISelEnv* env, IRExpr* e )
 {
+   MatchInfo mi;
+   DECLARE_PATTERN(p_complex);
    IRType ty = typeOfIRExpr(env->type_env,e);
    vassert(ty == Ity_I64);
 
+   /* Add64( Add64(expr1, Shl64(expr2, imm8)), simm32 ) */
+   /*              bind0        bind1  bind2   bind3   */
+   DEFINE_PATTERN(p_complex,
+      binop( Iop_Add64,
+             binop( Iop_Add64, 
+                    bind(0), 
+                    binop(Iop_Shl64, bind(1), bind(2))
+                  ),
+             bind(3)
+           )
+   );
+   if (matchIRExpr(&mi, p_complex, e)) {
+      IRExpr* expr1  = mi.bindee[0];
+      IRExpr* expr2  = mi.bindee[1];
+      IRExpr* imm8   = mi.bindee[2];
+      IRExpr* simm32 = mi.bindee[3];
+      if (imm8->tag == Iex_Const 
+          && imm8->Iex.Const.con->tag == Ico_U8
+          && imm8->Iex.Const.con->Ico.U8 < 4
+          /* imm8 is OK, now check simm32 */
+          && simm32->tag == Iex_Const
+          && simm32->Iex.Const.con->tag == Ico_U64
+          && fitsIn32Bits(simm32->Iex.Const.con->Ico.U64)) {
+         UInt shift = imm8->Iex.Const.con->Ico.U8;
+         UInt offset = (UInt)(0xFFFFFFFF & simm32->Iex.Const.con->Ico.U64);
+         HReg r1 = iselIntExpr_R(env, expr1);
+         HReg r2 = iselIntExpr_R(env, expr2);
+         vassert(shift == 0 || shift == 1 || shift == 2 || shift == 3);
+         return AMD64AMode_IRRS(offset, r1, r2, shift);
+      }
+   }
+
    /* Add64(expr1, Shl64(expr2, imm)) */
    if (e->tag == Iex_Binop
        && e->Iex.Binop.op == Iop_Add64
@@ -1419,73 +1464,74 @@ static AMD64RI* iselIntExpr_RI_wrk ( ISelEnv* env, IRExpr* e )
 }
 
 
-//.. /* --------------------- RMs --------------------- */
-//.. 
-//.. /* Similarly, calculate an expression into an X86RM operand.  As with
-//..    iselIntExpr_R, the expression can have type 32, 16 or 8 bits.  */
-//.. 
-//.. static X86RM* iselIntExpr_RM ( ISelEnv* env, IRExpr* e )
-//.. {
-//..    X86RM* rm = iselIntExpr_RM_wrk(env, e);
-//..    /* sanity checks ... */
-//..    switch (rm->tag) {
-//..       case Xrm_Reg:
-//..          vassert(hregClass(rm->Xrm.Reg.reg) == HRcInt32);
-//..          vassert(hregIsVirtual(rm->Xrm.Reg.reg));
-//..          return rm;
-//..       case Xrm_Mem:
-//..          vassert(sane_AMode(rm->Xrm.Mem.am));
-//..          return rm;
-//..       default:
-//..          vpanic("iselIntExpr_RM: unknown x86 RM tag");
-//..    }
-//.. }
-//.. 
-//.. /* DO NOT CALL THIS DIRECTLY ! */
-//.. static X86RM* iselIntExpr_RM_wrk ( ISelEnv* env, IRExpr* e )
-//.. {
-//..    IRType ty = typeOfIRExpr(env->type_env,e);
-//..    vassert(ty == Ity_I32 || ty == Ity_I16 || ty == Ity_I8);
-//.. 
-//..    /* special case: 32-bit GET */
-//..    if (e->tag == Iex_Get && ty == Ity_I32) {
-//..       return X86RM_Mem(X86AMode_IR(e->Iex.Get.offset,
-//..                                    hregX86_EBP()));
-//..    }
-//.. 
-//..    /* special case: load from memory */
-//.. 
-//..    /* default case: calculate into a register and return that */
-//..    {
-//..       HReg r = iselIntExpr_R ( env, e );
-//..       return X86RM_Reg(r);
-//..    }
-//.. }
-//.. 
-//.. 
-//.. /* --------------------- CONDCODE --------------------- */
-//.. 
-//.. /* Generate code to evaluated a bit-typed expression, returning the
-//..    condition code which would correspond when the expression would
-//..    notionally have returned 1. */
-//.. 
-//.. static X86CondCode iselCondCode ( ISelEnv* env, IRExpr* e )
-//.. {
-//..    /* Uh, there's nothing we can sanity check here, unfortunately. */
-//..    return iselCondCode_wrk(env,e);
-//.. }
-//.. 
-//.. /* DO NOT CALL THIS DIRECTLY ! */
-//.. static X86CondCode iselCondCode_wrk ( ISelEnv* env, IRExpr* e )
-//.. {
+/* --------------------- RMs --------------------- */
+
+/* Similarly, calculate an expression into an AMD64RM operand.  As
+   with iselIntExpr_R, the expression can have type 64, 32, 16 or 8
+   bits.  */
+
+static AMD64RM* iselIntExpr_RM ( ISelEnv* env, IRExpr* e )
+{
+   AMD64RM* rm = iselIntExpr_RM_wrk(env, e);
+   /* sanity checks ... */
+   switch (rm->tag) {
+      case Arm_Reg:
+         vassert(hregClass(rm->Arm.Reg.reg) == HRcInt64);
+         vassert(hregIsVirtual(rm->Arm.Reg.reg));
+         return rm;
+      case Arm_Mem:
+         vassert(sane_AMode(rm->Arm.Mem.am));
+         return rm;
+      default:
+         vpanic("iselIntExpr_RM: unknown amd64 RM tag");
+   }
+}
+
+/* DO NOT CALL THIS DIRECTLY ! */
+static AMD64RM* iselIntExpr_RM_wrk ( ISelEnv* env, IRExpr* e )
+{
+   IRType ty = typeOfIRExpr(env->type_env,e);
+   vassert(ty == Ity_I64 || ty == Ity_I32 || ty == Ity_I16 || ty == Ity_I8);
+
+   /* special case: 64-bit GET */
+   if (e->tag == Iex_Get && ty == Ity_I64) {
+      return AMD64RM_Mem(AMD64AMode_IR(e->Iex.Get.offset,
+                                       hregAMD64_RBP()));
+   }
+
+   /* special case: load from memory */
+
+   /* default case: calculate into a register and return that */
+   {
+      HReg r = iselIntExpr_R ( env, e );
+      return AMD64RM_Reg(r);
+   }
+}
+
+
+/* --------------------- CONDCODE --------------------- */
+
+/* Generate code to evaluated a bit-typed expression, returning the
+   condition code which would correspond when the expression would
+   notionally have returned 1. */
+
+static AMD64CondCode iselCondCode ( ISelEnv* env, IRExpr* e )
+{
+   /* Uh, there's nothing we can sanity check here, unfortunately. */
+   return iselCondCode_wrk(env,e);
+}
+
+/* DO NOT CALL THIS DIRECTLY ! */
+static AMD64CondCode iselCondCode_wrk ( ISelEnv* env, IRExpr* e )
+{
 //..    MatchInfo mi;
 //..    DECLARE_PATTERN(p_32to1);
 //..    DECLARE_PATTERN(p_1Uto32_then_32to1);
 //..    DECLARE_PATTERN(p_1Sto32_then_32to1);
-//.. 
-//..    vassert(e);
-//..    vassert(typeOfIRExpr(env->type_env,e) == Ity_I1);
-//.. 
+
+   vassert(e);
+   vassert(typeOfIRExpr(env->type_env,e) == Ity_I1);
+
 //..    /* Constant 1:Bit */
 //..    if (e->tag == Iex_Const && e->Iex.Const.con->Ico.U1 == True) {
 //..       HReg r;
@@ -1650,12 +1696,12 @@ static AMD64RI* iselIntExpr_RI_wrk ( ISelEnv* env, IRExpr* e )
 //..       addInstr(env, X86Instr_Alu32R(Xalu_AND,X86RMI_Imm(1),dst));
 //..       return Xcc_NZ;
 //..    }
-//.. 
-//..    ppIRExpr(e);
-//..    vpanic("iselCondCode");
-//.. }
-//.. 
-//.. 
+
+   ppIRExpr(e);
+   vpanic("iselCondCode(amd64)");
+}
+
+
 //.. /*---------------------------------------------------------*/
 //.. /*--- ISEL: Integer expressions (64 bit)                ---*/
 //.. /*---------------------------------------------------------*/
@@ -3159,24 +3205,24 @@ static void iselStmt ( ISelEnv* env, IRStmt* stmt )
 
    switch (stmt->tag) {
 
-//..    /* --------- STORE --------- */
-//..    case Ist_STle: {
-//..       X86AMode* am;
-//..       IRType tya = typeOfIRExpr(env->type_env, stmt->Ist.STle.addr);
-//..       IRType tyd = typeOfIRExpr(env->type_env, stmt->Ist.STle.data);
-//..       vassert(tya == Ity_I32);
-//..       am = iselIntExpr_AMode(env, stmt->Ist.STle.addr);
+   /* --------- STORE --------- */
+   case Ist_STle: {
+      AMD64AMode* am;
+      IRType tya = typeOfIRExpr(env->type_env, stmt->Ist.STle.addr);
+      IRType tyd = typeOfIRExpr(env->type_env, stmt->Ist.STle.data);
+      vassert(tya == Ity_I64);
+      am = iselIntExpr_AMode(env, stmt->Ist.STle.addr);
 //..       if (tyd == Ity_I32) {
 //..          X86RI* ri = iselIntExpr_RI(env, stmt->Ist.STle.data);
 //..          addInstr(env, X86Instr_Alu32M(Xalu_MOV,ri,am));
 //..          return;
 //..       }
-//..       if (tyd == Ity_I8 || tyd == Ity_I16) {
-//..          HReg r = iselIntExpr_R(env, stmt->Ist.STle.data);
-//..          addInstr(env, X86Instr_Store(tyd==Ity_I8 ? 1 : 2,
-//..                                       r,am));
-//..          return;
-//..       }
+      if (tyd == Ity_I8 || tyd == Ity_I16 || tyd == Ity_I32) {
+         HReg r = iselIntExpr_R(env, stmt->Ist.STle.data);
+         addInstr(env, AMD64Instr_Store(tyd==Ity_I8 ? 1 : (tyd==Ity_I16 ? 2 : 4),
+                                        r,am));
+         return;
+      }
 //..       if (tyd == Ity_F64) {
 //..          HReg r = iselDblExpr(env, stmt->Ist.STle.data);
 //..          addInstr(env, X86Instr_FpLdSt(False/*store*/, 8, r, am));
@@ -3203,7 +3249,7 @@ static void iselStmt ( ISelEnv* env, IRStmt* stmt )
 //..          return;
 //..       }
 //..       break;
-//..    }
+   }
 
    /* --------- PUT --------- */
    case Ist_Put: {
index 9ec7595c0c848a1815970ec1185a892bc0c7b90a..e41c9c4306906eb5c236982635593e30539cce0e 100644 (file)
@@ -144,7 +144,7 @@ typedef
    This can get quite large, but we don't expect to allocate them
    dynamically, so there's no problem. 
 */
-#define N_HREG_USAGE 4
+#define N_HREG_USAGE 9
 
 typedef
    struct {