mirror of
https://github.com/netwide-assembler/nasm.git
synced 2024-11-27 08:10:07 +08:00
AVX-512: Add support for parsing braces
AVX-512 introduced new syntax using braces for decorators. Opmask, broadcat, rounding control use this new syntax. http://software.intel.com/sites/default/files/319433-015.pdf Signed-off-by: Jin Kyu Song <jin.kyu.song@intel.com> Signed-off-by: Cyrill Gorcunov <gorcunov@gmail.com>
This commit is contained in:
parent
b775985bee
commit
72018a2b43
4
eval.c
4
eval.c
@ -869,6 +869,7 @@ static expr *expr6(int critical)
|
||||
case TOKEN_INSN: /* Opcodes that occur here are really labels */
|
||||
case TOKEN_HERE:
|
||||
case TOKEN_BASE:
|
||||
case TOKEN_DECORATOR:
|
||||
begintemp();
|
||||
switch (i) {
|
||||
case TOKEN_NUM:
|
||||
@ -938,6 +939,9 @@ static expr *expr6(int critical)
|
||||
if (label_seg != NO_SEG)
|
||||
addtotemp(EXPR_SEGBASE + label_seg, 1L);
|
||||
break;
|
||||
case TOKEN_DECORATOR:
|
||||
addtotemp(EXPR_RDSAE, tokval->t_integer);
|
||||
break;
|
||||
}
|
||||
i = scan(scpriv, tokval);
|
||||
return finishtemp();
|
||||
|
108
nasm.h
108
nasm.h
@ -226,6 +226,8 @@ enum token_type { /* token types, other than chars */
|
||||
TOKEN_FLOATIZE, /* __floatX__ */
|
||||
TOKEN_STRFUNC, /* __utf16*__, __utf32*__ */
|
||||
TOKEN_IFUNC, /* __ilog2*__ */
|
||||
TOKEN_DECORATOR, /* decorators such as {...} */
|
||||
TOKEN_OPMASK, /* translated token for opmask registers */
|
||||
};
|
||||
|
||||
enum floatize {
|
||||
@ -272,6 +274,7 @@ struct tokenval {
|
||||
int64_t t_integer;
|
||||
int64_t t_inttwo;
|
||||
enum token_type t_type;
|
||||
int8_t t_flag;
|
||||
};
|
||||
typedef int (*scanner)(void *private_data, struct tokenval *tv);
|
||||
|
||||
@ -352,11 +355,14 @@ typedef expr *(*evalfunc)(scanner sc, void *scprivate,
|
||||
/*
|
||||
* Special values for expr->type.
|
||||
* These come after EXPR_REG_END as defined in regs.h.
|
||||
* Expr types : 0 ~ EXPR_REG_END, EXPR_UNKNOWN, EXPR_...., EXPR_RDSAE,
|
||||
* EXPR_SEGBASE ~ EXPR_SEGBASE + SEG_ABS, ...
|
||||
*/
|
||||
#define EXPR_UNKNOWN (EXPR_REG_END+1) /* forward references */
|
||||
#define EXPR_SIMPLE (EXPR_REG_END+2)
|
||||
#define EXPR_WRT (EXPR_REG_END+3)
|
||||
#define EXPR_SEGBASE (EXPR_REG_END+4)
|
||||
#define EXPR_RDSAE (EXPR_REG_END+4)
|
||||
#define EXPR_SEGBASE (EXPR_REG_END+5)
|
||||
|
||||
/*
|
||||
* Linked list of strings
|
||||
@ -466,6 +472,14 @@ enum ccode { /* condition code names */
|
||||
C_none = -1
|
||||
};
|
||||
|
||||
/*
|
||||
* token flags
|
||||
*/
|
||||
#define TFLAG_BRC (1 << 0) /* valid only with braces. {1to8}, {rd-sae}, ...*/
|
||||
#define TFLAG_BRC_OPT (1 << 1) /* may or may not have braces. opmasks {k1} */
|
||||
#define TFLAG_BRC_ANY (TFLAG_BRC | TFLAG_BRC_OPT)
|
||||
#define TFLAG_BRDCAST (1 << 2) /* broadcasting decorator */
|
||||
|
||||
static inline uint8_t get_cond_opcode(enum ccode c)
|
||||
{
|
||||
static const uint8_t ccode_opcodes[] = {
|
||||
@ -563,6 +577,7 @@ typedef struct operand { /* operand to an instruction */
|
||||
int32_t wrt; /* segment base it's relative to */
|
||||
int eaflags; /* special EA flags */
|
||||
int opflags; /* see OPFLAG_* defines below */
|
||||
decoflags_t decoflags; /* decorator flags such as {...} */
|
||||
} operand;
|
||||
|
||||
#define OPFLAG_FORWARD 1 /* operand is a forward reference */
|
||||
@ -627,6 +642,7 @@ typedef struct insn { /* an instruction itself */
|
||||
int vexreg; /* Register encoded in VEX prefix */
|
||||
int vex_cm; /* Class and M field for VEX prefix */
|
||||
int vex_wlp; /* W, P and L information for VEX prefix */
|
||||
int evex_rm; /* static rounding mode for AVX3 (EVEX) */
|
||||
} insn;
|
||||
|
||||
enum geninfo { GI_SWITCH };
|
||||
@ -951,6 +967,96 @@ enum special_tokens {
|
||||
SPECIAL_ENUM_LIMIT
|
||||
};
|
||||
|
||||
enum decorator_tokens {
|
||||
DECORATOR_ENUM_START = SPECIAL_ENUM_LIMIT,
|
||||
BRC_1TO8 = DECORATOR_ENUM_START,
|
||||
BRC_1TO16,
|
||||
BRC_RN,
|
||||
BRC_RU,
|
||||
BRC_RD,
|
||||
BRC_RZ,
|
||||
BRC_SAE,
|
||||
BRC_Z,
|
||||
DECORATOR_ENUM_LIMIT
|
||||
};
|
||||
|
||||
/*
|
||||
* AVX512 Decorator (decoflags_t) bits distribution (counted from 0)
|
||||
* 3 2 1
|
||||
* 10987654321098765432109876543210
|
||||
* |
|
||||
* | word boundary
|
||||
* ............................1111 opmask
|
||||
* ...........................1.... zeroing / merging
|
||||
* ..........................1..... broadcast
|
||||
* .........................1...... static rounding
|
||||
* ........................1....... SAE
|
||||
*/
|
||||
|
||||
/*
|
||||
* Opmask register number
|
||||
* identical to EVEX.aaa
|
||||
*
|
||||
* Bits: 0 - 3
|
||||
*/
|
||||
#define OPMASK_SHIFT (0)
|
||||
#define OPMASK_BITS (4)
|
||||
#define OPMASK_MASK OP_GENMASK(OPMASK_BITS, OPMASK_SHIFT)
|
||||
#define GEN_OPMASK(bit) OP_GENBIT(bit, OPMASK_SHIFT)
|
||||
#define VAL_OPMASK(val) OP_GENVAL(val, OPMASK_BITS, OPMASK_SHIFT)
|
||||
|
||||
/*
|
||||
* zeroing / merging control available
|
||||
* matching to EVEX.z
|
||||
*
|
||||
* Bits: 4
|
||||
*/
|
||||
#define Z_SHIFT (4)
|
||||
#define Z_BITS (1)
|
||||
#define Z_MASK OP_GENMASK(Z_BITS, Z_SHIFT)
|
||||
#define GEN_Z(bit) OP_GENBIT(bit, Z_SHIFT)
|
||||
#define VAL_Z(val) OP_GENVAL(val, Z_BITS, Z_SHIFT)
|
||||
|
||||
/*
|
||||
* broadcast - Whether this operand can be broadcasted
|
||||
*
|
||||
* Bits: 5
|
||||
*/
|
||||
#define BRDCAST_SHIFT (5)
|
||||
#define BRDCAST_BITS (1)
|
||||
#define BRDCAST_MASK OP_GENMASK(BRDCAST_BITS, BRDCAST_SHIFT)
|
||||
#define GEN_BRDCAST(bit) OP_GENBIT(bit, BRDCAST_SHIFT)
|
||||
#define VAL_BRDCAST(val) OP_GENVAL(val, BRDCAST_BITS, BRDCAST_SHIFT)
|
||||
|
||||
/*
|
||||
* Whether this instruction can have a static rounding mode.
|
||||
* It goes with the last simd operand because the static rounding mode
|
||||
* decorator is located between the last simd operand and imm8 (if any).
|
||||
*
|
||||
* Bits: 6
|
||||
*/
|
||||
#define STATICRND_SHIFT (6)
|
||||
#define STATICRND_BITS (1)
|
||||
#define STATICRND_MASK OP_GENMASK(STATICRND_BITS, STATICRND_SHIFT)
|
||||
#define GEN_STATICRND(bit) OP_GENBIT(bit, STATICRND_SHIFT)
|
||||
|
||||
/*
|
||||
* SAE(Suppress all exception) available
|
||||
*
|
||||
* Bits: 7
|
||||
*/
|
||||
#define SAE_SHIFT (7)
|
||||
#define SAE_BITS (1)
|
||||
#define SAE_MASK OP_GENMASK(SAE_BITS, SAE_SHIFT)
|
||||
#define GEN_SAE(bit) OP_GENBIT(bit, SAE_SHIFT)
|
||||
|
||||
#define MASK OPMASK_MASK /* Opmask (k1 ~ 7) can be used */
|
||||
#define Z Z_MASK
|
||||
#define B32 BRDCAST_MASK /* {1to16} : load+op instruction can broadcast when it is reg-reg operation */
|
||||
#define B64 BRDCAST_MASK /* {1to8} : There are two definitions just for conforming to SDM */
|
||||
#define ER STATICRND_MASK /* ER(Embedded Rounding) == Static rounding mode */
|
||||
#define SAE SAE_MASK /* SAE(Suppress All Exception) */
|
||||
|
||||
/*
|
||||
* Global modes
|
||||
*/
|
||||
|
21
opflags.h
21
opflags.h
@ -39,6 +39,7 @@
|
||||
#define NASM_OPFLAGS_H
|
||||
|
||||
#include "compiler.h"
|
||||
#include "tables.h" /* for opflags_t and nasm_reg_flags[] */
|
||||
|
||||
/*
|
||||
* Here we define the operand types. These are implemented as bit
|
||||
@ -53,10 +54,9 @@
|
||||
* if and only if "operand" belongs to class type "class".
|
||||
*/
|
||||
|
||||
typedef uint64_t opflags_t;
|
||||
|
||||
#define OP_GENMASK(bits, shift) (((UINT64_C(1) << (bits)) - 1) << (shift))
|
||||
#define OP_GENBIT(bit, shift) (UINT64_C(1) << ((shift) + (bit)))
|
||||
#define OP_GENVAL(val, bits, shift) (((val) & ((UINT64_C(1) << (bits)) - 1)) << (shift))
|
||||
|
||||
/*
|
||||
* Type of operand: memory reference, register, etc.
|
||||
@ -162,11 +162,14 @@ typedef uint64_t opflags_t;
|
||||
#define REG_CLASS_RM_MMX GEN_REG_CLASS(4)
|
||||
#define REG_CLASS_RM_XMM GEN_REG_CLASS(5)
|
||||
#define REG_CLASS_RM_YMM GEN_REG_CLASS(6)
|
||||
#define REG_CLASS_RM_ZMM GEN_REG_CLASS(7)
|
||||
#define REG_CLASS_OPMASK GEN_REG_CLASS(8)
|
||||
|
||||
#define is_class(class, op) (!((opflags_t)(class) & ~(opflags_t)(op)))
|
||||
#define is_class(class, op) (!((opflags_t)(class) & ~(opflags_t)(op)))
|
||||
#define is_reg_class(class, reg) is_class((class), nasm_reg_flags[(reg)])
|
||||
|
||||
#define IS_SREG(op) is_class(REG_SREG, nasm_reg_flags[(op)])
|
||||
#define IS_FSGS(op) is_class(REG_FSGS, nasm_reg_flags[(op)])
|
||||
#define IS_SREG(op) is_reg_class(REG_SREG, (op))
|
||||
#define IS_FSGS(op) is_reg_class(REG_FSGS, (op))
|
||||
|
||||
/* Register classes */
|
||||
#define REG_EA ( REGMEM | REGISTER) /* 'normal' reg, qualifies as EA */
|
||||
@ -186,6 +189,12 @@ typedef uint64_t opflags_t;
|
||||
#define RM_YMM ( REG_CLASS_RM_YMM | REGMEM) /* YMM (AVX) operand */
|
||||
#define YMMREG ( REG_CLASS_RM_YMM | REGMEM | REGISTER) /* YMM (AVX) register */
|
||||
#define YMM0 (GEN_SUBCLASS(1) | REG_CLASS_RM_YMM | REGMEM | REGISTER) /* YMM register zero */
|
||||
#define RM_ZMM ( REG_CLASS_RM_ZMM | REGMEM) /* ZMM (AVX512) operand */
|
||||
#define ZMMREG ( REG_CLASS_RM_ZMM | REGMEM | REGISTER) /* ZMM (AVX512) register */
|
||||
#define ZMM0 (GEN_SUBCLASS(1) | REG_CLASS_RM_ZMM | REGMEM | REGISTER) /* ZMM register zero */
|
||||
#define RM_OPMASK ( REG_CLASS_OPMASK | REGMEM) /* Opmask operand */
|
||||
#define OPMASKREG ( REG_CLASS_OPMASK | REGMEM | REGISTER) /* Opmask register */
|
||||
#define OPMASK0 (GEN_SUBCLASS(1) | REG_CLASS_OPMASK | REGMEM | REGISTER) /* Opmask register zero (k0) */
|
||||
#define REG_CDT ( REG_CLASS_CDT | BITS32 | REGISTER) /* CRn, DRn and TRn */
|
||||
#define REG_CREG (GEN_SUBCLASS(1) | REG_CLASS_CDT | BITS32 | REGISTER) /* CRn */
|
||||
#define REG_DREG (GEN_SUBCLASS(2) | REG_CLASS_CDT | BITS32 | REGISTER) /* DRn */
|
||||
@ -232,7 +241,7 @@ typedef uint64_t opflags_t;
|
||||
#define YMEM (GEN_SUBCLASS(4) | MEMORY) /* 256-bit vector SIB */
|
||||
|
||||
/* memory which matches any type of r/m operand */
|
||||
#define MEMORY_ANY (MEMORY | RM_GPR | RM_MMX | RM_XMM | RM_YMM)
|
||||
#define MEMORY_ANY (MEMORY | RM_GPR | RM_MMX | RM_XMM | RM_YMM | RM_ZMM)
|
||||
|
||||
/* special immediate values */
|
||||
#define UNITY (GEN_SUBCLASS(0) | IMMEDIATE) /* operand equals 1 */
|
||||
|
94
parser.c
94
parser.c
@ -193,6 +193,51 @@ static void process_size_override(insn *result, int operand)
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* when two or more decorators follow a register operand,
|
||||
* consecutive decorators are parsed here.
|
||||
* the order of decorators does not matter.
|
||||
* 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;
|
||||
|
||||
i = tokval.t_type;
|
||||
do {
|
||||
if (i == TOKEN_OPMASK) {
|
||||
if (*decoflags & OPMASK_MASK) {
|
||||
nasm_error(ERR_NONFATAL, "opmask k%lu 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) {
|
||||
case BRC_Z:
|
||||
/*
|
||||
* according to AVX512 spec, only zeroing/merging decorator
|
||||
* is supported with opmask
|
||||
*/
|
||||
*decoflags |= GEN_Z(0);
|
||||
break;
|
||||
}
|
||||
} else if (i == ',' || i == TOKEN_EOS){
|
||||
break;
|
||||
} else {
|
||||
nasm_error(ERR_NONFATAL, "only a series of valid decorators"
|
||||
" expected");
|
||||
recover = true;
|
||||
break;
|
||||
}
|
||||
i = stdscan(NULL, &tokval);
|
||||
} while(1);
|
||||
|
||||
return recover;
|
||||
}
|
||||
|
||||
insn *parse_line(int pass, char *buffer, insn *result, ldfunc ldef)
|
||||
{
|
||||
bool insn_is_label = false;
|
||||
@ -557,10 +602,12 @@ is_expression:
|
||||
int mref; /* is this going to be a memory ref? */
|
||||
int bracket; /* is it a [] mref, or a & mref? */
|
||||
int setsize = 0;
|
||||
decoflags_t brace_flags = 0; /* flags for decorators in braces */
|
||||
|
||||
result->oprs[operand].disp_size = 0; /* have to zero this whatever */
|
||||
result->oprs[operand].eaflags = 0; /* and this */
|
||||
result->oprs[operand].opflags = 0;
|
||||
result->oprs[operand].decoflags = 0;
|
||||
|
||||
i = stdscan(NULL, &tokval);
|
||||
if (i == TOKEN_EOS)
|
||||
@ -702,17 +749,37 @@ is_expression:
|
||||
recover = true;
|
||||
} else { /* we got the required ] */
|
||||
i = stdscan(NULL, &tokval);
|
||||
if (i == TOKEN_DECORATOR) {
|
||||
/*
|
||||
* according to AVX512 spec, only broacast decorator is
|
||||
* expected for memory reference operands
|
||||
*/
|
||||
if (tokval.t_flag & TFLAG_BRDCAST) {
|
||||
brace_flags |= GEN_BRDCAST(0);
|
||||
i = stdscan(NULL, &tokval);
|
||||
} else {
|
||||
nasm_error(ERR_NONFATAL, "broadcast decorator"
|
||||
"expected inside braces");
|
||||
recover = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (i != 0 && i != ',') {
|
||||
nasm_error(ERR_NONFATAL, "comma or end of line expected");
|
||||
recover = true;
|
||||
}
|
||||
}
|
||||
} else { /* immediate operand */
|
||||
if (i != 0 && i != ',' && i != ':') {
|
||||
nasm_error(ERR_NONFATAL, "comma, colon or end of line expected");
|
||||
if (i != 0 && i != ',' && i != ':' &&
|
||||
i != TOKEN_DECORATOR && i != TOKEN_OPMASK) {
|
||||
nasm_error(ERR_NONFATAL, "comma, colon, decorator or end of "
|
||||
"line expected after operand");
|
||||
recover = true;
|
||||
} else if (i == ':') {
|
||||
result->oprs[operand].type |= COLON;
|
||||
} else if (i == TOKEN_DECORATOR || i == TOKEN_OPMASK) {
|
||||
/* parse opmask (and zeroing) after an operand */
|
||||
recover = parse_braces(&brace_flags);
|
||||
}
|
||||
}
|
||||
if (recover) {
|
||||
@ -856,6 +923,7 @@ is_expression:
|
||||
result->oprs[operand].indexreg = i;
|
||||
result->oprs[operand].scale = s;
|
||||
result->oprs[operand].offset = o;
|
||||
result->oprs[operand].decoflags |= brace_flags;
|
||||
} else { /* it's not a memory reference */
|
||||
if (is_just_unknown(value)) { /* it's immediate but unknown */
|
||||
result->oprs[operand].type |= IMMEDIATE;
|
||||
@ -891,6 +959,27 @@ is_expression:
|
||||
result->oprs[operand].type |= SDWORD;
|
||||
}
|
||||
}
|
||||
} else if(value->type == EXPR_RDSAE) {
|
||||
/*
|
||||
* it's not an operand but a rounding or SAE decorator.
|
||||
* put the decorator information in the (opflag_t) type field
|
||||
* of previous operand.
|
||||
*/
|
||||
operand --;
|
||||
switch (value->value) {
|
||||
case BRC_RN:
|
||||
case BRC_RU:
|
||||
case BRC_RD:
|
||||
case BRC_RZ:
|
||||
case BRC_SAE:
|
||||
result->oprs[operand].decoflags |=
|
||||
(value->value == BRC_SAE ? SAE : ER);
|
||||
result->evex_rm = value->value;
|
||||
break;
|
||||
default:
|
||||
nasm_error(ERR_NONFATAL, "invalid decorator");
|
||||
break;
|
||||
}
|
||||
} else { /* it's a register */
|
||||
opflags_t rs;
|
||||
|
||||
@ -923,6 +1012,7 @@ is_expression:
|
||||
result->oprs[operand].type &= TO;
|
||||
result->oprs[operand].type |= REGISTER;
|
||||
result->oprs[operand].type |= nasm_reg_flags[value->type];
|
||||
result->oprs[operand].decoflags |= brace_flags;
|
||||
result->oprs[operand].basereg = value->type;
|
||||
|
||||
if (rs && (result->oprs[operand].type & SIZE_MASK) != rs)
|
||||
|
15
regs.dat
15
regs.dat
@ -36,12 +36,17 @@
|
||||
#
|
||||
# The columns are:
|
||||
#
|
||||
# register name, assembler class, disassembler class(es), x86 register number
|
||||
# register name, assembler class, disassembler class(es), x86 register number[, token flag]
|
||||
#
|
||||
# If the register name ends in two numbers separated by a dash, then it is
|
||||
# repeated as many times as indicated, and the register number is
|
||||
# updated with it.
|
||||
#
|
||||
# If 'token flag' is present, this value will be assigned to tokflag field in
|
||||
# 'struct tokendata tokendata[]' table. Token flag can be used for specifying
|
||||
# special usage of corresponding register. E.g. opmask registers can be either
|
||||
# enclosed by curly braces or standalone operand depending on the usage.
|
||||
#
|
||||
|
||||
# General-purpose registers
|
||||
al REG_AL reg8,reg8_rex 0
|
||||
@ -117,3 +122,11 @@ xmm1-15 XMMREG xmmreg 1
|
||||
# AVX registers
|
||||
ymm0 YMM0 ymmreg 0
|
||||
ymm1-15 YMMREG ymmreg 1
|
||||
|
||||
# AVX3 registers
|
||||
zmm0 ZMM0 zmmreg 0
|
||||
zmm1-31 ZMMREG zmmreg 1
|
||||
|
||||
# Opmask registers
|
||||
k0 OPMASK0 opmaskreg 0
|
||||
k1-7 OPMASKREG opmaskreg 1 TFLAG_BRC_OPT
|
||||
|
2
regs.pl
2
regs.pl
@ -48,7 +48,7 @@ sub process_line($) {
|
||||
my($line) = @_;
|
||||
my @v;
|
||||
|
||||
if ( $line !~ /^\s*(\S+)\s*(\S+)\s*(\S+)\s*([0-9]+)$/i ) {
|
||||
if ( $line !~ /^\s*(\S+)\s*(\S+)\s*(\S+)\s*([0-9]+)\s*(\S*)/i ) {
|
||||
die "regs.dat:$nline: invalid input\n";
|
||||
}
|
||||
$reg = $1;
|
||||
|
94
stdscan.c
94
stdscan.c
@ -53,6 +53,8 @@
|
||||
static char *stdscan_bufptr = NULL;
|
||||
static char **stdscan_tempstorage = NULL;
|
||||
static int stdscan_tempsize = 0, stdscan_templen = 0;
|
||||
static int brace = 0; /* nested brace counter */
|
||||
static bool brace_opened = false; /* if brace is just opened */
|
||||
#define STDSCAN_TEMP_DELTA 256
|
||||
|
||||
void stdscan_set(char *str)
|
||||
@ -105,6 +107,40 @@ static char *stdscan_copy(char *p, int len)
|
||||
return text;
|
||||
}
|
||||
|
||||
/*
|
||||
* a token is enclosed with braces. proper token type will be assigned
|
||||
* accordingly with the token flag.
|
||||
* a closing brace is treated as an ending character of corresponding token.
|
||||
*/
|
||||
static int stdscan_handle_brace(struct tokenval *tv)
|
||||
{
|
||||
if (!(tv->t_flag & TFLAG_BRC_ANY)) {
|
||||
/* invalid token is put inside braces */
|
||||
nasm_error(ERR_NONFATAL,
|
||||
"%s is not a valid decorator with braces", tv->t_charptr);
|
||||
tv->t_type = TOKEN_INVALID;
|
||||
} else if (tv->t_flag & TFLAG_BRC_OPT) {
|
||||
if (is_reg_class(OPMASKREG, tv->t_integer)) {
|
||||
/* within braces, opmask register is now used as a mask */
|
||||
tv->t_type = TOKEN_OPMASK;
|
||||
}
|
||||
}
|
||||
|
||||
stdscan_bufptr = nasm_skip_spaces(stdscan_bufptr);
|
||||
|
||||
if (stdscan_bufptr[0] == '}') {
|
||||
stdscan_bufptr ++; /* skip the closing brace */
|
||||
brace --;
|
||||
} else if (stdscan_bufptr[0] != ',') {
|
||||
/* treat {foo,bar} as {foo}{bar}
|
||||
* by regarding ',' as a mere separator between decorators
|
||||
*/
|
||||
nasm_error(ERR_NONFATAL, "closing brace expected");
|
||||
tv->t_type = TOKEN_INVALID;
|
||||
}
|
||||
return tv->t_type;
|
||||
}
|
||||
|
||||
int stdscan(void *private_data, struct tokenval *tv)
|
||||
{
|
||||
char ourcopy[MAX_KEYWORD + 1], *r, *s;
|
||||
@ -112,14 +148,22 @@ int stdscan(void *private_data, struct tokenval *tv)
|
||||
(void)private_data; /* Don't warn that this parameter is unused */
|
||||
|
||||
stdscan_bufptr = nasm_skip_spaces(stdscan_bufptr);
|
||||
if (!*stdscan_bufptr)
|
||||
if (!*stdscan_bufptr) {
|
||||
/* nested brace shouldn't affect following lines */
|
||||
brace = 0;
|
||||
return tv->t_type = TOKEN_EOS;
|
||||
}
|
||||
|
||||
/* we have a token; either an id, a number or a char */
|
||||
if (isidstart(*stdscan_bufptr) ||
|
||||
(*stdscan_bufptr == '$' && isidstart(stdscan_bufptr[1]))) {
|
||||
(*stdscan_bufptr == '$' && isidstart(stdscan_bufptr[1])) ||
|
||||
(brace && isidchar(*stdscan_bufptr))) { /* because of {1to8} */
|
||||
/* now we've got an identifier */
|
||||
bool is_sym = false;
|
||||
int token_type;
|
||||
|
||||
/* opening brace is followed by any letter */
|
||||
brace_opened = false;
|
||||
|
||||
if (*stdscan_bufptr == '$') {
|
||||
is_sym = true;
|
||||
@ -128,7 +172,8 @@ int stdscan(void *private_data, struct tokenval *tv)
|
||||
|
||||
r = stdscan_bufptr++;
|
||||
/* read the entire buffer to advance the buffer pointer but... */
|
||||
while (isidchar(*stdscan_bufptr))
|
||||
/* {rn-sae}, {rd-sae}, {ru-sae}, {rz-sae} contain '-' in tokens. */
|
||||
while (isidchar(*stdscan_bufptr) || (brace && *stdscan_bufptr == '-'))
|
||||
stdscan_bufptr++;
|
||||
|
||||
/* ... copy only up to IDLEN_MAX-1 characters */
|
||||
@ -143,7 +188,19 @@ int stdscan(void *private_data, struct tokenval *tv)
|
||||
*r = '\0';
|
||||
/* right, so we have an identifier sitting in temp storage. now,
|
||||
* is it actually a register or instruction name, or what? */
|
||||
return nasm_token_hash(ourcopy, tv);
|
||||
token_type = nasm_token_hash(ourcopy, tv);
|
||||
|
||||
if (likely(!brace)) {
|
||||
if (likely(!(tv->t_flag & TFLAG_BRC))) {
|
||||
/* most of the tokens fall into this case */
|
||||
return token_type;
|
||||
} else {
|
||||
return tv->t_type = TOKEN_ID;
|
||||
}
|
||||
} else {
|
||||
/* handle tokens inside braces */
|
||||
return stdscan_handle_brace(tv);
|
||||
}
|
||||
} else if (*stdscan_bufptr == '$' && !isnumchar(stdscan_bufptr[1])) {
|
||||
/*
|
||||
* It's a $ sign with no following hex number; this must
|
||||
@ -267,6 +324,35 @@ int stdscan(void *private_data, struct tokenval *tv)
|
||||
} else if (stdscan_bufptr[0] == '|' && stdscan_bufptr[1] == '|') {
|
||||
stdscan_bufptr += 2;
|
||||
return tv->t_type = TOKEN_DBL_OR;
|
||||
} else if (stdscan_bufptr[0] == '{') {
|
||||
stdscan_bufptr ++; /* skip the opening brace */
|
||||
brace ++; /* in case of nested braces */
|
||||
brace_opened = true; /* brace is just opened */
|
||||
return stdscan(private_data, tv);
|
||||
} else if (stdscan_bufptr[0] == ',' && brace) {
|
||||
/*
|
||||
* a comma inside braces should be treated just as a separator.
|
||||
* this is almost same as an opening brace except increasing counter.
|
||||
*/
|
||||
stdscan_bufptr ++;
|
||||
brace_opened = true; /* brace is just opened */
|
||||
return stdscan(private_data, tv);
|
||||
} else if (stdscan_bufptr[0] == '}') {
|
||||
stdscan_bufptr ++; /* skip the closing brace */
|
||||
if (brace) {
|
||||
/* unhandled nested closing brace */
|
||||
brace --;
|
||||
/* if brace is closed without any content in it */
|
||||
if (brace_opened) {
|
||||
brace_opened = false;
|
||||
nasm_error(ERR_NONFATAL, "nothing inside braces");
|
||||
}
|
||||
return stdscan(private_data, tv);
|
||||
} else {
|
||||
/* redundant closing brace */
|
||||
return tv->t_type = TOKEN_INVALID;
|
||||
}
|
||||
return stdscan(private_data, tv);
|
||||
} else /* just an ordinary char */
|
||||
return tv->t_type = (uint8_t)(*stdscan_bufptr++);
|
||||
}
|
||||
|
3
tables.h
3
tables.h
@ -43,7 +43,6 @@
|
||||
#include "compiler.h"
|
||||
#include <inttypes.h>
|
||||
#include "insnsi.h" /* For enum opcode */
|
||||
#include "opflags.h" /* For opflags_t */
|
||||
|
||||
/* --- From standard.mac via macros.pl: --- */
|
||||
|
||||
@ -62,6 +61,8 @@ extern const char * const nasm_insn_names[];
|
||||
/* regs.c */
|
||||
extern const char * const nasm_reg_names[];
|
||||
/* regflags.c */
|
||||
typedef uint64_t opflags_t;
|
||||
typedef uint8_t decoflags_t;
|
||||
extern const opflags_t nasm_reg_flags[];
|
||||
/* regvals.c */
|
||||
extern const int nasm_regvals[];
|
||||
|
28
tokens.dat
28
tokens.dat
@ -35,7 +35,7 @@
|
||||
# Tokens other than instructions and registers
|
||||
#
|
||||
|
||||
% TOKEN_PREFIX, 0, P_*
|
||||
% TOKEN_PREFIX, 0, 0, P_*
|
||||
a16
|
||||
a32
|
||||
a64
|
||||
@ -55,7 +55,7 @@ wait
|
||||
xacquire
|
||||
xrelease
|
||||
|
||||
% TOKEN_SPECIAL, 0, S_*
|
||||
% TOKEN_SPECIAL, 0, 0, S_*
|
||||
abs
|
||||
byte
|
||||
dword
|
||||
@ -73,13 +73,13 @@ tword
|
||||
word
|
||||
yword
|
||||
|
||||
% TOKEN_FLOAT, 0, 0
|
||||
% TOKEN_FLOAT, 0, 0, 0
|
||||
__infinity__
|
||||
__nan__
|
||||
__qnan__
|
||||
__snan__
|
||||
|
||||
% TOKEN_FLOATIZE, 0, FLOAT_{__float*__}
|
||||
% TOKEN_FLOATIZE, 0, 0, FLOAT_{__float*__}
|
||||
__float8__
|
||||
__float16__
|
||||
__float32__
|
||||
@ -89,7 +89,7 @@ __float80e__
|
||||
__float128l__
|
||||
__float128h__
|
||||
|
||||
% TOKEN_STRFUNC, 0, STRFUNC_{__*__}
|
||||
% TOKEN_STRFUNC, 0, 0, STRFUNC_{__*__}
|
||||
__utf16__
|
||||
__utf16le__
|
||||
__utf16be__
|
||||
@ -97,12 +97,26 @@ __utf32__
|
||||
__utf32le__
|
||||
__utf32be__
|
||||
|
||||
% TOKEN_IFUNC, 0, IFUNC_{__*__}
|
||||
% TOKEN_IFUNC, 0, 0, IFUNC_{__*__}
|
||||
__ilog2e__
|
||||
__ilog2w__
|
||||
__ilog2f__
|
||||
__ilog2c__
|
||||
|
||||
% TOKEN_*, 0, 0
|
||||
% TOKEN_*, 0, 0, 0
|
||||
seg
|
||||
wrt
|
||||
|
||||
% TOKEN_DECORATOR, 0, TFLAG_BRC | TFLAG_BRDCAST , BRC_1TO{1to*}
|
||||
1to8
|
||||
1to16
|
||||
|
||||
% TOKEN_DECORATOR, 0, TFLAG_BRC, BRC_{*-sae}
|
||||
rn-sae
|
||||
rd-sae
|
||||
ru-sae
|
||||
rz-sae
|
||||
|
||||
% TOKEN_DECORATOR, 0, TFLAG_BRC, BRC_*
|
||||
sae
|
||||
z
|
||||
|
17
tokhash.pl
17
tokhash.pl
@ -65,14 +65,14 @@ while (defined($line = <ID>)) {
|
||||
# Single instruction token
|
||||
if (!defined($tokens{$token})) {
|
||||
$tokens{$token} = scalar @tokendata;
|
||||
push(@tokendata, "\"${token}\", TOKEN_INSN, C_none, I_${insn}");
|
||||
push(@tokendata, "\"${token}\", TOKEN_INSN, C_none, 0, I_${insn}");
|
||||
}
|
||||
} else {
|
||||
# Conditional instruction
|
||||
foreach $cc (@conditions) {
|
||||
if (!defined($tokens{$token.$cc})) {
|
||||
$tokens{$token.$cc} = scalar @tokendata;
|
||||
push(@tokendata, "\"${token}${cc}\", TOKEN_INSN, C_\U$cc\E, I_${insn}");
|
||||
push(@tokendata, "\"${token}${cc}\", TOKEN_INSN, C_\U$cc\E, 0, I_${insn}");
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -85,8 +85,9 @@ close(ID);
|
||||
#
|
||||
open(RD, "< ${regs_dat}") or die "$0: cannot open $regs_dat: $!\n";
|
||||
while (defined($line = <RD>)) {
|
||||
if ($line =~ /^([a-z0-9_-]+)\s/) {
|
||||
if ($line =~ /^([a-z0-9_-]+)\s*\S+\s*\S+\s*[0-9]+\s*(\S*)/) {
|
||||
$reg = $1;
|
||||
$reg_flag = $2;
|
||||
|
||||
if ($reg =~ /^(.*[^0-9])([0-9]+)\-([0-9]+)(|[^0-9].*)$/) {
|
||||
$nregs = $3-$2+1;
|
||||
@ -104,7 +105,11 @@ while (defined($line = <RD>)) {
|
||||
die "Duplicate definition: $reg\n";
|
||||
}
|
||||
$tokens{$reg} = scalar @tokendata;
|
||||
push(@tokendata, "\"${reg}\", TOKEN_REG, 0, R_\U${reg}\E");
|
||||
if ($reg_flag eq '') {
|
||||
push(@tokendata, "\"${reg}\", TOKEN_REG, 0, 0, R_\U${reg}\E");
|
||||
} else {
|
||||
push(@tokendata, "\"${reg}\", TOKEN_REG, 0, ${reg_flag}, R_\U${reg}\E");
|
||||
}
|
||||
|
||||
if (defined($reg_prefix)) {
|
||||
$reg_nr++;
|
||||
@ -214,7 +219,8 @@ if ($output eq 'h') {
|
||||
print "struct tokendata {\n";
|
||||
print " const char *string;\n";
|
||||
print " int16_t tokentype;\n";
|
||||
print " int16_t aux;\n";
|
||||
print " int8_t aux;\n";
|
||||
print " int8_t tokflag;\n";
|
||||
print " int32_t num;\n";
|
||||
print "};\n";
|
||||
print "\n";
|
||||
@ -270,6 +276,7 @@ if ($output eq 'h') {
|
||||
print "\n";
|
||||
print " tv->t_integer = data->num;\n";
|
||||
print " tv->t_inttwo = data->aux;\n";
|
||||
print " tv->t_flag = data->tokflag;\n";
|
||||
print " return tv->t_type = data->tokentype;\n";
|
||||
print "}\n";
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user