diff options
author | Jin Kyu Song <jin.kyu.song@intel.com> | 2013-10-30 03:12:45 -0700 |
---|---|---|
committer | Jin Kyu Song <jin.kyu.song@intel.com> | 2013-11-20 11:29:42 -0800 |
commit | 25c221258641aec4198e9e46127536676878a4bd (patch) | |
tree | 3b3435793bd08c7bcbde3dba5b8a6d581ad05863 | |
parent | 7903c07b7753fb02fc3b5ba6211dc566bc25aa7c (diff) | |
download | nasm-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.c | 21 | ||||
-rw-r--r-- | nasm.h | 14 | ||||
-rw-r--r-- | parser.c | 3 |
3 files changed, 36 insertions, 2 deletions
@@ -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 && @@ -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) */ @@ -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]); |