Browse Source

ARM: Add test/copy and comparison instructions.

Mike Pall 14 years ago
parent
commit
3af41060c7
1 changed files with 207 additions and 6 deletions
  1. 207 6
      src/buildvm_arm.dasc

+ 207 - 6
src/buildvm_arm.dasc

@@ -1356,33 +1356,234 @@ static void build_ins(BuildCtx *ctx, BCOp op, int defop)
   /* Remember: all ops branch for a true comparison, fall through otherwise. */
 
   case BC_ISLT: case BC_ISGE: case BC_ISLE: case BC_ISGT:
-    |  NYI
+    |  // RA = src1*8, RC = src2, JMP with RC = target
+    |   lsl RC, RC, #3
+    |  ldrd CARG12, [RA, BASE]!
+    |    ldrh RB, [PC, #2]
+    |   ldrd CARG34, [RC, BASE]!
+    |    add PC, PC, #4
+    |    add RB, PC, RB, lsl #2
+    |  checktp CARG2, LJ_TISNUM
+    |  bne >3
+    |  checktp CARG4, LJ_TISNUM
+    |  bne >4
+    |  cmp CARG1, CARG3
+    if (op == BC_ISLT) {
+      |  sublt PC, RB, #0x20000
+    } else if (op == BC_ISGE) {
+      |  subge PC, RB, #0x20000
+    } else if (op == BC_ISLE) {
+      |  suble PC, RB, #0x20000
+    } else {
+      |  subgt PC, RB, #0x20000
+    }
+    |1:
+    |  ins_next
+    |
+    |3: // CARG12 is not an integer.
+    |  bhi ->vmeta_comp
+    |  // CARG12 is a number.
+    |  checktp CARG4, LJ_TISNUM
+    |  movlo RA, RB			// Save RB.
+    |  blo >5
+    |  // CARG12 is a number, CARG3 is an integer.
+    |  mov CARG1, CARG3
+    |  mov RC, RA
+    |  mov RA, RB			// Save RB.
+    |  bl extern __aeabi_i2d
+    |  mov CARG3, CARG1
+    |  mov CARG4, CARG2
+    |  ldrd CARG12, [RC]		// Restore first operand.
+    |  b >5
+    |4:  // CARG1 is an integer, CARG34 is not an integer.
+    |  bhi ->vmeta_comp
+    |  // CARG1 is an integer, CARG34 is a number
+    |  mov RA, RB			// Save RB.
+    |  bl extern __aeabi_i2d
+    |  ldrd CARG34, [RC]		// Restore second operand.
+    |5:  // CARG12 and CARG34 are numbers.
+    |  bl extern __aeabi_cdcmple
+    |  // To preserve NaN semantics GE/GT branch on unordered, but LT/LE don't.
+    if (op == BC_ISLT) {
+      |  sublo PC, RA, #0x20000
+    } else if (op == BC_ISGE) {
+      |  subhs PC, RA, #0x20000
+    } else if (op == BC_ISLE) {
+      |  subls PC, RA, #0x20000
+    } else {
+      |  subhi PC, RA, #0x20000
+    }
+    |  b <1
     break;
 
   case BC_ISEQV: case BC_ISNEV:
     vk = op == BC_ISEQV;
-    |  NYI
+    |  // RA = src1*8, RC = src2, JMP with RC = target
+    |   lsl RC, RC, #3
+    |  ldrd CARG12, [RA, BASE]!
+    |    ldrh RB, [PC, #2]
+    |   ldrd CARG34, [RC, BASE]!
+    |    add PC, PC, #4
+    |    add RB, PC, RB, lsl #2
+    |  checktp CARG2, LJ_TISNUM
+    |  cmnls CARG4, #-LJ_TISNUM
+    if (vk) {
+      |  bls ->BC_ISEQN_Z
+    } else {
+      |  bls ->BC_ISNEN_Z
+    }
+    |  // Either or both types are not numbers.
+    |  cmp CARG2, CARG4			// Compare types.
+    |  bne >2				// Not the same type?
+    |  checktp CARG2, LJ_TISPRI
+    |  bhs >1				// Same type and primitive type?
+    |
+    |  // Same types and not a primitive type. Compare GCobj or pvalue.
+    |  cmp CARG1, CARG3
+    if (vk) {
+      |  bne >3				// Different GCobjs or pvalues?
+      |1:  // Branch if same.
+      |  sub PC, RB, #0x20000
+      |2:  // Different.
+      |  ins_next
+      |3:
+      |  checktp CARG2, LJ_TISTABUD
+      |  bhi <2				// Different objects and not table/ud?
+    } else {
+      |  beq >1				// Same GCobjs or pvalues?
+      |  checktp CARG2, LJ_TISTABUD
+      |  bhi >2				// Different objects and not table/ud?
+    }
+    |  // Different tables or userdatas. Need to check __eq metamethod.
+    |  // Field metatable must be at same offset for GCtab and GCudata!
+    |  ldr TAB:RA, TAB:CARG1->metatable
+    |  cmp TAB:RA, #0
+    if (vk) {
+      |  beq <2			// No metatable?
+    } else {
+      |  beq >2			// No metatable?
+    }
+    |  ldrb RA, TAB:RA->nomm
+    |   mov CARG4, #1-vk		// ne = 0 or 1.
+    |   mov CARG2, CARG1
+    |  tst RA, #1<<MM_eq
+    |  beq ->vmeta_equal		// 'no __eq' flag not set?
+    if (!vk) {
+      |2:  // Branch if different.
+      |  sub PC, RB, #0x20000
+      |1:  // Same.
+      |  ins_next
+    }
     break;
 
   case BC_ISEQS: case BC_ISNES:
     vk = op == BC_ISEQS;
-    |  NYI
+    |  // RA = src*8, RC = str_const (~), JMP with RC = target
+    |   mvn RC, RC
+    |  ldrd CARG12, [BASE, RA]
+    |    ldrh RB, [PC, #2]
+    |   ldr STR:CARG3, [KBASE, RC, lsl #2]
+    |    add PC, PC, #4
+    |    add RB, PC, RB, lsl #2
+    |  checktp CARG2, LJ_TSTR
+    |  cmpeq CARG1, CARG3
+    if (vk) {
+      |  subeq PC, RB, #0x20000
+    } else {
+      |  subne PC, RB, #0x20000
+    }
+    |  ins_next
     break;
 
   case BC_ISEQN: case BC_ISNEN:
     vk = op == BC_ISEQN;
-    |  NYI
+    |  // RA = src*8, RC = num_const (~), JMP with RC = target
+    |   lsl RC, RC, #3
+    |  ldrd CARG12, [RA, BASE]!
+    |    ldrh RB, [PC, #2]
+    |   ldrd CARG34, [RC, KBASE]!
+    |    add PC, PC, #4
+    |    add RB, PC, RB, lsl #2
+    if (vk) {
+      |->BC_ISEQN_Z:
+    } else {
+      |->BC_ISNEN_Z:
+    }
+    |  checktp CARG2, LJ_TISNUM
+    |  bne >3
+    |  checktp CARG4, LJ_TISNUM
+    |  bne >4
+    |  cmp CARG1, CARG3
+    if (vk) {
+      |  subeq PC, RB, #0x20000
+    } else {
+      |  subne PC, RB, #0x20000
+    }
+    |1:
+    |  ins_next
+    |
+    |3:  // CARG12 is not an integer.
+    |  bhi <1
+    |  // CARG12 is a number.
+    |  checktp CARG4, LJ_TISNUM
+    |  movlo RA, RB			// Save RB.
+    |  blo >5
+    |  // CARG12 is a number, CARG3 is an integer.
+    |  mov CARG1, CARG3
+    |  mov RC, RA
+    |4:  // CARG1 is an integer, CARG34 is a number.
+    |  mov RA, RB			// Save RB.
+    |  bl extern __aeabi_i2d
+    |  ldrd CARG34, [RC]		// Restore other operand.
+    |5:  // CARG12 and CARG34 are numbers.
+    |  bl extern __aeabi_cdcmpeq
+    if (vk) {
+      |  subeq PC, RA, #0x20000
+    } else {
+      |  subne PC, RA, #0x20000
+    }
+    |  b <1
     break;
 
   case BC_ISEQP: case BC_ISNEP:
     vk = op == BC_ISEQP;
-    |  NYI
+    |  // RA = src*8, RC = primitive_type (~), JMP with RC = target
+    |  ldrd CARG12, [BASE, RA]
+    |   ldrh RB, [PC, #2]
+    |   add PC, PC, #4
+    |  mvn RC, RC
+    |   add RB, PC, RB, lsl #2
+    |  cmp CARG2, RC
+    if (vk) {
+      |  subeq PC, RB, #0x20000
+    } else {
+      |  subne PC, RB, #0x20000
+    }
+    |  ins_next
     break;
 
   /* -- Unary test and copy ops ------------------------------------------- */
 
   case BC_ISTC: case BC_ISFC: case BC_IST: case BC_ISF:
-    |  NYI
+    |  // RA = dst*8 or unused, RC = src, JMP with RC = target
+    |  add RC, BASE, RC, lsl #3
+    |   ldrh RB, [PC, #2]
+    |  ldrd CARG12, [RC]
+    |   add PC, PC, #4
+    |   add RB, PC, RB, lsl #2
+    |  checktp CARG2, LJ_TTRUE
+    if (op == BC_ISTC || op == BC_IST) {
+      |  subls PC, RB, #0x20000
+      if (op == BC_ISTC) {
+	|  strdls CARG12, [BASE, RA]
+      }
+    } else {
+      |  subhi PC, RB, #0x20000
+      if (op == BC_ISFC) {
+	|  strdhi CARG12, [BASE, RA]
+      }
+    }
+    |  ins_next
     break;
 
   /* -- Unary ops --------------------------------------------------------- */