diff options
author | cinap_lenrek <cinap_lenrek@felloff.net> | 2016-09-03 17:11:38 +0200 |
---|---|---|
committer | cinap_lenrek <cinap_lenrek@felloff.net> | 2016-09-03 17:11:38 +0200 |
commit | b46a0e97ea5ec8666924ec34a6fa1cd86f899fcc (patch) | |
tree | f7a7cc70d1d4c6b772ef4c834dc5bdf6ab96fb74 /sys/src/cmd/5a | |
parent | 607f3bc55c2425c7e7d022961517793eb20f3b74 (diff) |
5a: assemble constant >>0 right shifts as <<0 (no shift), allow >>32
previously, right shift >>0 resulted in >>32 being emited. this
is especially problematic when the shift count comes from a macro
expansion.
we now handle constant shift >>0 as <<0 (no shift) and allow
shift by 32 be specified.
this applies to logical right shift (>>) arithmetic right shift (->)
and right rotate (@>).
Diffstat (limited to 'sys/src/cmd/5a')
-rw-r--r-- | sys/src/cmd/5a/a.y | 21 |
1 files changed, 14 insertions, 7 deletions
diff --git a/sys/src/cmd/5a/a.y b/sys/src/cmd/5a/a.y index 7ef969ca0..ba877a5b6 100644 --- a/sys/src/cmd/5a/a.y +++ b/sys/src/cmd/5a/a.y @@ -469,27 +469,34 @@ regreg: shift: spreg '<' '<' rcon { + nullshift: $$ = nullgen; $$.type = D_SHIFT; - $$.offset = $1 | $4 | (0 << 5); + $$.offset = $1 | ($4 & ~(32<<7)) | (0 << 5); } | spreg '>' '>' rcon { + if($4 == 0) + goto nullshift; $$ = nullgen; $$.type = D_SHIFT; - $$.offset = $1 | $4 | (1 << 5); + $$.offset = $1 | ($4 & ~(32<<7)) | (1 << 5); } | spreg '-' '>' rcon { + if($4 == 0) + goto nullshift; $$ = nullgen; $$.type = D_SHIFT; - $$.offset = $1 | $4 | (2 << 5); + $$.offset = $1 | ($4 & ~(32<<7)) | (2 << 5); } | spreg LAT '>' rcon { + if($4 == 0) + goto nullshift; $$ = nullgen; $$.type = D_SHIFT; - $$.offset = $1 | $4 | (3 << 5); + $$.offset = $1 | ($4 & ~(32<<7)) | (3 << 5); } rcon: @@ -497,13 +504,13 @@ rcon: { if($$ < 0 || $$ >= 16) print("register value out of range\n"); - $$ = (($1&15) << 8) | (1 << 4); + $$ = ($1 << 8) | (1 << 4); } | con { - if($$ < 0 || $$ >= 32) + if($$ < 0 || $$ > 32) print("shift value out of range\n"); - $$ = ($1&31) << 7; + $$ = ($1 << 7); } sreg: |