From 4b5b1cbc6a9b00a9062a6c2333ea052d8785584b Mon Sep 17 00:00:00 2001 From: Jin Kyu Song Date: Wed, 30 Oct 2013 03:12:45 -0700 Subject: [PATCH] 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 --- assemble.c | 21 ++++++++++++++++++++- nasm.h | 14 ++++++++++++++ parser.c | 3 ++- 3 files changed, 36 insertions(+), 2 deletions(-) diff --git a/assemble.c b/assemble.c index afc5457f..6aeb9a21 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 = (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 34adc69b..b68a8ba8 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 7112781c..9a54ce67 100644 --- a/parser.c +++ b/parser.c @@ -946,7 +946,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]); -- 2.11.4.GIT