X-Authentication-Warning: kendall.sfbr.org: jeffw set sender to jeffw AT darwin DOT sfbr DOT org using -f Date: Fri, 8 Jun 2001 10:46:57 -0500 From: JT Williams To: djgpp-workers AT delorie DOT com Subject: patch for djasm.y (double-precision instructions) Message-ID: <20010608104657.A21101@kendall.sfbr.org> Mail-Followup-To: djgpp-workers AT delorie DOT com Mime-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Disposition: inline User-Agent: Mutt/1.2.5i Reply-To: djgpp-workers AT delorie DOT com 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 ARITH2 ARITH2B ARITH2D ARITH2W %token LXS MOVSZX MOVSZXB MOVSZXW %token JCC JCCL JCXZ LOOP SETCC -%token SHIFT SHIFTB SHIFTD SHIFTW +%token SHIFT SHIFTB SHIFTD SHIFTW DPSHIFT %token ONEBYTE TWOBYTE ASCADJ %token 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)