summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJin Kyu Song <jin.kyu.song@intel.com>2013-10-30 03:00:12 -0700
committerJin Kyu Song <jin.kyu.song@intel.com>2013-11-20 11:29:42 -0800
commit7903c07b7753fb02fc3b5ba6211dc566bc25aa7c (patch)
tree314962309dd0a4219af530c9aa2ed615c20d6f0b
parentc9486b965b8883268871aa749f4f617f9835adf2 (diff)
downloadnasm-7903c07b7753fb02fc3b5ba6211dc566bc25aa7c.tar.gz
match: Improve broadcast opsize matching
Broadcasting operand size is different from the original operand size because 32b or 64b element is repeated to form a vector. So when matching a broadcasting operand, opsize should be treated differently. The broadcasting element size is specified in the decorator information. Signed-off-by: Jin Kyu Song <jin.kyu.song@intel.com>
-rw-r--r--assemble.c55
1 files changed, 35 insertions, 20 deletions
diff --git a/assemble.c b/assemble.c
index 100d131a..a6195759 100644
--- a/assemble.c
+++ b/assemble.c
@@ -2020,10 +2020,13 @@ static enum match_result find_match(const struct itemplate **tempp,
if ((xsizeflags[i] & (xsizeflags[i]-1)))
goto done; /* No luck */
- if (i == broadcast)
+ if (i == broadcast) {
instruction->oprs[i].decoflags |= xsizeflags[i];
- else
+ instruction->oprs[i].type |= (xsizeflags[i] == BR_BITS32 ?
+ BITS32 : BITS64);
+ } else {
instruction->oprs[i].type |= xsizeflags[i]; /* Set the size */
+ }
}
/* Try matching again... */
@@ -2159,32 +2162,44 @@ static enum match_result matches(const struct itemplate *itemp,
for (i = 0; i < itemp->operands; i++) {
opflags_t type = instruction->oprs[i].type;
decoflags_t deco = instruction->oprs[i].decoflags;
+ bool is_broadcast = deco & BRDCAST_MASK;
+ opflags_t template_opsize, insn_opsize;
+
if (!(type & SIZE_MASK))
type |= size[i];
+ insn_opsize = type & SIZE_MASK;
+ if (!is_broadcast) {
+ template_opsize = itemp->opd[i] & SIZE_MASK;
+ } else {
+ decoflags_t deco_brsize = itemp->deco[i] & BRSIZE_MASK;
+ /*
+ * when broadcasting, the element size depends on
+ * the instruction type. decorator flag should match.
+ */
+
+ if (deco_brsize) {
+ template_opsize = (deco_brsize == BR_BITS32 ? BITS32 : BITS64);
+ } else {
+ template_opsize = 0;
+ }
+ }
+
if ((itemp->opd[i] & ~type & ~SIZE_MASK) ||
(itemp->deco[i] & deco) != deco) {
return MERR_INVALOP;
- } else if ((itemp->opd[i] & SIZE_MASK) &&
- (itemp->opd[i] & SIZE_MASK) != (type & SIZE_MASK)) {
- if (type & SIZE_MASK) {
- /*
- * 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)))) {
+ } else if (template_opsize) {
+ if (template_opsize != insn_opsize) {
+ if (insn_opsize) {
return MERR_INVALOP;
+ } else if (!is_class(REGISTER, type)) {
+ /*
+ * Note: we don't honor extrinsic operand sizes for registers,
+ * so "missing operand size" for a register should be
+ * considered a wildcard match rather than an error.
+ */
+ opsizemissing = true;
}
- } else if (!is_class(REGISTER, type)) {
- /*
- * Note: we don't honor extrinsic operand sizes for registers,
- * so "missing operand size" for a register should be
- * considered a wildcard match rather than an error.
- */
- opsizemissing = true;
}
} else if (is_register(instruction->oprs[i].basereg) &&
nasm_regvals[instruction->oprs[i].basereg] >= 16 &&