Skip to content

Commit 42d4840

Browse files
authored
[X86][MC] Support encoding/decoding for JMPABS (#72835)
JMPABS is a 64-bit only ISA extension, and acts as a near-direct branch with an absolute target. The 64-bit immediate operand is treated an as absolute effective address, which is subject to canonicality checks. It is in legacy map 0 and requires REX2 prefix with `REX2.M0=0` and `REX2.W=0`. All other REX2 payload bits are ignored. blog: https://kanrobert.github.io/rfc/All-about-APX-JMPABS/ This patch 1. Extends `ExplicitVEXPrefix` to `ExplicitOpPrefix` for instrcutions requires explicit `REX2` or `EVEX` 2. Adds `ATTR_REX2` and `IC_64BIT_REX2` to put `JMPABS` , `MOV EAX, moffs32` in different tables to avoid opcode conflict NOTE: 1. `ExplicitREX2Prefix` can be reused by the following PUSHP/POPP instructions. 2. `ExplicitEVEXPrefix` will be used by the instructions promoted to EVEX space for EGPR.
1 parent 3311112 commit 42d4840

File tree

14 files changed

+79
-10
lines changed

14 files changed

+79
-10
lines changed

llvm/include/llvm/Support/X86DisassemblerDecoderCommon.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,8 @@ enum attributeBits {
6767
ATTR_EVEXK = 0x1 << 10,
6868
ATTR_EVEXKZ = 0x1 << 11,
6969
ATTR_EVEXB = 0x1 << 12,
70-
ATTR_max = 0x1 << 13,
70+
ATTR_REX2 = 0x1 << 13,
71+
ATTR_max = 0x1 << 14,
7172
};
7273

7374
// Combinations of the above attributes that are relevant to instruction
@@ -118,6 +119,7 @@ enum attributeBits {
118119
ENUM_ENTRY(IC_64BIT_REXW_OPSIZE, 8, "The Dynamic Duo! Prefer over all " \
119120
"else because this changes most " \
120121
"operands' meaning") \
122+
ENUM_ENTRY(IC_64BIT_REX2, 2, "requires a REX2 prefix") \
121123
ENUM_ENTRY(IC_VEX, 1, "requires a VEX prefix") \
122124
ENUM_ENTRY(IC_VEX_XS, 2, "requires VEX and the XS prefix") \
123125
ENUM_ENTRY(IC_VEX_XD, 2, "requires VEX and the XD prefix") \

llvm/lib/Target/X86/AsmParser/X86AsmParser.cpp

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3974,7 +3974,6 @@ unsigned X86AsmParser::checkTargetMatchPredicate(MCInst &Inst) {
39743974
(MCID.TSFlags & X86II::EncodingMask) != X86II::VEX)
39753975
return Match_Unsupported;
39763976

3977-
// These instructions are only available with {vex}, {vex2} or {vex3} prefix
39783977
if (MCID.TSFlags & X86II::ExplicitVEXPrefix &&
39793978
(ForcedVEXEncoding != VEXEncoding_VEX &&
39803979
ForcedVEXEncoding != VEXEncoding_VEX2 &&

llvm/lib/Target/X86/Disassembler/X86Disassembler.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1257,6 +1257,11 @@ static int getInstructionID(struct InternalInstruction *insn,
12571257
attrMask &= ~ATTR_ADSIZE;
12581258
}
12591259

1260+
// Absolute jump need special handling
1261+
if (insn->rex2ExtensionPrefix[0] == 0xd5 && insn->opcodeType == ONEBYTE &&
1262+
insn->opcode == 0xA1)
1263+
attrMask |= ATTR_REX2;
1264+
12601265
if (insn->mode == MODE_16BIT) {
12611266
// JCXZ/JECXZ need special handling for 16-bit mode because the meaning
12621267
// of the AdSize prefix is inverted w.r.t. 32-bit mode.

llvm/lib/Target/X86/MCTargetDesc/X86BaseInfo.h

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -966,9 +966,16 @@ namespace X86II {
966966
NoTrackShift = EVEX_RCShift + 1,
967967
NOTRACK = 1ULL << NoTrackShift,
968968

969-
// Force VEX encoding
970-
ExplicitVEXShift = NoTrackShift + 1,
971-
ExplicitVEXPrefix = 1ULL << ExplicitVEXShift
969+
// Force REX2/VEX/EVEX encoding
970+
ExplicitOpPrefixShift = NoTrackShift + 1,
971+
// For instructions that require REX2 prefix even if EGPR is not used.
972+
ExplicitREX2Prefix = 1ULL << ExplicitOpPrefixShift,
973+
// For instructions that use VEX encoding only when {vex}, {vex2} or {vex3}
974+
// is present.
975+
ExplicitVEXPrefix = 2ULL << ExplicitOpPrefixShift,
976+
// For instructions that are promoted to EVEX space for EGPR.
977+
ExplicitEVEXPrefix = 3ULL << ExplicitOpPrefixShift,
978+
ExplicitOpPrefixMask = 3ULL << ExplicitOpPrefixShift
972979
};
973980

974981
/// \returns true if the instruction with given opcode is a prefix.

llvm/lib/Target/X86/MCTargetDesc/X86MCCodeEmitter.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1305,6 +1305,8 @@ PrefixKind X86MCCodeEmitter::emitREXPrefix(int MemOperand, const MCInst &MI,
13051305
}
13061306
}
13071307
}
1308+
if ((TSFlags & X86II::ExplicitOpPrefixMask) == X86II::ExplicitREX2Prefix)
1309+
Prefix.setLowerBound(REX2);
13081310
switch (TSFlags & X86II::FormMask) {
13091311
default:
13101312
assert(!HasRegOp && "Unexpected form in emitREXPrefix!");

llvm/lib/Target/X86/X86InstrControl.td

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -188,6 +188,9 @@ let isBranch = 1, isTerminator = 1, isBarrier = 1, isIndirectBranch = 1 in {
188188
}
189189
}
190190

191+
def JMPABS64i : Ii64<0xA1, RawFrm, (outs), (ins i64imm:$dst), "jmpabs\t$dst", []>,
192+
ExplicitREX2Prefix, Requires<[In64BitMode]>, Sched<[WriteJumpLd]>;
193+
191194
// Loop instructions
192195
let isBranch = 1, isTerminator = 1, SchedRW = [WriteJump] in {
193196
def LOOP : Ii8PCRel<0xE2, RawFrm, (outs), (ins brtarget8:$dst), "loop\t$dst", []>;

llvm/lib/Target/X86/X86InstrFormats.td

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -271,8 +271,17 @@ class EVEX2VEXOverride<string VEXInstrName> {
271271
// Prevent EVEX->VEX conversion from considering this instruction.
272272
class NotEVEX2VEXConvertible { bit notEVEX2VEXConvertible = 1; }
273273

274-
// Force the instruction to use VEX encoding.
275-
class ExplicitVEXPrefix { bit ExplicitVEXPrefix = 1; }
274+
// Force the instruction to use REX2/VEX/EVEX encoding.
275+
class ExplicitOpPrefix<bits<2> val> {
276+
bits<2> Value = val;
277+
}
278+
def NoExplicitOpPrefix : ExplicitOpPrefix<0>;
279+
def ExplicitREX2 : ExplicitOpPrefix<1>;
280+
def ExplicitVEX : ExplicitOpPrefix<2>;
281+
def ExplicitEVEX : ExplicitOpPrefix<3>;
282+
class ExplicitREX2Prefix { ExplicitOpPrefix explicitOpPrefix = ExplicitREX2; }
283+
class ExplicitVEXPrefix { ExplicitOpPrefix explicitOpPrefix = ExplicitVEX; }
284+
class ExplicitEVEXPrefix { ExplicitOpPrefix explicitOpPrefix = ExplicitEVEX; }
276285

277286
class X86Inst<bits<8> opcod, Format f, ImmType i, dag outs, dag ins,
278287
string AsmStr, Domain d = GenericDomain>
@@ -354,7 +363,8 @@ class X86Inst<bits<8> opcod, Format f, ImmType i, dag outs, dag ins,
354363
string EVEX2VEXOverride = ?;
355364

356365
bit notEVEX2VEXConvertible = 0; // Prevent EVEX->VEX conversion.
357-
bit ExplicitVEXPrefix = 0; // Force the instruction to use VEX encoding.
366+
ExplicitOpPrefix explicitOpPrefix = NoExplicitOpPrefix;
367+
bits<2> explicitOpPrefixBits = explicitOpPrefix.Value;
358368
// Force to check predicate before compress EVEX to VEX encoding.
359369
bit checkVEXPredicate = 0;
360370
// TSFlags layout should be kept in sync with X86BaseInfo.h.
@@ -381,7 +391,7 @@ class X86Inst<bits<8> opcod, Format f, ImmType i, dag outs, dag ins,
381391
let TSFlags{47-45} = !if(!eq(CD8_Scale, 0), 0, !add(!logtwo(CD8_Scale), 1));
382392
let TSFlags{48} = hasEVEX_RC;
383393
let TSFlags{49} = hasNoTrackPrefix;
384-
let TSFlags{50} = ExplicitVEXPrefix;
394+
let TSFlags{51-50} = explicitOpPrefixBits;
385395
}
386396

387397
class PseudoI<dag oops, dag iops, list<dag> pattern>

llvm/lib/Target/X86/X86InstrSSE.td

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7316,7 +7316,7 @@ defm VMASKMOVPD : avx_movmask_rm<0x2D, 0x2F, "vmaskmovpd",
73167316
// AVX_VNNI
73177317
//===----------------------------------------------------------------------===//
73187318
let Predicates = [HasAVXVNNI, NoVLX_Or_NoVNNI], Constraints = "$src1 = $dst",
7319-
ExplicitVEXPrefix = 1, checkVEXPredicate = 1 in
7319+
explicitOpPrefix = ExplicitVEX, checkVEXPredicate = 1 in
73207320
multiclass avx_vnni_rm<bits<8> opc, string OpcodeStr, SDNode OpNode,
73217321
bit IsCommutable> {
73227322
let isCommutable = IsCommutable in
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
# RUN: llvm-mc -triple x86_64 -disassemble %s | FileCheck %s --check-prefix=ATT
2+
# RUN: llvm-mc -triple x86_64 -disassemble -output-asm-variant=1 %s | FileCheck %s --check-prefix=INTEL
3+
4+
# ATT: jmpabs $1
5+
# INTEL: jmpabs 1
6+
0xd5,0x00,0xa1,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00
7+
8+
# ATT: jmpabs $72623859790382856
9+
# INTEL: jmpabs 72623859790382856
10+
0xd5,0x00,0xa1,0x08,0x07,0x06,0x05,0x04,0x03,0x02,0x01

llvm/test/MC/X86/apx/jmpabs-att.s

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
# RUN: llvm-mc -triple x86_64 -show-encoding %s | FileCheck %s
2+
# RUN: not llvm-mc -triple i386 -show-encoding %s 2>&1 | FileCheck %s --check-prefix=ERROR
3+
4+
# ERROR-COUNT-2: error:
5+
# ERROR-NOT: error:
6+
7+
# CHECK: jmpabs $1
8+
# CHECK: encoding: [0xd5,0x00,0xa1,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00]
9+
jmpabs $1
10+
# CHECK: jmpabs $72623859790382856
11+
# CHECK: encoding: [0xd5,0x00,0xa1,0x08,0x07,0x06,0x05,0x04,0x03,0x02,0x01]
12+
jmpabs $72623859790382856

llvm/test/MC/X86/apx/jmpabs-intel.s

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
# RUN: llvm-mc -triple x86_64 -show-encoding -x86-asm-syntax=intel -output-asm-variant=1 %s | FileCheck %s
2+
3+
# CHECK: jmpabs 1
4+
# CHECK: encoding: [0xd5,0x00,0xa1,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00]
5+
jmpabs 1
6+
# CHECK: jmpabs 72623859790382856
7+
# CHECK: encoding: [0xd5,0x00,0xa1,0x08,0x07,0x06,0x05,0x04,0x03,0x02,0x01]
8+
jmpabs 72623859790382856

llvm/utils/TableGen/X86DisassemblerTables.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -142,6 +142,7 @@ static inline bool inheritsFrom(InstructionContext child,
142142
case IC_64BIT_REXW_XS:
143143
case IC_64BIT_REXW_OPSIZE:
144144
case IC_64BIT_REXW_ADSIZE:
145+
case IC_64BIT_REX2:
145146
return false;
146147
case IC_VEX:
147148
return (VEX_LIG && WIG && inheritsFrom(child, IC_VEX_L_W)) ||
@@ -908,6 +909,8 @@ void DisassemblerTables::emitContextTable(raw_ostream &o, unsigned &i) const {
908909
o << "_B";
909910
}
910911
}
912+
else if ((index & ATTR_64BIT) && (index & ATTR_REX2))
913+
o << "IC_64BIT_REX2";
911914
else if ((index & ATTR_64BIT) && (index & ATTR_REXW) && (index & ATTR_XS))
912915
o << "IC_64BIT_REXW_XS";
913916
else if ((index & ATTR_64BIT) && (index & ATTR_REXW) && (index & ATTR_XD))

llvm/utils/TableGen/X86RecognizableInstr.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,8 @@ RecognizableInstrBase::RecognizableInstrBase(const CodeGenInstruction &insn) {
129129
ForceDisassemble = Rec->getValueAsBit("ForceDisassemble");
130130
CD8_Scale = byteFromRec(Rec, "CD8_Scale");
131131
HasVEX_L = Rec->getValueAsBit("hasVEX_L");
132+
ExplicitREX2Prefix =
133+
byteFromRec(Rec, "explicitOpPrefixBits") == X86Local::ExplicitREX2;
132134

133135
EncodeRC = HasEVEX_B &&
134136
(Form == X86Local::MRMDestReg || Form == X86Local::MRMSrcReg);
@@ -340,6 +342,8 @@ InstructionContext RecognizableInstr::insnContext() const {
340342
insnContext = IC_64BIT_XD;
341343
else if (OpPrefix == X86Local::XS)
342344
insnContext = IC_64BIT_XS;
345+
else if (ExplicitREX2Prefix)
346+
insnContext = IC_64BIT_REX2;
343347
else if (HasREX_W)
344348
insnContext = IC_64BIT_REXW;
345349
else

llvm/utils/TableGen/X86RecognizableInstr.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -155,6 +155,8 @@ namespace X86Local {
155155
enum {
156156
AdSize16 = 1, AdSize32 = 2, AdSize64 = 3
157157
};
158+
159+
enum { ExplicitREX2 = 1 };
158160
}
159161

160162
namespace X86Disassembler {
@@ -206,6 +208,8 @@ struct RecognizableInstrBase {
206208
bool ForceDisassemble;
207209
// The CD8_Scale field from the record
208210
uint8_t CD8_Scale;
211+
/// If explicitOpPrefix field from the record equals ExplicitREX2
212+
bool ExplicitREX2Prefix;
209213
/// \param insn The CodeGenInstruction to extract information from.
210214
RecognizableInstrBase(const CodeGenInstruction &insn);
211215
/// \returns true if this instruction should be emitted

0 commit comments

Comments
 (0)