ARM: Add test/copy and comparison instructions.

This commit is contained in:
Mike Pall 2011-04-08 02:48:55 +02:00
parent 83e302938b
commit 3af41060c7

View File

@ -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. */ /* Remember: all ops branch for a true comparison, fall through otherwise. */
case BC_ISLT: case BC_ISGE: case BC_ISLE: case BC_ISGT: 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; break;
case BC_ISEQV: case BC_ISNEV: case BC_ISEQV: case BC_ISNEV:
vk = op == BC_ISEQV; 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; break;
case BC_ISEQS: case BC_ISNES: case BC_ISEQS: case BC_ISNES:
vk = op == BC_ISEQS; 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; break;
case BC_ISEQN: case BC_ISNEN: case BC_ISEQN: case BC_ISNEN:
vk = op == BC_ISEQN; 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; break;
case BC_ISEQP: case BC_ISNEP: case BC_ISEQP: case BC_ISNEP:
vk = op == BC_ISEQP; 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; break;
/* -- Unary test and copy ops ------------------------------------------- */ /* -- Unary test and copy ops ------------------------------------------- */
case BC_ISTC: case BC_ISFC: case BC_IST: case BC_ISF: 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; break;
/* -- Unary ops --------------------------------------------------------- */ /* -- Unary ops --------------------------------------------------------- */