Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
64 changes: 33 additions & 31 deletions ext/opcache/jit/ir/dynasm/dasm_arm64.h
Original file line number Diff line number Diff line change
Expand Up @@ -175,44 +175,46 @@ static int dasm_imm12(unsigned int n)
return -1;
}

static int dasm_ffs(unsigned long long x)
#if defined(__GNUC__) || defined(__clang__)
#define dasm_ctz(x) __builtin_ctzll(x)
#define dasm_clz(x) __builtin_clzll(x)
#else
static int dasm_ctz(unsigned long long x)
{
int n = 0;
x = ~x;
while (x & 1) { x >>= 1; n++; }
return n;
}

static int dasm_clz(unsigned long long x)
{
int n = -1;
while (x) { x >>= 1; n++; }
int n = 0;
x = ~x;
while ((long long)x < 0) { x <<= 1; n++; }
return n;
}
#endif

static unsigned long long dasm_ror(unsigned long long x, int n)
{
return (x << (-n & 63)) | (x >> n);
}

static int dasm_imm13(int lo, int hi)
{
int inv = 0, w = 64, s = 0xfff, xa, xb;
/* Thanks to: https://dougallj.wordpress.com/2021/10/30/ */
int rot, ones, size, immr, imms;
unsigned long long n = (((unsigned long long)hi) << 32) | (unsigned int)lo;
unsigned long long m = 1ULL, a, b, c;
if (n & 1) { n = ~n; inv = 1; }
a = n & (unsigned long long)-(long long)n;
b = (n+a)&(unsigned long long)-(long long)(n+a);
c = (n+a-b)&(unsigned long long)-(long long)(n+a-b);
xa = dasm_ffs(a); xb = dasm_ffs(b);
if (c) {
w = dasm_ffs(c) - xa;
if (w == 32) m = 0x0000000100000001UL;
else if (w == 16) m = 0x0001000100010001UL;
else if (w == 8) m = 0x0101010101010101UL;
else if (w == 4) m = 0x1111111111111111UL;
else if (w == 2) m = 0x5555555555555555UL;
else return -1;
s = (-2*w & 0x3f) - 1;
} else if (!a) {
return -1;
} else if (xb == -1) {
xb = 64;
}
if ((b-a) * m != n) return -1;
if (inv) {
return ((w - xb) << 6) | (s+w+xa-xb);
} else {
return ((w - xa) << 6) | (s+xb-xa);
}
return -1;
if ((n+1u) <= 1u) return -1; /* Neither all-zero nor all-ones are allowed. */
rot = (n & (n+1u)) ? dasm_ctz(n & (n+1u)) : 64;
n = dasm_ror(n, rot & 63);
ones = dasm_ctz(~n);
size = dasm_clz(n) + ones;
if (dasm_ror(n, size & 63) != n) return -1; /* Non-repeating? */
immr = -rot & (size - 1);
imms = (-(size << 1) | (ones - 1)) & 63;
return ((immr | (size & 64)) << 6) | imms;
}

/* Pass 1: Store actions and args, link branches/labels, estimate offsets. */
Expand Down
19 changes: 19 additions & 0 deletions ext/opcache/tests/jit/and_003.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
--TEST--
JIT BW_AND: 003 (non-encodable AArch64 logical immediate, wrong result)
--INI--
opcache.enable=1
opcache.enable_cli=1
opcache.file_update_protection=0
opcache.jit=function
opcache.jit_buffer_size=64M
--EXTENSIONS--
opcache
--SKIPIF--
<?php if (PHP_INT_SIZE != 8) die("skip: 64-bit only"); ?>
--FILE--
<?php
function foo($x) { return $x & 0x5555555555555554; }
var_dump(foo(-1));
?>
--EXPECT--
int(6148914691236517204)
19 changes: 19 additions & 0 deletions ext/opcache/tests/jit/and_004.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
--TEST--
JIT BW_AND: 004 (non-encodable AArch64 logical immediate, illegal instruction)
--INI--
opcache.enable=1
opcache.enable_cli=1
opcache.file_update_protection=0
opcache.jit=function
opcache.jit_buffer_size=64M
--EXTENSIONS--
opcache
--SKIPIF--
<?php if (PHP_INT_SIZE != 8) die("skip: 64-bit only"); ?>
--FILE--
<?php
function foo($x) { return $x & 0x200000003; }
var_dump(foo(-1));
?>
--EXPECT--
int(8589934595)
19 changes: 19 additions & 0 deletions ext/opcache/tests/jit/or_001.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
--TEST--
JIT BW_OR: 001 (non-encodable AArch64 logical immediate, wrong result)
--INI--
opcache.enable=1
opcache.enable_cli=1
opcache.file_update_protection=0
opcache.jit=function
opcache.jit_buffer_size=64M
--EXTENSIONS--
opcache
--SKIPIF--
<?php if (PHP_INT_SIZE != 8) die("skip: 64-bit only"); ?>
--FILE--
<?php
function foo($x) { return $x | 0x5555555555555554; }
var_dump(foo(0));
?>
--EXPECT--
int(6148914691236517204)
19 changes: 19 additions & 0 deletions ext/opcache/tests/jit/or_002.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
--TEST--
JIT BW_OR: 002 (non-encodable AArch64 logical immediate, illegal instruction)
--INI--
opcache.enable=1
opcache.enable_cli=1
opcache.file_update_protection=0
opcache.jit=function
opcache.jit_buffer_size=64M
--EXTENSIONS--
opcache
--SKIPIF--
<?php if (PHP_INT_SIZE != 8) die("skip: 64-bit only"); ?>
--FILE--
<?php
function foo($x) { return $x | 0x200000003; }
var_dump(foo(0));
?>
--EXPECT--
int(8589934595)
19 changes: 19 additions & 0 deletions ext/opcache/tests/jit/xor_004.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
--TEST--
JIT XOR: 004 (non-encodable AArch64 logical immediate, wrong result)
--INI--
opcache.enable=1
opcache.enable_cli=1
opcache.file_update_protection=0
opcache.jit=function
opcache.jit_buffer_size=64M
--EXTENSIONS--
opcache
--SKIPIF--
<?php if (PHP_INT_SIZE != 8) die("skip: 64-bit only"); ?>
--FILE--
<?php
function foo($x) { return $x ^ 0x5555555555555554; }
var_dump(foo(0));
?>
--EXPECT--
int(6148914691236517204)
19 changes: 19 additions & 0 deletions ext/opcache/tests/jit/xor_005.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
--TEST--
JIT XOR: 005 (non-encodable AArch64 logical immediate, illegal instruction)
--INI--
opcache.enable=1
opcache.enable_cli=1
opcache.file_update_protection=0
opcache.jit=function
opcache.jit_buffer_size=64M
--EXTENSIONS--
opcache
--SKIPIF--
<?php if (PHP_INT_SIZE != 8) die("skip: 64-bit only"); ?>
--FILE--
<?php
function foo($x) { return $x ^ 0x200000003; }
var_dump(foo(0));
?>
--EXPECT--
int(8589934595)
Loading