[php-src] jit-arm64: Optimizing LONG MUL to SHIFT: add overflow detection for x86
| From: | Hao Sun | Date: | Tue, 27 Apr 2021 09:39:33 +0000 |
| Subject: | [php-src] jit-arm64: Optimizing LONG MUL to SHIFT: add overflow detection for x86 | ||
| Groups: | php.cvs | ||
| Request: | Send a blank email to php-cvs+get-115868@lists.php.net to get a copy of this message | ||
Author: Hao Sun (shqking)
Date: 2021-04-27T09:39:04Z
Commit: https://github.com/php/php-src/commit/0be1cd9e279cc366bf2e2e8d1739b88633e054dc
Raw diff: https://github.com/php/php-src/commit/0be1cd9e279cc366bf2e2e8d1739b88633e054dc.diff
Optimizing LONG MUL to SHIFT: add overflow detection for x86
Similar to the AArch64 implementation, we compare "op" and "op << n >>
n" to detect integer overflow.
Note that instructions 'pushf' and 'popf' are used to save/restore the
flags set by 'cmp', otherwise, the follow-up 'shl' might change the
flags.
Note that test case "mul_004.phpt" can pass now for x86.
Change-Id: Ieee037f41dce298979b8a0964ca97598939c495c
Changed paths:
M ext/opcache/jit/zend_jit_x86.dasc
Diff:
diff --git a/ext/opcache/jit/zend_jit_x86.dasc b/ext/opcache/jit/zend_jit_x86.dasc
index 8dbf12b94b5e..679746ec91e8 100644
--- a/ext/opcache/jit/zend_jit_x86.dasc
+++ b/ext/opcache/jit/zend_jit_x86.dasc
@@ -4180,6 +4180,7 @@ static int zend_jit_math_long_long(dasm_State **Dst,
bool same_ops = zend_jit_same_addr(op1_addr, op2_addr);
zend_reg result_reg;
zend_reg tmp_reg = ZREG_R0;
+ bool use_ovf_flag = 1;
if (Z_MODE(res_addr) == IS_REG && (res_info & MAY_BE_LONG)) {
if (may_overflow && (res_info & MAY_BE_GUARD)
@@ -4211,7 +4212,23 @@ static int zend_jit_math_long_long(dasm_State **Dst,
| GET_ZVAL_LVAL result_reg, op1_addr
| shl Ra(result_reg), floor_log2(Z_LVAL_P(Z_ZV(op2_addr)))
if (may_overflow) {
- // TODO: check overflow.
+ /* Compare 'op' and '((op << n) >> n)' for overflow.
+ * Flag: jne -> overflow. je -> no overflow.
+ */
+ use_ovf_flag = 0;
+ | sar Ra(result_reg), floor_log2(Z_LVAL_P(Z_ZV(op2_addr)))
+ if (Z_MODE(op1_addr) == IS_CONST_ZVAL) {
+ | cmp Ra(result_reg), Z_LVAL_P(Z_ZV(op1_addr))
+ } else if (Z_MODE(op1_addr) == IS_MEM_ZVAL) {
+ | cmp Ra(result_reg), [Ra(Z_REG(op1_addr))+Z_OFFSET(op1_addr)]
+ } else if (Z_MODE(op1_addr) == IS_REG) {
+ | cmp Ra(result_reg), Ra(Z_REG(op1_addr))
+ } else {
+ ZEND_UNREACHABLE();
+ }
+ | pushf
+ | shl Ra(result_reg), floor_log2(Z_LVAL_P(Z_ZV(op2_addr)))
+ | popf
}
}
} else if (opcode == ZEND_MUL &&
@@ -4226,7 +4243,23 @@ static int zend_jit_math_long_long(dasm_State **Dst,
| GET_ZVAL_LVAL result_reg, op2_addr
| shl Ra(result_reg), floor_log2(Z_LVAL_P(Z_ZV(op1_addr)))
if (may_overflow) {
- // TODO: check overflow.
+ /* Compare 'op' and '((op << n) >> n)' for overflow.
+ * Flag: jne -> overflow. je -> no overflow.
+ */
+ use_ovf_flag = 0;
+ | sar Ra(result_reg), floor_log2(Z_LVAL_P(Z_ZV(op1_addr)))
+ if (Z_MODE(op2_addr) == IS_CONST_ZVAL) {
+ | cmp Ra(result_reg), Z_LVAL_P(Z_ZV(op2_addr))
+ } else if (Z_MODE(op2_addr) == IS_MEM_ZVAL) {
+ | cmp Ra(result_reg), [Ra(Z_REG(op2_addr))+Z_OFFSET(op2_addr)]
+ } else if (Z_MODE(op2_addr) == IS_REG) {
+ | cmp Ra(result_reg), Ra(Z_REG(op2_addr))
+ } else {
+ ZEND_UNREACHABLE();
+ }
+ | pushf
+ | shl Ra(result_reg), floor_log2(Z_LVAL_P(Z_ZV(op1_addr)))
+ | popf
}
}
} else if (opcode == ZEND_DIV &&
@@ -4267,20 +4300,36 @@ static int zend_jit_math_long_long(dasm_State **Dst,
int32_t exit_point = zend_jit_trace_get_exit_point(opline, 0);
const void *exit_addr = zend_jit_trace_get_exit_addr(exit_point);
if ((res_info & MAY_BE_ANY) == MAY_BE_LONG) {
- | jo &exit_addr
+ if (use_ovf_flag) {
+ | jo &exit_addr
+ } else {
+ | jne &exit_addr
+ }
if (Z_MODE(res_addr) == IS_REG && result_reg != Z_REG(res_addr)) {
| mov Ra(Z_REG(res_addr)), Ra(result_reg)
}
} else if ((res_info & MAY_BE_ANY) == MAY_BE_DOUBLE) {
- | jno &exit_addr
+ if (use_ovf_flag) {
+ | jno &exit_addr
+ } else {
+ | je &exit_addr
+ }
} else {
ZEND_UNREACHABLE();
}
} else {
if (res_info & MAY_BE_LONG) {
- | jo >1
+ if (use_ovf_flag) {
+ | jo >1
+ } else {
+ | jne >1
+ }
} else {
- | jno >1
+ if (use_ovf_flag) {
+ | jno >1
+ } else {
+ | je >1
+ }
}
}
}