mirror of
https://github.com/netwide-assembler/nasm.git
synced 2025-01-18 16:25:05 +08:00
BR3392392: fix broadcast decorators and improve error messages
Checkin c33d95fde9
:
BR 3392370: {z} decorator allowed on MOVDQ* memory operands
... inadvertently broke broadcast operations, which only apply to
memory operands and therefore were only handled in one of the two
brace-parser implementations. Fix that.
Signed-off-by: H. Peter Anvin <hpa@zytor.com>
This commit is contained in:
parent
e886c0e968
commit
8e37ff4ea1
@ -198,7 +198,9 @@ enum match_result {
|
||||
MERR_INVALOP,
|
||||
MERR_OPSIZEMISSING,
|
||||
MERR_OPSIZEMISMATCH,
|
||||
MERR_BRNOTHERE,
|
||||
MERR_BRNUMMISMATCH,
|
||||
MERR_MASKNOTHERE,
|
||||
MERR_BADCPU,
|
||||
MERR_BADMODE,
|
||||
MERR_BADHLE,
|
||||
@ -756,10 +758,18 @@ int64_t assemble(int32_t segment, int64_t start, int bits, insn *instruction)
|
||||
case MERR_OPSIZEMISMATCH:
|
||||
nasm_error(ERR_NONFATAL, "mismatch in operand sizes");
|
||||
break;
|
||||
case MERR_BRNOTHERE:
|
||||
nasm_error(ERR_NONFATAL,
|
||||
"broadcast not permitted on this operand");
|
||||
break;
|
||||
case MERR_BRNUMMISMATCH:
|
||||
nasm_error(ERR_NONFATAL,
|
||||
"mismatch in the number of broadcasting elements");
|
||||
break;
|
||||
case MERR_MASKNOTHERE:
|
||||
nasm_error(ERR_NONFATAL,
|
||||
"mask not permitted on this operand");
|
||||
break;
|
||||
case MERR_BADCPU:
|
||||
nasm_error(ERR_NONFATAL, "no instruction for this cpu level");
|
||||
break;
|
||||
@ -2278,6 +2288,7 @@ static enum match_result matches(const struct itemplate *itemp,
|
||||
for (i = 0; i < itemp->operands; i++) {
|
||||
opflags_t type = instruction->oprs[i].type;
|
||||
decoflags_t deco = instruction->oprs[i].decoflags;
|
||||
decoflags_t ideco = itemp->deco[i];
|
||||
bool is_broadcast = deco & BRDCAST_MASK;
|
||||
uint8_t brcast_num = 0;
|
||||
opflags_t template_opsize, insn_opsize;
|
||||
@ -2289,12 +2300,15 @@ static enum match_result matches(const struct itemplate *itemp,
|
||||
if (!is_broadcast) {
|
||||
template_opsize = itemp->opd[i] & SIZE_MASK;
|
||||
} else {
|
||||
decoflags_t deco_brsize = itemp->deco[i] & BRSIZE_MASK;
|
||||
decoflags_t deco_brsize = ideco & BRSIZE_MASK;
|
||||
|
||||
if (~ideco & BRDCAST_MASK)
|
||||
return MERR_BRNOTHERE;
|
||||
|
||||
/*
|
||||
* when broadcasting, the element size depends on
|
||||
* the instruction type. decorator flag should match.
|
||||
*/
|
||||
|
||||
if (deco_brsize) {
|
||||
template_opsize = (deco_brsize == BR_BITS32 ? BITS32 : BITS64);
|
||||
/* calculate the proper number : {1to<brcast_num>} */
|
||||
@ -2304,8 +2318,10 @@ static enum match_result matches(const struct itemplate *itemp,
|
||||
}
|
||||
}
|
||||
|
||||
if ((itemp->opd[i] & ~type & ~SIZE_MASK) ||
|
||||
(deco & ~itemp->deco[i] & ~BRNUM_MASK)) {
|
||||
if (~ideco & deco & OPMASK_MASK)
|
||||
return MERR_MASKNOTHERE;
|
||||
|
||||
if (itemp->opd[i] & ~type & ~SIZE_MASK) {
|
||||
return MERR_INVALOP;
|
||||
} else if (template_opsize) {
|
||||
if (template_opsize != insn_opsize) {
|
||||
|
60
asm/parser.c
60
asm/parser.c
@ -191,52 +191,56 @@ static void process_size_override(insn *result, operand *op)
|
||||
}
|
||||
|
||||
/*
|
||||
* when two or more decorators follow a register operand,
|
||||
* consecutive decorators are parsed here.
|
||||
* opmask and zeroing decorators can be placed in any order.
|
||||
* e.g. zmm1 {k2}{z} or zmm2 {z}{k3}
|
||||
* decorator(s) are placed at the end of an operand.
|
||||
* Brace decorators are are parsed here. opmask and zeroing
|
||||
* decorators can be placed in any order. e.g. zmm1 {k2}{z} or zmm2
|
||||
* {z}{k3} decorator(s) are placed at the end of an operand.
|
||||
*/
|
||||
static bool parse_braces(decoflags_t *decoflags)
|
||||
{
|
||||
int i;
|
||||
bool recover = false;
|
||||
int i, j;
|
||||
|
||||
i = tokval.t_type;
|
||||
do {
|
||||
if (i == TOKEN_OPMASK) {
|
||||
|
||||
while (true) {
|
||||
switch (i) {
|
||||
case TOKEN_OPMASK:
|
||||
if (*decoflags & OPMASK_MASK) {
|
||||
nasm_error(ERR_NONFATAL, "opmask k%"PRIu64" is already set",
|
||||
nasm_error(ERR_NONFATAL,
|
||||
"opmask k%"PRIu64" is already set",
|
||||
*decoflags & OPMASK_MASK);
|
||||
*decoflags &= ~OPMASK_MASK;
|
||||
}
|
||||
*decoflags |= VAL_OPMASK(nasm_regvals[tokval.t_integer]);
|
||||
} else if (i == TOKEN_DECORATOR) {
|
||||
switch (tokval.t_integer) {
|
||||
break;
|
||||
case TOKEN_DECORATOR:
|
||||
j = tokval.t_integer;
|
||||
switch (j) {
|
||||
case BRC_Z:
|
||||
/*
|
||||
* according to AVX512 spec, only zeroing/merging decorator
|
||||
* is supported with opmask
|
||||
*/
|
||||
*decoflags |= GEN_Z(0);
|
||||
*decoflags |= Z_MASK;
|
||||
break;
|
||||
case BRC_1TO2:
|
||||
case BRC_1TO4:
|
||||
case BRC_1TO8:
|
||||
case BRC_1TO16:
|
||||
*decoflags |= BRDCAST_MASK | VAL_BRNUM(j - BRC_1TO2);
|
||||
break;
|
||||
default:
|
||||
nasm_error(ERR_NONFATAL, "{%s} is not an expected decorator",
|
||||
tokval.t_charptr);
|
||||
nasm_error(ERR_NONFATAL,
|
||||
"{%s} is not an expected decorator",
|
||||
tokval.t_charptr);
|
||||
break;
|
||||
}
|
||||
} else if (i == ',' || i == TOKEN_EOS){
|
||||
break;
|
||||
} else {
|
||||
nasm_error(ERR_NONFATAL, "only a series of valid decorators"
|
||||
" expected");
|
||||
recover = true;
|
||||
break;
|
||||
case ',':
|
||||
case TOKEN_EOS:
|
||||
return false;
|
||||
default:
|
||||
nasm_error(ERR_NONFATAL,
|
||||
"only a series of valid decorators expected");
|
||||
return true;
|
||||
}
|
||||
i = stdscan(NULL, &tokval);
|
||||
} while(1);
|
||||
|
||||
return recover;
|
||||
}
|
||||
}
|
||||
|
||||
static int parse_mref(operand *op, const expr *e)
|
||||
|
@ -4,45 +4,46 @@ NASM = ../nasm
|
||||
NASMOPT = -Ox -I../misc $(OPT)
|
||||
PERL = perl
|
||||
TESTS = $(wildcard *.asm)
|
||||
RM = rm -f
|
||||
|
||||
$(NASM):
|
||||
$(MAKE) -C ..
|
||||
|
||||
%.bin: %.asm $(NASM)
|
||||
$(NASM) $(NASMOPT) -f bin -o $@ -l $*.lst $<
|
||||
$(RM) $*.lst ; $(NASM) $(NASMOPT) -f bin -o $@ -l $*.lst $<
|
||||
|
||||
%.ith: %.asm $(NASM)
|
||||
$(NASM) $(NASMOPT) -f ith -o $@ -l $*.lst $<
|
||||
$(RM) $*.lst ; $(NASM) $(NASMOPT) -f ith -o $@ -l $*.lst $<
|
||||
|
||||
%.srec: %.asm $(NASM)
|
||||
$(NASM) $(NASMOPT) -f srec -o $@ -l $*.lst $<
|
||||
$(RM) $*.lst ; $(NASM) $(NASMOPT) -f srec -o $@ -l $*.lst $<
|
||||
|
||||
%.o: %.asm $(NASM)
|
||||
$(NASM) $(NASMOPT) -f elf32 -o $@ -l $*.lst $<
|
||||
$(RM) $*.lst ; $(NASM) $(NASMOPT) -f elf32 -o $@ -l $*.lst $<
|
||||
|
||||
%.o64: %.asm $(NASM)
|
||||
$(NASM) $(NASMOPT) -f elf64 -o $@ -l $*.lst $<
|
||||
$(RM) $*.lst ; $(NASM) $(NASMOPT) -f elf64 -o $@ -l $*.lst $<
|
||||
|
||||
%.obj: %.asm $(NASM)
|
||||
$(NASM) $(NASMOPT) -f obj -o $@ -l $*.lst $<
|
||||
$(RM) $*.lst ; $(NASM) $(NASMOPT) -f obj -o $@ -l $*.lst $<
|
||||
|
||||
%.coff: %.asm $(NASM)
|
||||
$(NASM) $(NASMOPT) -f coff -o $@ -l $*.lst $<
|
||||
$(RM) $*.lst ; $(NASM) $(NASMOPT) -f coff -o $@ -l $*.lst $<
|
||||
|
||||
%.win32: %.asm $(NASM)
|
||||
$(NASM) $(NASMOPT) -f win32 -o $@ -l $*.lst $<
|
||||
$(RM) $*.lst ; $(NASM) $(NASMOPT) -f win32 -o $@ -l $*.lst $<
|
||||
|
||||
%.win64: %.asm $(NASM)
|
||||
$(NASM) $(NASMOPT) -f win64 -o $@ -l $*.lst $<
|
||||
$(RM) $*.lst ; $(NASM) $(NASMOPT) -f win64 -o $@ -l $*.lst $<
|
||||
|
||||
%.mo32: %.asm $(NASM)
|
||||
$(NASM) $(NASMOPT) -f macho32 -o $@ -l $*.lst $<
|
||||
$(RM) $*.lst ; $(NASM) $(NASMOPT) -f macho32 -o $@ -l $*.lst $<
|
||||
|
||||
%.mo64: %.asm $(NASM)
|
||||
$(NASM) $(NASMOPT) -f macho64 -o $@ -l $*.lst $<
|
||||
$(RM) $*.lst ; $(NASM) $(NASMOPT) -f macho64 -o $@ -l $*.lst $<
|
||||
|
||||
%.dbg: %.asm $(NASM)
|
||||
$(NASM) $(NASMOPT) -f dbg -o $@ -l $*.lst $<
|
||||
$(RM) $*.lst ; $(NASM) $(NASMOPT) -f dbg -o $@ -l $*.lst $<
|
||||
|
||||
%.asm: %.pl
|
||||
$(PERL) $< > $@
|
||||
@ -62,13 +63,13 @@ diff: performtest.pl $(NASM) $(TESTS)
|
||||
$(PERL) performtest.pl --diff --nasm='$(NASM)' $(TESTS)
|
||||
|
||||
clean:
|
||||
rm -f *.com *.o *.o64 *.obj *.win32 *.win64 *.exe *.lst *.bin
|
||||
rm -f *.dbg *.coff *.ith *.srec *.mo32 *.mo64 *.i
|
||||
rm -rf testresults
|
||||
rm -f elftest elftest64
|
||||
$(RM) *.com *.o *.o64 *.obj *.win32 *.win64 *.exe *.lst *.bin
|
||||
$(RM) *.dbg *.coff *.ith *.srec *.mo32 *.mo64 *.i
|
||||
$(RM) -r testresults
|
||||
$(RM) elftest elftest64
|
||||
|
||||
spotless: clean
|
||||
rm -rf golden
|
||||
$(RM) -r golden
|
||||
|
||||
#
|
||||
# Test for ELF32 shared libraries; assumes an x86 Linux system
|
||||
|
15
test/br3392392.asm
Normal file
15
test/br3392392.asm
Normal file
@ -0,0 +1,15 @@
|
||||
bits 64
|
||||
vpaddd zmm0, zmm0, [rax]{1to16}
|
||||
vpaddd zmm2{k3}, zmm0, zmm1
|
||||
vpaddd zmm2 {k3}, zmm0, zmm1
|
||||
vpaddd zmm0{k1}, zmm0, [rax]{1to16}
|
||||
vmovdqa32 [rsi]{k1}, zmm1
|
||||
vmovdqa32 [rsi]{z}, zmm1
|
||||
vmovdqa32 [rsi]{k1}{z}, zmm1
|
||||
vmovdqa32 [rsi]{z}{k1}, zmm1
|
||||
%ifdef ERROR
|
||||
vmovdqa32 [rsi]{z}{1to16}, zmm1
|
||||
vmovdqa32 [rsi]{z}{k1}{1to16}, zmm1
|
||||
vpaddd zmm0, zmm0, [rax]{k1}
|
||||
%endif
|
||||
|
Loading…
Reference in New Issue
Block a user