summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJin Kyu Song <jin.kyu.song@intel.com>2013-10-30 03:12:45 -0700
committerJin Kyu Song <jin.kyu.song@intel.com>2013-11-20 11:29:42 -0800
commit25c221258641aec4198e9e46127536676878a4bd (patch)
tree3b3435793bd08c7bcbde3dba5b8a6d581ad05863
parent7903c07b7753fb02fc3b5ba6211dc566bc25aa7c (diff)
downloadnasm-25c221258641aec4198e9e46127536676878a4bd.tar.gz
nasm-25c221258641aec4198e9e46127536676878a4bd.tar.bz2
nasm-25c221258641aec4198e9e46127536676878a4bd.zip
match: Check the number of elements in broadcasting operands
The broadcasting decorator {1to##} must describe exactly how many times the memory element is repeated in order to clearly match the correct instruction format. For example, vaddpd zmm30,zmm29,QWORD [rdx+0x3f8]{1to8} ; good vaddpd zmm30,zmm29,QWORD [rdx+0x3f8]{1to16} ; fail qword * 16 = 1024b vaddps zmm30,zmm29,DWORD [rcx]{1to16} ; good vaddps zmm30,zmm29,DWORD [rcx]{1to8} ; fail dword * 8 = 256b Signed-off-by: Jin Kyu Song <jin.kyu.song@intel.com>
-rw-r--r--assemble.c21
-rw-r--r--nasm.h14
-rw-r--r--parser.c3
3 files changed, 36 insertions, 2 deletions
diff --git a/assemble.c b/assemble.c
index a619575..00acd20 100644
--- a/assemble.c
+++ b/assemble.c
@@ -189,6 +189,7 @@ enum match_result {
MERR_INVALOP,
MERR_OPSIZEMISSING,
MERR_OPSIZEMISMATCH,
+ MERR_BRNUMMISMATCH,
MERR_BADCPU,
MERR_BADMODE,
MERR_BADHLE,
@@ -671,6 +672,10 @@ int64_t assemble(int32_t segment, int64_t offset, int bits, iflags_t cp,
case MERR_OPSIZEMISMATCH:
error(ERR_NONFATAL, "mismatch in operand sizes");
break;
+ case MERR_BRNUMMISMATCH:
+ error(ERR_NONFATAL,
+ "mismatch in the number of broadcasting elements");
+ break;
case MERR_BADCPU:
error(ERR_NONFATAL, "no instruction for this cpu level");
break;
@@ -2163,6 +2168,7 @@ static enum match_result matches(const struct itemplate *itemp,
opflags_t type = instruction->oprs[i].type;
decoflags_t deco = instruction->oprs[i].decoflags;
bool is_broadcast = deco & BRDCAST_MASK;
+ uint8_t brcast_num = 0;
opflags_t template_opsize, insn_opsize;
if (!(type & SIZE_MASK))
@@ -2180,13 +2186,16 @@ static enum match_result matches(const struct itemplate *itemp,
if (deco_brsize) {
template_opsize = (deco_brsize == BR_BITS32 ? BITS32 : BITS64);
+ /* calculate the proper number : {1to<brcast_num>} */
+ brcast_num = (itemp->opd[i] & SIZE_MASK) / BITS128 *
+ BITS64 / template_opsize * 2;
} else {
template_opsize = 0;
}
}
if ((itemp->opd[i] & ~type & ~SIZE_MASK) ||
- (itemp->deco[i] & deco) != deco) {
+ (deco & ~itemp->deco[i] & ~BRNUM_MASK)) {
return MERR_INVALOP;
} else if (template_opsize) {
if (template_opsize != insn_opsize) {
@@ -2200,6 +2209,16 @@ static enum match_result matches(const struct itemplate *itemp,
*/
opsizemissing = true;
}
+ } else if (is_broadcast &&
+ (brcast_num !=
+ (8U << ((deco & BRNUM_MASK) >> BRNUM_SHIFT)))) {
+ /*
+ * broadcasting opsize matches but the number of repeated memory
+ * element does not match.
+ * if 64b double precision float is broadcasted to zmm (512b),
+ * broadcasting decorator must be {1to8}.
+ */
+ return MERR_BRNUMMISMATCH;
}
} else if (is_register(instruction->oprs[i].basereg) &&
nasm_regvals[instruction->oprs[i].basereg] >= 16 &&
diff --git a/nasm.h b/nasm.h
index 34adc69..b68a8ba 100644
--- a/nasm.h
+++ b/nasm.h
@@ -1048,6 +1048,7 @@ enum decorator_tokens {
* .........................1...... static rounding
* ........................1....... SAE
* ......................11........ broadcast element size
+ * ....................11.......... number of broadcast elements
*/
#define OP_GENVAL(val, bits, shift) (((val) & ((UINT64_C(1) << (bits)) - 1)) << (shift))
@@ -1119,6 +1120,19 @@ enum decorator_tokens {
#define BR_BITS32 GEN_BRSIZE(0)
#define BR_BITS64 GEN_BRSIZE(1)
+/*
+ * Number of broadcasting elements
+ *
+ * Bits: 10 - 11
+ */
+#define BRNUM_SHIFT (10)
+#define BRNUM_BITS (2)
+#define BRNUM_MASK OP_GENMASK(BRNUM_BITS, BRNUM_SHIFT)
+#define VAL_BRNUM(val) OP_GENVAL(val, BRNUM_BITS, BRNUM_SHIFT)
+
+#define BR_1TO8 VAL_BRNUM(0)
+#define BR_1TO16 VAL_BRNUM(1)
+
#define MASK OPMASK_MASK /* Opmask (k1 ~ 7) can be used */
#define Z Z_MASK
#define B32 (BRDCAST_MASK|BR_BITS32) /* {1to16} : broadcast 32b * 16 to zmm(512b) */
diff --git a/parser.c b/parser.c
index 155308f..343f35e 100644
--- a/parser.c
+++ b/parser.c
@@ -947,7 +947,8 @@ is_expression:
* is expected for memory reference operands
*/
if (tokval.t_flag & TFLAG_BRDCAST) {
- brace_flags |= GEN_BRDCAST(0);
+ brace_flags |= GEN_BRDCAST(0) |
+ VAL_BRNUM(tokval.t_integer - BRC_1TO8);
i = stdscan(NULL, &tokval);
} else if (i == TOKEN_OPMASK) {
brace_flags |= VAL_OPMASK(nasm_regvals[tokval.t_integer]);