summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorH. Peter Anvin <hpa@zytor.com>2018-06-25 17:15:08 -0700
committerH. Peter Anvin <hpa@zytor.com>2018-06-25 17:15:08 -0700
commitcd26fccab48bc35465e68d44a7432d1b1cca4d7e (patch)
tree2a8b7ed835cf9a4271e36dfa600952c7e3004851
parent2bf35e0b026d937bbd1c5208c0060e36caacb7cc (diff)
downloadnasm-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.c23
-rw-r--r--asm/parser.c30
-rw-r--r--disasm/disasm.c3
-rw-r--r--include/opflags.h20
-rw-r--r--test/v4.asm12
-rw-r--r--x86/insns.dat12
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