match: Check the number of elements in broadcasting operands
authorJin Kyu Song <jin.kyu.song@intel.com>
Wed, 30 Oct 2013 10:12:45 +0000 (03:12 -0700)
committerJin Kyu Song <jin.kyu.song@intel.com>
Wed, 20 Nov 2013 19:29:42 +0000 (11:29 -0800)
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>
assemble.c
nasm.h
parser.c

index a619575..00acd20 100644 (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 &&
diff --git a/nasm.h b/nasm.h
index 34adc69..b68a8ba 100644 (file)
--- 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) */
index 155308f..343f35e 100644 (file)
--- a/parser.c
+++ b/parser.c
@@ -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]);