Mail Archives: djgpp-workers/2001/06/08/11:44:03
Below is the last patch currently in the queue for djasm.y.
This patch (re-)implements the double-precision shift instructions, and
traps any obsolete usage of `sh[lr]d' to denote double-precision shifts.
(Recall, `sh[lr]d' are now the mnemonics for basic left/right shifts of a
double-word operand.) For example, here are some (obsolete) instructions
and the resulting error messages:
shld ax,bx,4
shrd ax,bx,4
shld eax,ebx,4
shrd eax,ebx,4
% djasm shifty.asm shifty.exe shifty.map
shifty.asm:11: Obsolete use of `shld' detected. Use `dshl' instead.
shifty.asm:12: Obsolete use of `shrd' detected. Use `dshr' instead.
shifty.asm:19: Obsolete use of `shld' detected. Use `dshl' instead.
shifty.asm:20: Obsolete use of `shrd' detected. Use `dshr' instead.
shifty.asm: 4 errors
Documentation patches can be finalized and committed when the final form
of this patch is known.
This patch is a considerably simplified implementation of Bill Currie's
original scheme for double-precision shifts. Bill used the mnemonics
`sh[lr]d[dq]', interpreted as follows:
sh [sh]ift
lr [l]eft/[r]ight
d [d]ouble-precision
dq [d]ouble-word operands/[q]uad-word (double double-word) operands
I have two problems with this:
(1) the double-precision shifts are *not* equivalent to shifts of a
double-wide operand. See the Intel documentation, or confirm this using
small test programs (I did both). Therefore the `d' and `q' suffixes
are IMHO misleading, because they suggest monolithic shifts of 32- and
64-bit operands.
(2) the double-precision shift instructions do *not* require a suffix
to denote the operand size. Further explanation is given in the patch.
For our implementation, I chose the mnemonics `dsh[lr]'.
(I didn't plan it this way, but it turns out that *if* anyone ever did
use `shld' or `shrd' for a double-precision shift, all they have to do
is rewrite these instructions as `dshl' or `dshr'.)
--- djasm.y.old Thu May 24 16:46:49 2001
+++ djasm.y Fri Jun 8 10:01:57 2001
@@ -36,6 +36,7 @@
void djerror(char *s);
void yyerror(char *s);
+void shd_error(int opcode, int b32);
#define OUT_exe 0
#define OUT_com 1
@@ -230,7 +231,7 @@
%token <i> ARITH2 ARITH2B ARITH2D ARITH2W
%token <i> LXS MOVSZX MOVSZXB MOVSZXW
%token <i> JCC JCCL JCXZ LOOP SETCC
-%token <i> SHIFT SHIFTB SHIFTD SHIFTW
+%token <i> SHIFT SHIFTB SHIFTD SHIFTW DPSHIFT
%token <i> ONEBYTE TWOBYTE ASCADJ
%token <i> BITTEST GROUP3 GROUP3B GROUP3D GROUP3W GROUP6 GROUP7 STRUCT
%token ALIGN ARPL
@@ -592,10 +593,12 @@
{"shlb", SHIFTB, 4},
{"shld", SHIFTD, 4},
{"shlw", SHIFTW, 4},
+ {"dshl", DPSHIFT, 0xa4},
{"shr", SHIFT, 5},
{"shrb", SHIFTB, 5},
{"shrd", SHIFTD, 5},
{"shrw", SHIFTW, 5},
+ {"dshr", DPSHIFT, 0xac},
{"smsw", GROUP7, 4},
{"str", GROUP6, 1},
{"sub", ARITH2, 5},
@@ -1031,6 +1034,7 @@
| SETCC REG8 { emitb(0x0f); emitb(0x90+$1); modrm(3, 0, $2); }
| SETCC regmem { emitb(0x0f); emitb(0x90+$1); reg(0); }
+ /* basic shift of byte/word/double operand */
| SHIFT REG8 ',' const { emitb($4 == 1 ? 0xd0 : 0xc0); modrm(3, $1, $2); if ($4 != 1) emitb($4); }
| SHIFT REG8 ',' REG8 { if ($4 != 1) djerror ("Non-constant shift count must be `cl'"); emitb(0xd2); modrm(3, $1, $2); }
| SHIFTB regmem ',' const { emitb($4 == 1 ? 0xd0 : 0xc0); reg($1); if ($4 != 1) emitb($4); }
@@ -1044,6 +1048,40 @@
| SHIFTD regmem ',' const { emitb(0x66); emitb($4 == 1 ? 0xd1 : 0xc1); reg($1); if ($4 != 1) emitb($4); }
| SHIFTD regmem ',' REG8 { if ($4 != 1) djerror ("Non-constant shift count must be `cl'"); emitb(0x66); emitb(0xd3); reg($1); }
+ /* Trap any use of `sh[lr]d' to denote a double-precision shift.
+ This trap is not strictly necessary, because writing `sh[lr]d'
+ with three operands would generate a parse error anyway. However,
+ there _was_ a time when djasm did use `sh[lr]d' as the mnemonics
+ for the double-precision shifts. This usage was later removed
+ (it interfered with subsequent implementation of the basic shift
+ instructions). (jtw) */
+
+ | SHIFTD REG16 ',' REG16 ',' const { shd_error($1,0); }
+ | SHIFTD REG16 ',' REG16 ',' REG8 { shd_error($1,0); }
+ | SHIFTD regmem ',' REG16 ',' const { shd_error($1,0); }
+ | SHIFTD regmem ',' REG16 ',' REG8 { shd_error($1,0); }
+ | SHIFTD REG32 ',' REG32 ',' const { shd_error($1,1); }
+ | SHIFTD REG32 ',' REG32 ',' REG8 { shd_error($1,1); }
+ | SHIFTD regmem ',' REG32 ',' const { shd_error($1,1); }
+ | SHIFTD regmem ',' REG32 ',' REG8 { shd_error($1,1); }
+
+ /* These double-precision shift instructions do *not* require an
+ operand-size suffix. The size of the memory operand must agree
+ with the size of the register, hence the allowable combinations
+ of operands are completely unambiguous. (jtw) */
+
+ /* 16-bit double-precision shift */
+ | DPSHIFT REG16 ',' REG16 ',' const { emitb(0x0f); emitb($1); modrm(3, $4, $2); emitb($6); }
+ | DPSHIFT REG16 ',' REG16 ',' REG8 { if ($6 != 1) djerror ("Non-constant shift count must be `cl'"); emitb(0x0f); emitb($1+1); modrm(3, $4, $2); }
+ | DPSHIFT regmem ',' REG16 ',' const { emitb(0x0f); emitb($1); reg($4); emitb($6); }
+ | DPSHIFT regmem ',' REG16 ',' REG8 { if ($6 != 1) djerror ("Non-constant shift count must be `cl'"); emitb(0x0f); emitb($1+1); reg($4); }
+
+ /* 32-bit double-precision shift */
+ | DPSHIFT REG32 ',' REG32 ',' const { emitb(0x66); emitb(0x0f); emitb($1); modrm(3, $4, $2); emitb($6); }
+ | DPSHIFT REG32 ',' REG32 ',' REG8 { if ($6 != 1) djerror ("Non-constant shift count must be `cl'"); emitb(0x66); emitb(0x0f); emitb($1+1); modrm(3, $4, $2); }
+ | DPSHIFT regmem ',' REG32 ',' const { emitb(0x66); emitb(0x0f); emitb($1); reg($4); emitb($6); }
+ | DPSHIFT regmem ',' REG32 ',' REG8 { if ($6 != 1) djerror ("Non-constant shift count must be `cl'"); emitb(0x66); emitb(0x0f); emitb($1+1); reg($4); }
+
| STACK { stack_ptr = pc; }
| START { start_ptr = pc; main_obj=1; }
@@ -1628,6 +1666,35 @@
{
djerror(s);
fprintf(stderr, "%s:%d: Last token was `%s' (%s)\n", inname, lineno, last_token, yytname[(unsigned char)yytranslate[last_tret]]);
+}
+
+void
+shd_error(int opcode, int b32)
+{
+ char *bad_op;
+ char *good_op;
+ char msg[80];
+
+ if (opcode == 4)
+ {
+ bad_op = "`shld'";
+ good_op = "`dshl'";
+ /* good_op = b32 ? "`shldd' or `shldq'" : "`shldd'"; */
+ }
+ else
+ {
+ bad_op = "`shrd'";
+ good_op = "`dshr'";
+ /* good_op = b32 ? "`shrdd' or `shrdq'" : "`shrdd'"; */
+ }
+ sprintf(msg, "Obsolete use of %s detected. Use %s instead.", bad_op, good_op);
+ djerror(msg);
+/*
+ sprintf(msg, "Attempted obsolete use of %s detected.", bad_op);
+ djerror(msg);
+ sprintf(msg, "Use %s instead.", good_op);
+ djerror(msg);
+*/
}
Symbol *get_symbol(char *name, int create)
- Raw text -