summaryrefslogtreecommitdiff
path: root/assemble.c
diff options
context:
space:
mode:
authorJin Kyu Song <jin.kyu.song@intel.com>2013-08-21 19:29:10 -0700
committerCyrill Gorcunov <gorcunov@gmail.com>2013-08-22 19:37:37 +0400
commit4d1fc3f1a0865b82bbf5212cd601c0a4a1495fd6 (patch)
tree669bc601a607b0af7965fee87c0d31424d7ac1e3 /assemble.c
parentf9a71e0c3800092bb1db592de6870e4fe9e83444 (diff)
downloadnasm-4d1fc3f1a0865b82bbf5212cd601c0a4a1495fd6.tar.gz
nasm-4d1fc3f1a0865b82bbf5212cd601c0a4a1495fd6.tar.bz2
nasm-4d1fc3f1a0865b82bbf5212cd601c0a4a1495fd6.zip
AVX-512: Fix instruction match function
When an instruction allows broadcasting, the memory element size is different from the size of normal memory operation. This information is provided in a decoflags field, so it should try to match those properties before it fails. Signed-off-by: Jin Kyu Song <jin.kyu.song@intel.com> Signed-off-by: Cyrill Gorcunov <gorcunov@gmail.com>
Diffstat (limited to 'assemble.c')
-rw-r--r--assemble.c35
1 files changed, 31 insertions, 4 deletions
diff --git a/assemble.c b/assemble.c
index 6054d4a..83971f6 100644
--- a/assemble.c
+++ b/assemble.c
@@ -1915,10 +1915,22 @@ static enum match_result find_match(const struct itemplate **tempp,
enum match_result m, merr;
opflags_t xsizeflags[MAX_OPERANDS];
bool opsizemissing = false;
+ int8_t broadcast = -1;
int i;
+ /* find the position of broadcasting operand */
for (i = 0; i < instruction->operands; i++)
- xsizeflags[i] = instruction->oprs[i].type & SIZE_MASK;
+ if (instruction->oprs[i].decoflags & BRDCAST_MASK) {
+ broadcast = i;
+ break;
+ }
+
+ /* broadcasting uses a different data element size */
+ for (i = 0; i < instruction->operands; i++)
+ if (i == broadcast)
+ xsizeflags[i] = instruction->oprs[i].decoflags & BRSIZE_MASK;
+ else
+ xsizeflags[i] = instruction->oprs[i].type & SIZE_MASK;
merr = MERR_INVALOP;
@@ -1936,7 +1948,10 @@ static enum match_result find_match(const struct itemplate **tempp,
* Missing operand size and a candidate for fuzzy matching...
*/
for (i = 0; i < temp->operands; i++)
- xsizeflags[i] |= temp->opd[i] & SIZE_MASK;
+ if (i == broadcast)
+ xsizeflags[i] |= temp->deco[i] & BRSIZE_MASK;
+ else
+ xsizeflags[i] |= temp->opd[i] & SIZE_MASK;
opsizemissing = true;
}
if (m > merr)
@@ -1962,7 +1977,10 @@ static enum match_result find_match(const struct itemplate **tempp,
if ((xsizeflags[i] & (xsizeflags[i]-1)))
goto done; /* No luck */
- instruction->oprs[i].type |= xsizeflags[i]; /* Set the size */
+ if (i == broadcast)
+ instruction->oprs[i].decoflags |= xsizeflags[i];
+ else
+ instruction->oprs[i].type |= xsizeflags[i]; /* Set the size */
}
/* Try matching again... */
@@ -2107,7 +2125,16 @@ static enum match_result matches(const struct itemplate *itemp,
} else if ((itemp->opd[i] & SIZE_MASK) &&
(itemp->opd[i] & SIZE_MASK) != (type & SIZE_MASK)) {
if (type & SIZE_MASK) {
- return MERR_INVALOP;
+ /*
+ * when broadcasting, the element size depends on
+ * the instruction type. decorator flag should match.
+ */
+#define MATCH_BRSZ(bits) (((type & SIZE_MASK) == BITS##bits) && \
+ ((itemp->deco[i] & BRSIZE_MASK) == BR_BITS##bits))
+ if (!((deco & BRDCAST_MASK) &&
+ (MATCH_BRSZ(32) || MATCH_BRSZ(64)))) {
+ return MERR_INVALOP;
+ }
} else if (!is_class(REGISTER, type)) {
/*
* Note: we don't honor extrinsic operand sizes for registers,