Browse Source

ARM: Add binary arithmetic instructions.

Mike Pall 14 years ago
parent
commit
5b06b298a2
1 changed files with 155 additions and 15 deletions
  1. 155 15
      src/buildvm_arm.dasc

+ 155 - 15
src/buildvm_arm.dasc

@@ -92,6 +92,7 @@
 |.macro decode_RB8, dst, ins; and dst, MASKR8, ins, lsr #21; .endmacro
 |.macro decode_RB8, dst, ins; and dst, MASKR8, ins, lsr #21; .endmacro
 |.macro decode_RC8, dst, ins; and dst, MASKR8, ins, lsr #13; .endmacro
 |.macro decode_RC8, dst, ins; and dst, MASKR8, ins, lsr #13; .endmacro
 |.macro decode_RD, dst, ins; lsr dst, ins, #16; .endmacro
 |.macro decode_RD, dst, ins; lsr dst, ins, #16; .endmacro
+|.macro decode_OP, dst, ins; and dst, ins, #255; .endmacro
 |
 |
 |// Instruction fetch.
 |// Instruction fetch.
 |.macro ins_NEXT1
 |.macro ins_NEXT1
@@ -189,6 +190,10 @@
 |
 |
 |//-----------------------------------------------------------------------
 |//-----------------------------------------------------------------------
 
 
+#if !LJ_DUALNUM
+#error "Only dual-number mode supported for ARM target"
+#endif
+
 /* Generate subroutines used by opcodes and other parts of the VM. */
 /* Generate subroutines used by opcodes and other parts of the VM. */
 /* The .code_sub section should be last to help static branch prediction. */
 /* The .code_sub section should be last to help static branch prediction. */
 static void build_subroutines(BuildCtx *ctx)
 static void build_subroutines(BuildCtx *ctx)
@@ -417,7 +422,7 @@ static void build_subroutines(BuildCtx *ctx)
   |  NYI
   |  NYI
   |
   |
   |->cont_nop:
   |->cont_nop:
-  |  NYI
+  |  ins_next
   |
   |
   |->cont_ra:				// RA = resultptr
   |->cont_ra:				// RA = resultptr
   |  NYI
   |  NYI
@@ -434,18 +439,44 @@ static void build_subroutines(BuildCtx *ctx)
   |//-- Arithmetic metamethods ---------------------------------------------
   |//-- Arithmetic metamethods ---------------------------------------------
   |
   |
   |->vmeta_arith_vn:
   |->vmeta_arith_vn:
-  |  NYI
+  |  decode_RB8 RB, INS
+  |   decode_RC8 RC, INS
+  |  add CARG3, BASE, RB
+  |   add CARG4, KBASE, RC
+  |  b >1
   |
   |
   |->vmeta_arith_nv:
   |->vmeta_arith_nv:
-  |  NYI
+  |  decode_RB8 RB, INS
+  |   decode_RC8 RC, INS
+  |  add CARG4, BASE, RB
+  |   add CARG3, KBASE, RC
+  |  b >1
   |
   |
   |->vmeta_unm:
   |->vmeta_unm:
-  |  NYI
+  |  add CARG3, BASE, RC
+  |  add CARG4, BASE, RC
+  |  b >1
   |
   |
   |->vmeta_arith_vv:
   |->vmeta_arith_vv:
-  |  NYI
-  |
+  |  decode_RB8 RB, INS
+  |   decode_RC8 RC, INS
+  |  add CARG3, BASE, RB
+  |   add CARG4, BASE, RC
+  |1:
+  |  decode_OP OP, INS
+  |   add CARG2, BASE, RA
+  |    str BASE, L->base
+  |   mov CARG1, L
+  |    str PC, SAVE_PC
+  |  str OP, ARG5
+  |  bl extern lj_meta_arith  // (lua_State *L, TValue *ra,*rb,*rc, BCReg op)
+  |  // Returns NULL (finished) or TValue * (metamethod).
+  |  cmp CRET1, #0
+  |  beq ->cont_nop
+  |
+  |  // Call metamethod for binary op.
   |->vmeta_binop:
   |->vmeta_binop:
+  |  // BASE = old base, CRET1 = new base, stack = cont/func/o1/o2
   |  NYI
   |  NYI
   |
   |
   |->vmeta_len:
   |->vmeta_len:
@@ -789,6 +820,9 @@ static void build_subroutines(BuildCtx *ctx)
 #else
 #else
   |->vm_trunc:
   |->vm_trunc:
 #endif
 #endif
+  |
+  |->vm_mod:
+  |  NYI
   |
   |
   |->vm_powi:
   |->vm_powi:
 #if LJ_HASJIT
 #if LJ_HASJIT
@@ -804,7 +838,21 @@ static void build_subroutines(BuildCtx *ctx)
   |// Compute x op y for basic arithmetic operators (+ - * / % ^ and unary -)
   |// Compute x op y for basic arithmetic operators (+ - * / % ^ and unary -)
   |// and basic math functions. ORDER ARITH
   |// and basic math functions. ORDER ARITH
   |->vm_foldarith:
   |->vm_foldarith:
-  |  NYI
+  |  ldr OP, [sp]
+  |  cmp OP, #1
+  |  blo extern __aeabi_dadd
+  |  beq extern __aeabi_dsub
+  |  cmp OP, #3
+  |  blo extern __aeabi_dmul
+  |  beq extern __aeabi_ddiv
+  |  cmp OP, #5
+  |  blo ->vm_mod
+  |  beq extern pow
+  |  cmp OP, #7
+  |  eorlo CARG2, CARG2, #0x80000000
+  |  biceq CARG2, CARG2, #0x80000000
+  |  bxls lr
+  |  NYI  // Other operations only needed by JIT compiler.
   |
   |
   |//-----------------------------------------------------------------------
   |//-----------------------------------------------------------------------
   |//-- Miscellaneous functions --------------------------------------------
   |//-- Miscellaneous functions --------------------------------------------
@@ -925,33 +973,125 @@ static void build_ins(BuildCtx *ctx, BCOp op, int defop)
     |   ins_next3
     |   ins_next3
     |2:
     |2:
     |  checktab CARG2, ->vmeta_len
     |  checktab CARG2, ->vmeta_len
-    |  blx extern lj_tab_len		// (GCtab *t)
+    |  bl extern lj_tab_len		// (GCtab *t)
     |  // Returns uint32_t (but less than 2^31).
     |  // Returns uint32_t (but less than 2^31).
     |  b <1
     |  b <1
     break;
     break;
 
 
   /* -- Binary ops -------------------------------------------------------- */
   /* -- Binary ops -------------------------------------------------------- */
 
 
+    |.macro ins_arithcheck, cond, ncond, target
+    ||if (vk == 1) {
+    |   cmn CARG4, #-LJ_TISNUM
+    |    cmn..cond CARG2, #-LJ_TISNUM
+    ||} else {
+    |   cmn CARG2, #-LJ_TISNUM
+    |    cmn..cond CARG4, #-LJ_TISNUM
+    ||}
+    |  b..ncond target
+    |.endmacro
+    |.macro ins_arithcheck_int, target
+    |  ins_arithcheck eq, ne, target
+    |.endmacro
+    |.macro ins_arithcheck_num, target
+    |  ins_arithcheck lo, hs, target
+    |.endmacro
+    |
+    |.macro ins_arithpre
+    |  decode_RB8 RB, INS
+    |   decode_RC8 RC, INS
+    |  // RA = dst*8, RB = src1*8, RC = src2*8 | num_const*8
+    ||vk = ((int)op - BC_ADDVN) / (BC_ADDNV-BC_ADDVN);
+    ||switch (vk) {
+    ||case 0:
+    |   ldrd CARG12, [BASE, RB]
+    |    ldrd CARG34, [KBASE, RC]
+    ||  break;
+    ||case 1:
+    |   ldrd CARG34, [BASE, RB]
+    |    ldrd CARG12, [KBASE, RC]
+    ||  break;
+    ||default:
+    |   ldrd CARG12, [BASE, RB]
+    |    ldrd CARG34, [BASE, RC]
+    ||  break;
+    ||}
+    |.endmacro
+    |
+    |.macro ins_arithfallback, ins
+    ||switch (vk) {
+    ||case 0:
+    |   ins ->vmeta_arith_vn
+    ||  break;
+    ||case 1:
+    |   ins ->vmeta_arith_nv
+    ||  break;
+    ||default:
+    |   ins ->vmeta_arith_vv
+    ||  break;
+    ||}
+    |.endmacro
+    |
+    |.macro ins_arithdn, intins, fpcall
+    |  ins_arithpre
+    |   ins_next1
+    |  ins_arithcheck_int >5
+    |.if "intins" == "smull"
+    |  smull CARG1, RC, CARG3, CARG1
+    |  cmp RC, CARG1, asr #31
+    |  ins_arithfallback bne
+    |.else
+    |  intins CARG1, CARG1, CARG3
+    |  ins_arithfallback bvs
+    |.endif
+    |4:
+    |   ins_next2
+    |  strd CARG12, [BASE, RA]
+    |   ins_next3
+    |5:  // FP variant.
+    |  ins_arithfallback ins_arithcheck_num
+    |  bl fpcall
+    |   ins_next1
+    |  b <4
+    |.endmacro
+    |
+    |.macro ins_arithfp, fpcall
+    |  ins_arithpre
+    ||if (op == BC_MODVN) {
+    |  ->BC_MODVN_Z:
+    ||}
+    |  ins_arithfallback ins_arithcheck_num
+    |  bl fpcall
+    |   ins_next1
+    |   ins_next2
+    |  strd CARG12, [BASE, RA]
+    |   ins_next3
+    |.endmacro
+
   case BC_ADDVN: case BC_ADDNV: case BC_ADDVV:
   case BC_ADDVN: case BC_ADDNV: case BC_ADDVV:
-    |  NYI
+    |  ins_arithdn adds, extern __aeabi_dadd
     break;
     break;
   case BC_SUBVN: case BC_SUBNV: case BC_SUBVV:
   case BC_SUBVN: case BC_SUBNV: case BC_SUBVV:
-    |  NYI
+    |  ins_arithdn subs, extern __aeabi_dsub
     break;
     break;
   case BC_MULVN: case BC_MULNV: case BC_MULVV:
   case BC_MULVN: case BC_MULNV: case BC_MULVV:
-    |  NYI
+    |  ins_arithdn smull, extern __aeabi_dmul
     break;
     break;
   case BC_DIVVN: case BC_DIVNV: case BC_DIVVV:
   case BC_DIVVN: case BC_DIVNV: case BC_DIVVV:
-    |  NYI
+    |  ins_arithfp extern __aeabi_ddiv
     break;
     break;
   case BC_MODVN:
   case BC_MODVN:
-    |  NYI
+    |  // NYI: integer arithmetic.
+    |  // Note: __aeabi_idivmod is unsuitable. It uses trunc, not floor.
+    |  ins_arithfp ->vm_mod
     break;
     break;
   case BC_MODNV: case BC_MODVV:
   case BC_MODNV: case BC_MODVV:
-    |  NYI
+    |  ins_arithpre
+    |  b ->BC_MODVN_Z
     break;
     break;
   case BC_POW:
   case BC_POW:
-    |  NYI
+    |  // NYI: (partial) integer arithmetic.
+    |  ins_arithfp extern pow
     break;
     break;
 
 
   case BC_CAT:
   case BC_CAT: