diff options
author | Jin Kyu Song <jin.kyu.song@intel.com> | 2013-08-21 19:29:10 -0700 |
---|---|---|
committer | Cyrill Gorcunov <gorcunov@gmail.com> | 2013-08-22 19:37:37 +0400 |
commit | 4d1fc3f1a0865b82bbf5212cd601c0a4a1495fd6 (patch) | |
tree | 669bc601a607b0af7965fee87c0d31424d7ac1e3 /assemble.c | |
parent | f9a71e0c3800092bb1db592de6870e4fe9e83444 (diff) | |
download | nasm-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.c | 35 |
1 files changed, 31 insertions, 4 deletions
@@ -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, |