diff options
author | H. Peter Anvin <hpa@zytor.com> | 2018-06-25 17:15:08 -0700 |
---|---|---|
committer | H. Peter Anvin <hpa@zytor.com> | 2018-06-25 17:15:08 -0700 |
commit | cd26fccab48bc35465e68d44a7432d1b1cca4d7e (patch) | |
tree | 2a8b7ed835cf9a4271e36dfa600952c7e3004851 | |
parent | 2bf35e0b026d937bbd1c5208c0060e36caacb7cc (diff) | |
download | nasm-cd26fccab48bc35465e68d44a7432d1b1cca4d7e.tar.gz |
asm: support the +n syntax for register sets
Support the +n syntax for multiple contiguous registers, and emit it
in the output from ndisasm as well.
Signed-off-by: H. Peter Anvin (Intel) <hpa@zytor.com>
-rw-r--r-- | asm/assemble.c | 23 | ||||
-rw-r--r-- | asm/parser.c | 30 | ||||
-rw-r--r-- | disasm/disasm.c | 3 | ||||
-rw-r--r-- | include/opflags.h | 20 | ||||
-rw-r--r-- | test/v4.asm | 12 | ||||
-rw-r--r-- | x86/insns.dat | 12 |
6 files changed, 82 insertions, 18 deletions
diff --git a/asm/assemble.c b/asm/assemble.c index a6bb0ee5..7196f911 100644 --- a/asm/assemble.c +++ b/asm/assemble.c @@ -208,6 +208,8 @@ enum match_result { MERR_ENCMISMATCH, MERR_BADBND, MERR_BADREPNE, + MERR_REGSETSIZE, + MERR_REGSET, /* * Matching success; the conditional ones first */ @@ -792,6 +794,12 @@ int64_t assemble(int32_t segment, int64_t start, int bits, insn *instruction) (has_prefix(instruction, PPS_REP, P_REPNE) ? "repne" : "repnz")); break; + case MERR_REGSETSIZE: + nasm_error(ERR_NONFATAL, "invalid register set size"); + break; + case MERR_REGSET: + nasm_error(ERR_NONFATAL, "register set not valid for operand"); + break; default: nasm_error(ERR_NONFATAL, "invalid combination of opcode and operands"); @@ -2162,7 +2170,6 @@ static enum match_result matches(const struct itemplate *itemp, insn *instruction, int bits) { opflags_t size[MAX_OPERANDS], asize; - bool opsizemissing = false; int i, oprs; /* @@ -2323,9 +2330,14 @@ static enum match_result matches(const struct itemplate *itemp, if (~ideco & deco & (Z_MASK|STATICRND_MASK|SAE_MASK)) return MERR_DECONOTHERE; - if (itemp->opd[i] & ~type & ~SIZE_MASK) { + if (itemp->opd[i] & ~type & ~(SIZE_MASK|REGSET_MASK)) return MERR_INVALOP; - } else if (template_opsize) { + + if (~itemp->opd[i] & type & REGSET_MASK) + return (itemp->opd[i] & REGSET_MASK) + ? MERR_REGSETSIZE : MERR_REGSET; + + if (template_opsize) { if (template_opsize != insn_opsize) { if (insn_opsize) { return MERR_INVALOP; @@ -2335,7 +2347,7 @@ static enum match_result matches(const struct itemplate *itemp, * so "missing operand size" for a register should be * considered a wildcard match rather than an error. */ - opsizemissing = true; + return MERR_OPSIZEMISSING; } } else if (is_broadcast && (brcast_num != @@ -2351,9 +2363,6 @@ static enum match_result matches(const struct itemplate *itemp, } } - if (opsizemissing) - return MERR_OPSIZEMISSING; - /* * Check operand sizes */ diff --git a/asm/parser.c b/asm/parser.c index 64d7a024..2643099b 100644 --- a/asm/parser.c +++ b/asm/parser.c @@ -1078,6 +1078,7 @@ is_expression: } } else { /* it's a register */ opflags_t rs; + uint64_t regset_size = 0; if (value->type >= EXPR_SIMPLE || value->value != 1) { nasm_error(ERR_NONFATAL, "invalid operand type"); @@ -1085,13 +1086,32 @@ is_expression: } /* - * check that its only 1 register, not an expression... + * We do not allow any kind of expression, except for + * reg+value in which case it is a register set. */ - for (i = 1; value[i].type; i++) - if (value[i].value) { + for (i = 1; value[i].type; i++) { + if (!value[i].value) + continue; + + switch (value[i].type) { + case EXPR_SIMPLE: + if (!regset_size) { + regset_size = value[i].value + 1; + break; + } + /* fallthrough */ + default: nasm_error(ERR_NONFATAL, "invalid operand type"); goto fail; } + } + + if ((regset_size & (regset_size - 1)) || + regset_size >= (UINT64_C(1) << REGSET_BITS)) { + nasm_error(ERR_NONFATAL | ERR_PASS2, + "invalid register set size"); + regset_size = 0; + } /* clear overrides, except TO which applies to FPU regs */ if (op->type & ~TO) { @@ -1100,12 +1120,14 @@ is_expression: * is different from the register size */ rs = op->type & SIZE_MASK; - } else + } else { rs = 0; + } op->type &= TO; op->type |= REGISTER; op->type |= nasm_reg_flags[value->type]; + op->type |= (regset_size >> 1) << REGSET_SHIFT; op->decoflags |= brace_flags; op->basereg = value->type; diff --git a/disasm/disasm.c b/disasm/disasm.c index a75d839e..fa52d30f 100644 --- a/disasm/disasm.c +++ b/disasm/disasm.c @@ -1431,6 +1431,9 @@ int32_t disasm(uint8_t *data, char *output, int outbufsize, int segsize, slen += snprintf(output + slen, outbufsize - slen, "to "); slen += snprintf(output + slen, outbufsize - slen, "%s", nasm_reg_names[reg-EXPR_REG_START]); + if (t & REGSET_MASK) + slen += snprintf(output + slen, outbufsize - slen, "+%d", + (int)((t & REGSET_MASK) >> (REGSET_SHIFT-1))-1); if (is_evex && deco) slen += append_evex_reg_deco(output + slen, outbufsize - slen, deco, ins.evex_p); diff --git a/include/opflags.h b/include/opflags.h index ef2838c1..469e2b91 100644 --- a/include/opflags.h +++ b/include/opflags.h @@ -1,6 +1,6 @@ /* ----------------------------------------------------------------------- * * - * Copyright 1996-2013 The NASM Authors - All Rights Reserved + * Copyright 1996-2018 The NASM Authors - All Rights Reserved * See the file AUTHORS included with the NASM distribution for * the specific copyright holders. * @@ -118,6 +118,16 @@ #define GEN_SIZE(bit) OP_GENBIT(bit, SIZE_SHIFT) /* + * Register set count + * + * Bits: 47 - 43 + */ +#define REGSET_SHIFT (43) +#define REGSET_BITS (5) +#define REGSET_MASK OP_GENMASK(REGSET_BITS, REGSET_SHIFT) +#define GEN_REGSET(bit) OP_GENBIT(bit, REGSET_SHIFT) + +/* * Bits distribution (counted from 0) * * 6 5 4 3 2 1 @@ -131,6 +141,7 @@ * .......................................11111111................. subclasses * ................................1111111......................... specials * .....................11111111111................................ sizes + * ................11111........................................... regset count */ #define REGISTER GEN_OPTYPE(0) /* register number in 'basereg' */ @@ -268,4 +279,11 @@ #define ZMM0 (GEN_SUBCLASS(1) | GEN_SUBCLASS(6) | ZMMREG) /* ZMM register zero */ #define ZMM_L16 ( GEN_SUBCLASS(6) | ZMMREG) /* ZMM register 0 ~ 15 */ +/* Register set sizes */ +#define RS2 GEN_REGSET(0) +#define RS4 GEN_REGSET(1) +#define RS8 GEN_REGSET(2) +#define RS16 GEN_REGSET(3) +#define RS32 GEN_REGSET(4) + #endif /* NASM_OPFLAGS_H */ diff --git a/test/v4.asm b/test/v4.asm new file mode 100644 index 00000000..a64d3c66 --- /dev/null +++ b/test/v4.asm @@ -0,0 +1,12 @@ + bits 64 + v4fmaddps zmm0,zmm1+3,[rax] + v4fnmaddps zmm2,zmm3,[rax] + v4fmaddss zmm4,zmm5+3,[rax] + v4fnmaddss zmm6,zmm7+3,[rax] + + v4dpwssds zmm8,zmm9,[rax] + v4dpwssd zmm10,zmm11+3,[rax] + v4dpwssd zmm10+0,zmm11+3,[rax] +; v4dpwssd zmm10+1,zmm11+3,[rax] +; v4dpwssd zmm10,zmm11+4,[rax] +; v4dpwssd zmm10,zmm11+7,[rax] diff --git a/x86/insns.dat b/x86/insns.dat index 22af9f5f..af454efc 100644 --- a/x86/insns.dat +++ b/x86/insns.dat @@ -5333,14 +5333,14 @@ VPSHUFBITQMB kreg|mask,ymmreg,ymmrm256 [rvm:fvm: evex.nds.256.66.0f38.w0 8f /r VPSHUFBITQMB kreg|mask,zmmreg,zmmrm512 [rvm:fvm: evex.nds.512.66.0f38.w0 8f /r] AVX512BITALG,FUTURE ;# AVX512 4-iteration Multiply-Add -V4FMADDPS zmmreg|mask|z,zmmreg,mem128 [rvm:m128:evex.dds.512.f2.0f38.w0 9a /r] AVX5124FMAPS,FUTURE -V4FNMADDPS zmmreg|mask|z,zmmreg,mem128 [rvm:m128:evex.dds.512.f2.0f38.w0 9a /r] AVX5124FMAPS,FUTURE -V4FMADDSS zmmreg|mask|z,zmmreg,mem128 [rvm:m128:evex.dds.512.f2.0f38.w0 9b /r] AVX5124FMAPS,FUTURE -V4FNMADDSS zmmreg|mask|z,zmmreg,mem128 [rvm:m128:evex.dds.512.f2.0f38.w0 9b /r] AVX5124FMAPS,FUTURE +V4FMADDPS zmmreg|mask|z,zmmreg|rs4,mem [rvm:m128:evex.dds.512.f2.0f38.w0 9a /r] AVX5124FMAPS,FUTURE,SO +V4FNMADDPS zmmreg|mask|z,zmmreg|rs4,mem [rvm:m128:evex.dds.512.f2.0f38.w0 9a /r] AVX5124FMAPS,FUTURE,SO +V4FMADDSS zmmreg|mask|z,zmmreg|rs4,mem [rvm:m128:evex.dds.512.f2.0f38.w0 9b /r] AVX5124FMAPS,FUTURE,SO +V4FNMADDSS zmmreg|mask|z,zmmreg|rs4,mem [rvm:m128:evex.dds.512.f2.0f38.w0 9b /r] AVX5124FMAPS,FUTURE,SO ;# AVX512 4-iteration Dot Product -V4DPWSSDS zmmreg|mask|z,zmmreg,mem128 [rvm:m128:evex.dds.512.f2.0f38.w0 53 /r] AVX5124VNNIW,FUTURE -V4DPWSSD zmmreg|mask|z,zmmreg,mem128 [rvm:m128:evex.dds.512.f2.0f38.w0 52 /r] AVX5124VNNIW,FUTURE +V4DPWSSDS zmmreg|mask|z,zmmreg|rs4,mem [rvm:m128:evex.dds.512.f2.0f38.w0 53 /r] AVX5124VNNIW,FUTURE,SO +V4DPWSSD zmmreg|mask|z,zmmreg|rs4,mem [rvm:m128:evex.dds.512.f2.0f38.w0 52 /r] AVX5124VNNIW,FUTURE,SO ;# Systematic names for the hinting nop instructions ; These should be last in the file |