0
0
mirror of https://github.com/netwide-assembler/nasm.git synced 2025-10-10 00:25:06 -04:00

Allow synthesis of ROLX

If the shift amount is known, there is really no reason why we can't
accept "ROLX" as an alias for "RORX" with a modified shift operand.

Signed-off-by: H. Peter Anvin (Intel) <hpa@zytor.com>
This commit is contained in:
H. Peter Anvin
2025-09-13 21:25:02 -07:00
parent 01cef66b23
commit 04c21dc0c5
6 changed files with 43 additions and 0 deletions

View File

@@ -1728,6 +1728,11 @@ static int64_t calcsize(insn *ins, const struct itemplate * const temp)
length++;
break;
case4(0304):
length++;
codes += 2;
break;
case 0310:
{
enum prefixes pfx = ins->prefixes[PPS_ASIZE];
@@ -2840,6 +2845,20 @@ static void gencode(struct out_data *data, insn *ins)
break;
}
case4(0304):
{
uint8_t type = *codes++;
uint8_t modifier = *codes++;
enum out_flags flags = type & 3; /* signed or unsigned */
nasm_assert(type <= 2);
nasm_assert(absolute_op(opx));
warn_overflow_out(opx->offset, 1, flags, "byte");
out_rawbyte(data, opx->offset ^ modifier);
break;
}
case 0310:
case 0311:
break;

View File

@@ -688,12 +688,15 @@ static inline opflags_t set_imm_flags(struct operand *op, enum optimization opt)
op->type |= UNITY|FOURBITS;
if (!strict)
op->type |= SBYTEDWORD|SBYTEWORD|UDWORD|SDWORD;
op->type |= IMM_KNOWN; /* Unknowable in pass 1 */
return op->type;
}
if (!(op->opflags & OPFLAG_SIMPLE))
return op->type;
op->type |= IMM_KNOWN;
if (!strict || !(op->type & SIZE_MASK)) {
if (n == 1)
op->type |= UNITY;

View File

@@ -335,6 +335,7 @@ static inline bool is_reg_class(opflags_t class, int reg)
#define SDWORD (GEN_SUBCLASS(4) | IMMEDIATE) /* operand is in the range -0x80000000..0x7FFFFFFF */
#define UDWORD (GEN_SUBCLASS(5) | IMMEDIATE) /* operand is in the range 0..0xFFFFFFFF */
#define FOURBITS (GEN_SUBCLASS(6) | IMMEDIATE) /* operand is in the range 0-15 */
#define IMM_KNOWN (GEN_SUBCLASS(7) | IMMEDIATE) /* operand value is known at compile time */
#define BYTEEXTMASK (GEN_SUBCLASS(2) | GEN_SUBCLASS(3))
#define DWORDEXTMASK (GEN_SUBCLASS(4) | GEN_SUBCLASS(5))

View File

@@ -104,6 +104,10 @@ t = 0 for VEX (C4/C5), t = 1 for XOP (8F).
\274..\277 ib,s a byte immediate operand, from operand 0..3, sign-extended
to the operand size (if o16/o32/o64 present) or the bit size
\300..\303 ibn a valid 0F NOP opcode.
\304..\307
\0\xNN ib^NN intermediate byte XOR 0xNN
\1\xNN ib,s^NN signed intermediate byte XOR 0xNN
\2\xNN ib,u^NN unsigned intermediate byte XOR 0xNN
\310 a16 indicates fixed 16-bit address size, i.e. optional 0x67.
\311 a32 indicates fixed 32-bit address size, i.e. optional 0x67.
\312 adf, asz (disassembler only) invalid with non-default address size.

View File

@@ -104,12 +104,14 @@ $arith ADD OR ADC SBB AND SUB XOR
$shift ROL ROR RCL RCR SHL,SAL SHR - SAR
$dq RORX reg#,rm#*,imm8 [rmi: vex+.lz.f2.0f3a.w# f0 /r ib] BMI2,SM0-1
$dq ROLX reg#,rm#*,imm_known8 [rmi: vex+.lz.f2.0f3a.w# f0 /r ib^(d:1f/3f)] BMI2,SM0-1
$dq SHLX reg#,rm#*,reg# [rmv: vex+.lz.66.0f38.w# f7 /r] BMI2,SM
$dq SALX reg#,rm#*,reg# [rmv: vex+.lz.66.0f38.w# f7 /r] BMI2,SM,ND
$dq SARX reg#,rm#*,reg# [rmv: vex+.lz.f3.0f38.w# f7 /r] BMI2,SM
$dq SHRX reg#,rm#*,reg# [rmv: vex+.lz.f2.0f38.w# f7 /r] BMI2,SM
$dq ROR reg#,rm#,imm8 [rmi: vex+.lz.f2.0f3a.w# f0 /r ib] BMI2,SM0-1,ND,NF!,OPT
$dq ROL reg#,rm#*,imm_known8 [rmi: vex+.lz.f2.0f3a.w# f0 /r ib^(d:1f/3f)] BMI2,SM0-1,ND,NF!,OPT
$dq SHL reg#,rm#*,reg# [rmv: vex+.lz.66.0f38.w# f7 /r] BMI2,ND,NF!,OPT
$dq SAL reg#,rm#*,reg# [rmv: vex+.lz.66.0f38.w# f7 /r] BMI2,ND,NF!,OPT
$dq SAR reg#,rm#*,reg# [rmv: vex+.lz.f3.0f38.w# f7 /r] BMI2,ND,NF!,OPT

View File

@@ -1556,6 +1556,20 @@ sub byte_code_compile($$$$) {
push(@codes, 05) if ($oppos->{$last_imm} & 4);
push(@codes, $imm_codes{$op} + ($oppos->{$last_imm} & 3));
$prefix_ok = 0;
} elsif ($op =~ /^ib(,[us])?[\^]([0-9a-f]+)$/) {
my $type = $1 eq ',u' ? 2 : $1 eq ',s' ? 1 : 0;
my $mod = hex $2;
$last_imm++;
if ($last_imm gt 'j') {
die "$fname:$line: $opcode: too many immediate operands\n";
}
if (!defined($oppos->{$last_imm})) {
die "$fname:$line: $opcode: $op without '$last_imm' operand\n";
}
push(@codes, 05) if ($oppos->{$last_imm} & 4);
push(@codes, 0304 + ($oppos->{$last_imm} & 3));
push(@codes, $type, $mod);
$flags->{'ND'}++;
} elsif ($op eq '/is4') {
if (!defined($oppos->{'s'})) {
die "$fname:$line: $opcode: $op without 's' operand\n";