From 156ab0e2f784f46b1415ad44a8abd549de9035a2 Mon Sep 17 00:00:00 2001
From: Per Hedbor <ph@opera.com>
Date: Sun, 31 Aug 2014 12:14:25 +0200
Subject: [PATCH] Added a few more opcodes

F_NEGATE F_LSH F_AND_INT F_OR_INT F_RSH_INT F_SUBTRACT_INT
---
 src/code/amd64.c | 201 +++++++++++++++++++++++++++++++++++++++++++----
 1 file changed, 184 insertions(+), 17 deletions(-)

diff --git a/src/code/amd64.c b/src/code/amd64.c
index 421e199ca7..b6ca76518b 100644
--- a/src/code/amd64.c
+++ b/src/code/amd64.c
@@ -265,7 +265,32 @@ static void or_reg_reg( enum amd64_reg reg1,  enum amd64_reg reg2 )
   modrm(3,reg1,reg2);
 }
 
-static void and_reg_imm( enum amd64_reg reg, int imm32 )
+static void or_reg_imm( enum amd64_reg reg, INT_TYPE imm32 )
+{
+  rex( 1, 0, 0, reg );
+  if( imm32 < -0x80 || imm32 > 0x7f )
+  {
+    if( reg == P_REG_RAX )
+    {
+      opcode( 0xd ); /* OR rax,imm32 */
+      id( imm32 );
+    }
+    else
+    {
+      opcode( 0x81 ); /* OR REG,imm32 */
+      modrm( 3, 1, reg);
+      id( imm32 );
+    }
+  }
+  else
+  {
+    add_to_program(0x83); /* OR REG,imm8 */
+    modrm( 3, 1, reg );
+    ib( imm32 );
+  }
+}
+
+static void and_reg_imm( enum amd64_reg reg, INT_TYPE imm32 )
 {
   rex( 1, 0, 0, reg );
 
@@ -369,7 +394,6 @@ static void shl_reg_imm( enum amd64_reg from_reg, int shift )
   }
 }
 
-#if 0
 static void shl_reg_reg( enum amd64_reg reg, enum amd64_reg sreg)
 {
   if( sreg != P_REG_RCX )
@@ -379,7 +403,6 @@ static void shl_reg_reg( enum amd64_reg reg, enum amd64_reg sreg)
   opcode( 0xd3 );
   modrm( 3, 4, reg );
 }
-#endif
 
 static void shl_reg32_reg( enum amd64_reg reg, enum amd64_reg sreg)
 {
@@ -390,16 +413,6 @@ static void shl_reg32_reg( enum amd64_reg reg, enum amd64_reg sreg)
   modrm( 3, 4, reg );
 }
 
-#if 0
-static void shl_reg_mem( enum amd64_reg reg, enum amd64_reg mem, int offset)
-{
-  if( reg == P_REG_RCX )
-    Pike_fatal("Not supported\n");
-  mov_mem8_reg( mem, offset, P_REG_RCX );
-  shl_reg_reg( reg, P_REG_RCX );
-}
-#endif
-
 static void shr_mem_reg( enum amd64_reg reg, int off, enum amd64_reg sreg)
 {
   if( sreg != P_REG_RCX )
@@ -411,6 +424,18 @@ static void shr_mem_reg( enum amd64_reg reg, int off, enum amd64_reg sreg)
 /*   modrm( 3, 7, reg ); */
 }
 
+
+static void shr_reg_reg( enum amd64_reg reg, enum amd64_reg reg_rcx )
+{
+  if( reg_rcx != P_REG_RCX )
+    Pike_fatal("Not supported\n");
+
+  rex( 1, 0, 0, reg );
+  opcode( 0xd3 ); /* SAR r/m64,CL */
+  modrm( 3, 7, reg );
+}
+
+
 static void shr_reg_imm( enum amd64_reg from_reg, int shift )
 {
   rex( 1, from_reg, 0, 0 );
@@ -553,6 +578,13 @@ static void mov_imm_mem32( int imm, enum amd64_reg to_reg, ptrdiff_t offset )
 
 static void sub_reg_imm( enum amd64_reg reg, int imm32 );
 
+static void neg_mem( enum amd64_reg reg, int off )
+{
+  rex( 1, 0, 0, reg );
+  opcode(0xf7);
+  offset_modrm_sib( off, 3, reg );
+}
+
 static void add_reg_imm( enum amd64_reg reg, int imm32 )
 {
   if( !imm32 ) return;
@@ -738,7 +770,7 @@ static void cmp_reg32_imm( enum amd64_reg reg, int imm32 )
 {
   if(!imm32)
   {
-   test_reg( reg );
+   test_reg32( reg );
    return;
   }
   rex(0, 0, 0, reg);
@@ -1813,6 +1845,27 @@ void ins_f_byte(unsigned int b)
    }
    return;
 
+  case F_NEGATE:
+    {
+    LABELS();
+    ins_debug_instr_prologue(b, 0, 0);
+    amd64_load_sp_reg();
+    mov_mem8_reg(sp_reg, SVAL(-1).type, P_REG_RAX );
+    test_reg32(P_REG_RAX);
+    jz(&label_B);
+   LABEL_D;
+    neg_mem(sp_reg, SVAL(-1).value );
+   LABEL_A;
+    amd64_call_c_opcode(addr, flags);
+    amd64_load_sp_reg();
+    jmp(&label_C);
+   LABEL_B;
+     neg_mem(sp_reg, SVAL(-1).value );
+     jo(&label_D);
+   LABEL_C;
+    }
+    return;
+
   case F_AND:
     {
     LABELS();
@@ -1821,7 +1874,7 @@ void ins_f_byte(unsigned int b)
     mov_mem8_reg(sp_reg, SVAL(-1).type, P_REG_RAX );
     mov_mem8_reg(sp_reg, SVAL(-2).type, P_REG_RBX );
     add_reg_reg(P_REG_RAX,P_REG_RBX);
-    /*    test_reg(P_REG_RAX); int == 0 */
+    /*    test_reg32(P_REG_RAX); int == 0 */
     jnz(&label_A);
     
     mov_mem_reg(sp_reg, SVAL(-1).value, P_REG_RAX );
@@ -1846,7 +1899,7 @@ void ins_f_byte(unsigned int b)
     mov_mem8_reg(sp_reg, SVAL(-1).type, P_REG_RAX );
     mov_mem8_reg(sp_reg, SVAL(-2).type, P_REG_RBX );
     add_reg32_reg32(P_REG_RAX,P_REG_RBX);
-    /*    test_reg(P_REG_RAX); int == 0 */
+    /*    test_reg32(P_REG_RAX); int == 0 */
     jnz(&label_A);
     
     mov_mem_reg(sp_reg, SVAL(-1).value, P_REG_RAX );
@@ -1871,7 +1924,7 @@ void ins_f_byte(unsigned int b)
     mov_mem8_reg(sp_reg, -1*sizeof(struct svalue), P_REG_RAX );
     mov_mem8_reg(sp_reg, -2*sizeof(struct svalue), P_REG_RBX );
     add_reg32_reg32(P_REG_RAX,P_REG_RBX);
-    /* test_reg(P_REG_RAX);  int == 0 */
+    /* test_reg32(P_REG_RAX);  int == 0 */
     jnz(&label_A);
 
     mov_mem_reg(sp_reg, SVAL(-1).value, P_REG_RCX );
@@ -1890,6 +1943,45 @@ void ins_f_byte(unsigned int b)
   LABEL_C;
     }
     return;
+
+  case F_LSH:
+    {
+    LABELS();
+    ins_debug_instr_prologue(b, 0, 0);
+    amd64_load_sp_reg();
+    mov_mem8_reg(sp_reg, -1*sizeof(struct svalue), P_REG_RAX );
+    mov_mem8_reg(sp_reg, -2*sizeof(struct svalue), P_REG_RBX );
+    add_reg32_reg32(P_REG_RAX,P_REG_RBX);
+    /* test_reg32(P_REG_RAX);  int == 0 */
+    jnz(&label_A);
+
+    mov_mem_reg(sp_reg, SVAL(-1).value, P_REG_RCX );
+    cmp_reg_imm(P_REG_RCX,0);
+    jl( &label_A );
+    cmp_reg_imm(P_REG_RCX,63);
+    jl( &label_B );
+  LABEL_A;
+    amd64_call_c_opcode(addr, flags);
+    amd64_load_sp_reg();
+    jmp(&label_C);
+  LABEL_B;
+    mov_imm_mem(PIKE_T_INT,sp_reg,SVAL(-2).type);
+    mov_mem_reg( sp_reg, SVAL(-2).value, P_REG_RBX);
+
+    /* ok. It would have been nice is sal set a
+       bit that stayed set when you shifted out a 1 bit. :)
+    */
+    mov_reg_reg( P_REG_RBX, P_REG_RAX );
+    shl_reg_reg( P_REG_RBX, P_REG_RCX);
+    mov_reg_reg( P_REG_RBX, P_REG_RDX );
+    shr_reg_reg( P_REG_RDX, P_REG_RCX );
+    cmp_reg_reg( P_REG_RDX, P_REG_RAX );
+    jne( &label_A );
+    mov_reg_mem( P_REG_RBX,  sp_reg, SVAL(-2).value);
+    amd64_add_sp(-1);
+  LABEL_C;
+    }
+    return;
   case F_ADD_INTS:
     {
       ins_debug_instr_prologue(b, 0, 0);
@@ -2766,7 +2858,82 @@ void ins_f_byte_with_arg(unsigned int a, INT32 b)
     }
     return;
 
+  case F_AND_INT:
+    {
+    LABELS();
+    ins_debug_instr_prologue(b, 0, 0);
+    amd64_load_sp_reg();
+    mov_mem8_reg(sp_reg, SVAL(-1).type, P_REG_RAX );
+    test_reg(P_REG_RAX);
+    jnz(&label_A);
+    
+ /* FIXME: and_mem_imm */
+    mov_mem_reg(sp_reg, SVAL(-1).value, P_REG_RAX );
+    and_reg_imm(P_REG_RAX,b);
+    mov_imm_mem(PIKE_T_INT,sp_reg,SVAL(-1).type);
+    mov_reg_mem(P_REG_RBX,sp_reg,SVAL(-1).value);
+    jmp(&label_B);
+   LABEL_A;
+    update_arg1(b);
+    amd64_call_c_opcode(instrs[a-F_OFFSET].address,
+			instrs[a-F_OFFSET].flags);
+   LABEL_B;
+    }
+    return;
+
+  case F_OR_INT:
+    if( !b )
+      return;
+   {
+    LABELS();
+    ins_debug_instr_prologue(b, 0, 0);
+    amd64_load_sp_reg();
+    mov_mem8_reg(sp_reg, SVAL(-1).type, P_REG_RAX );
+    test_reg(P_REG_RAX);
+    jnz(&label_A);
+    
+ /* FIXME: or_mem_imm */
+    mov_mem_reg(sp_reg, SVAL(-1).value, P_REG_RAX );
+    or_reg_imm(P_REG_RAX,b);
+    mov_imm_mem(PIKE_T_INT,sp_reg,SVAL(-1).type);
+    mov_reg_mem(P_REG_RAX,sp_reg,SVAL(-1).value);
+    jmp(&label_B);
+   LABEL_A;
+    update_arg1(b);
+    amd64_call_c_opcode(instrs[a-F_OFFSET].address,
+			instrs[a-F_OFFSET].flags);
+   LABEL_B;
+    }
+    return;
+
+  case F_RSH_INT:
+    if( b >= 0 && b <= 63 )
+    {
+      LABELS();
+      ins_debug_instr_prologue(b, 0, 0);
+      amd64_load_sp_reg();
+      mov_mem8_reg(sp_reg, -1*sizeof(struct svalue), P_REG_RAX );
+      test_reg(P_REG_RAX);
+      jnz(&label_A);
+      mov_mem_reg( sp_reg, SVAL(-1).value, P_REG_RAX);
+    /* FIXME: shr_mem_imm */
+      mov_imm_mem(PIKE_T_INT,sp_reg,SVAL(-1).type);
+      shr_reg_imm( P_REG_RAX,b);
+      mov_reg_mem( P_REG_RAX, sp_reg, SVAL(-1).value);
+      jmp(&label_B);
+    LABEL_A;
+      update_arg1(b);
+      amd64_call_c_opcode(instrs[a-F_OFFSET].address,
+			  instrs[a-F_OFFSET].flags);
+    LABEL_C;
+    return;
+    }
+    if(!b) return;
+    if( b < 0 )
+      yyerror(">> with negative constant\n");
+  break;
 
+  case F_SUBTRACT_INT:
   case F_ADD_NEG_INT:
     b = -b;
   case F_ADD_INT:
-- 
GitLab