# Zero-fill right shift.

- Thread: https://externals.io/message/81706
- Original archive: https://news-web.php.net/php.internals/81706
- Started by Leigh on 2015-02-03T13:20:22+00:00
- Messages: 16
- Reply by email to internals@lists.php.net
- More for agents: search with https://externals.io/search.md?q={query} · JSON API at https://externals.io/api · documentation at https://externals.io/llms.txt

---

## #81706 — Leigh — 2015-02-03T13:20:22+00:00

URL: https://externals.io/message/81706#81706

Hi list,

How do we feel about a zero-fill right shift operator?

PHPs current right shift operator preserves signage, but this is not
always desirable.

I propose the same syntax as JavaScript for this: >>>

php -r 'var_dump(-256 >> 8);'
int(-1)

php -r 'var_dump(-256 >>> 8);'
int(16777215)

This will introduce a T_SHRZF token and corresponding opcode. Targeting PHP 7.

---

## #81707 — Leigh — 2015-02-03T13:24:07+00:00

URL: https://externals.io/message/81706#81707 · In reply to: #81706

> This will introduce a T_SHRZF token and corresponding opcode. Targeting PHP 7.

That should have been T_SRZF, and I suppose I would also have to add
">>>=" (T_SRZF_EQUAL) which looks nasty, but should be included for
completeness.

---

## #81708 — Andrea Faulds — 2015-02-03T13:25:12+00:00

URL: https://externals.io/message/81706#81708 · In reply to: #81706

Hi Leigh,

> 
> 
> Hi list,
> 
> How do we feel about a zero-fill right shift operator?
> 
> PHPs current right shift operator preserves signage, but this is not
> always desirable.
> 
> I propose the same syntax as JavaScript for this: >>>
> 
> php -r 'var_dump(-256 >> 8);'
> int(-1)
> 
> php -r 'var_dump(-256 >>> 8);'
> int(16777215)
> 
> This will introduce a T_SHRZF token and corresponding opcode. Targeting PHP 7.

Hmm, how would this interact with bigints? Does it rely on fixed-width integers, as it appears to? :/

I think it’s a very obscure use case, too. Might be better to add a function in this case, like we did for `intdiv()`.

Thoughts?

--
Andrea Faulds
http://ajf.me/

---

## #81710 — Leigh — 2015-02-03T13:51:38+00:00

URL: https://externals.io/message/81706#81710 · In reply to: #81708

> Hmm, how would this interact with bigints? Does it rely on fixed-width integers, as it appears to? :/

No idea. Personally I'm opposed to the bigints implementation because
of the implicit type auto-promotion.

---

## #81711 — Andrea Faulds — 2015-02-03T13:54:13+00:00

URL: https://externals.io/message/81706#81711 · In reply to: #81710

Hi Leigh,

> 
> 
> 
> > […]
> 
> No idea. Personally I'm opposed to the bigints implementation because
> of the implicit type auto-promotion.

Huh? There’s no type promotion from a userland perspective, it’s entirely an implementation detail. Yes, some integers may be IS_LONG and others may be IS_BIGINT internally, but that’s only for Zend Engine 3 (might change in future), the boundary point varies by platform, and crucially, you can’t distinguish them from userland.

--
Andrea Faulds
http://ajf.me/

---

## #81713 — Leigh — 2015-02-03T14:15:11+00:00

URL: https://externals.io/message/81706#81713 · In reply to: #81711

> Hi Leigh,
>
> > […]
>
> Huh? There’s no type promotion from a userland perspective, it’s entirely an implementation detail. Yes, some integers may be IS_LONG and others may be IS_BIGINT internally, but that’s only for Zend Engine 3 (might change in future), the boundary point varies by platform, and crucially, you can’t distinguish them from userland.

Aside from the breaks to some binary ops and once you hit the
promotion breakpoint working with that integer is a lot slower. Lets
not derail this thread into a discussion about why I dislike bigints.

---

## #81714 — Andrea Faulds — 2015-02-03T14:36:15+00:00

URL: https://externals.io/message/81706#81714 · In reply to: #81713

> 
> 
> > […]
> 
> Aside from the breaks to some binary ops

I don’t know where you got that idea. The binary ops are consistent - they aren’t constrained by register size like in previous PHP versions, but they’re still completely consistent.

> and once you hit the
> promotion breakpoint working with that integer is a lot slower.

It’s slower, yes, but that hardly matters. If people care so much about performance, why use PHP?
--
Andrea Faulds
http://ajf.me/

---

## #81715 — Leigh — 2015-02-03T14:43:43+00:00

URL: https://externals.io/message/81706#81715 · In reply to: #81714

> I don’t know where you got that idea. The binary ops are consistent - they aren’t constrained by register size like in previous PHP versions, but they’re still completely consistent.
>

php -r 'var_dump(1 << 65);'
int(2)

Rotate left gets broken.

> It’s slower, yes, but that hardly matters. If people care so much about performance, why use PHP?
>

If people didn't care about performance, we wouldn't have phpng, or
any of the other work people have done to make the engine faster.

Sometimes you have to make the most of what you have available.

---

## #81717 — Andrea Faulds — 2015-02-03T14:49:27+00:00

URL: https://externals.io/message/81706#81717 · In reply to: #81715

Hi,

> 
> 
> 
> > […]
> 
> php -r 'var_dump(1 << 65);'
> int(2)
> 
> Rotate left gets broken.

It’s not “broken”, the behaviour is just different to account for it now being an arbitrary-precision type. If you want to “rotate left”, bitmasking does exist.

> 
> > […]
> 
> If people didn't care about performance, we wouldn't have phpng, or
> any of the other work people have done to make the engine faster.
> 
> Sometimes you have to make the most of what you have available.

OK, performance is not unimportant. But in most cases, arbitrary-precision integers are not going to be a bottleneck for your web app.

Also, the bigint changes only affect you if you’re dealing with large integers anyway. If you want to preserve the horrid float promotion behaviour, you can do so explicitly. But I think in most cases, it’s better to trade off performance for lack of data loss.

--
Andrea Faulds
http://ajf.me/

---

## #81718 — Leigh — 2015-02-03T14:59:15+00:00

URL: https://externals.io/message/81706#81718 · In reply to: #81717

> It’s not “broken”, the behaviour is just different to account for it now being an arbitrary-precision type.
>

That's pretty much the definition of a BC issue.

> Also, the bigint changes only affect you if you’re dealing with large integers anyway. If you want to preserve the horrid float promotion behaviour, you can do so explicitly. But I think in most cases, it’s better to trade off performance for lack of data loss.
>

It's not anything to do with float promotion or data loss. If I'm
working with a 64-bit bitmask that gets promoted to bigint when I set
the high bit, it's a performance regression from then on. Not
everything written in PHP is a web app.

---

## #81719 — Andrea Faulds — 2015-02-03T15:02:14+00:00

URL: https://externals.io/message/81706#81719 · In reply to: #81718

> 
> 
> 
> > […]
> 
> That's pretty much the definition of a BC issue.

Sure, it’s a BC break if you’re relying on the undefined behaviour of your platform. Which a lot of people unfortunately were doing.

Actually, this specific case was already broken in PHP 7 after the Integer Semantics RFC passed, which made our bitwise shifts more consistent across platforms.

> > […]
> 
> It's not anything to do with float promotion or data loss. If I'm
> working with a 64-bit bitmask that gets promoted to bigint when I set
> the high bit

Why would it be promoted?! The high bit is the 63rd bit. It fits within a long.

--
Andrea Faulds
http://ajf.me/

---

## #81721 — Leigh — 2015-02-03T15:12:22+00:00

URL: https://externals.io/message/81706#81721 · In reply to: #81719

> Why would it be promoted?! The high bit is the 63rd bit. It fits within a long.
>

I'm assuming your bigint implementation would want to respect signage.

When does it promote? 63rd to preserve signage?

4611686018427387904 // 1 << 62 - int
9223372036854775808 // 1 << 63 - bigint
18446744073709551616 // 1 << 64 - bigint

Or 64th to for complete madness?

4611686018427387904 // 1 << 62 - int
-9223372036854775808 // 1 << 63 - int
18446744073709551616 // 1 << 64 - bigint

---

## #81723 — Andrea Faulds — 2015-02-03T16:08:54+00:00

URL: https://externals.io/message/81706#81723 · In reply to: #81721

> 
> 
> 
> > […]
> 
> I'm assuming your bigint implementation would want to respect signage.
> 
> When does it promote? 63rd to preserve signage?
> 
> 4611686018427387904 // 1 << 62 - int
> 9223372036854775808 // 1 << 63 - bigint
> 18446744073709551616 // 1 << 64 - bigint
> 
> Or 64th to for complete madness?
> 
> 4611686018427387904 // 1 << 62 - int
> -9223372036854775808 // 1 << 63 - int
> 18446744073709551616 // 1 << 64 - bigint

The specific code can be found here:

https://github.com/TazeTSchnitzel/php-src/blob/b91a80879ca3ba269bd239d9c820003c83d0dbc1/Zend/zend_operators.c#L2265

The algorithm is fairly simple: if the number of bits in the long plus the number of bits to shift is greater than the number of bits in a zend_long, then it promotes.

Thus:

$ sapi/cli/php -r '$x = 1 << 62; debug_zval_dump($x);'
long(4611686018427387904)
$ sapi/cli/php -r '$x = 1 << 63; debug_zval_dump($x);'
bigint(9223372036854775808) refcount(2)
$ sapi/cli/php -r '$x = 1 << 64; debug_zval_dump($x);'
bigint(18446744073709551616) refcount(2)

I tried some negative numbers, but I’ve noticed that any left shift on a negative integer promotes - that’s probably because clz is including the high bit... that should probably be fixed, mostly likely by doing clz on its absolute value in that case and factoring in the high bit.
--
Andrea Faulds
http://ajf.me/

---

## #81726 — Leigh — 2015-02-03T16:22:03+00:00

URL: https://externals.io/message/81706#81726 · In reply to: #81723

>
> Why would it be promoted?! The high bit is the 63rd bit. It fits within a long.

because


>
> $ sapi/cli/php -r '$x = 1 << 63; debug_zval_dump($x);'
> bigint(9223372036854775808) refcount(2)

---

## #81728 — Andrea Faulds — 2015-02-03T16:26:13+00:00

URL: https://externals.io/message/81706#81728 · In reply to: #81726

> 
> 
> 
> > […]
> 
> because
> 
> 
> > […]

Yeah, I see your point now, although I’d question *why* you need to mess with the high bit.

You can still do ^ -1 or something as usual, though.
--
Andrea Faulds
http://ajf.me/

---

## #81812 — Dmitry Stogov — 2015-02-04T12:45:40+00:00

URL: https://externals.io/message/81706#81812 · In reply to: #81706

I'm not sure if this is often necessary, but sometimes it may be nice to
have.

Actually, this is "logical right shift" operation (>> is "arithmetic right
shift").
LSHR is a well recognizable name, used in assemblers.
Use T_LSHR instead of T_SHRZF.

Thanks. Dmitry.




> Hi list,
>
> How do we feel about a zero-fill right shift operator?
>
> PHPs current right shift operator preserves signage, but this is not
> always desirable.
>
> I propose the same syntax as JavaScript for this: >>>
>
> php -r 'var_dump(-256 >> 8);'
> int(-1)
>
> php -r 'var_dump(-256 >>> 8);'
> int(16777215)
>
> This will introduce a T_SHRZF token and corresponding opcode. Targeting
> PHP 7.
