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>
This commit is contained in:
Jin Kyu Song 2013-10-30 03:12:45 -07:00
parent 7903c07b77
commit 25c2212586
3 changed files with 36 additions and 2 deletions

View File

@ -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 &&

14
nasm.h
View File

@ -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) */

View File

@ -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]);