Skip to content

[X86][MC] Support encoding/decoding for APX variant ADD/SUB/ADC/SBB/OR/XOR/NEG/NOT instructions #76319

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 10 commits into from
Dec 28, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 8 additions & 1 deletion llvm/include/llvm/Support/X86DisassemblerDecoderCommon.h
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,8 @@ enum attributeBits {
ATTR_EVEXKZ = 0x1 << 11,
ATTR_EVEXB = 0x1 << 12,
ATTR_REX2 = 0x1 << 13,
ATTR_max = 0x1 << 14,
ATTR_EVEXNF = 0x1 << 14,
ATTR_max = 0x1 << 15,
};

// Combinations of the above attributes that are relevant to instruction
Expand Down Expand Up @@ -137,12 +138,15 @@ enum attributeBits {
ENUM_ENTRY(IC_VEX_L_W_XD, 5, "requires VEX, L, W and XD prefix") \
ENUM_ENTRY(IC_VEX_L_W_OPSIZE, 5, "requires VEX, L, W and OpSize") \
ENUM_ENTRY(IC_EVEX, 1, "requires an EVEX prefix") \
ENUM_ENTRY(IC_EVEX_NF, 2, "requires EVEX and NF prefix") \
ENUM_ENTRY(IC_EVEX_XS, 2, "requires EVEX and the XS prefix") \
ENUM_ENTRY(IC_EVEX_XD, 2, "requires EVEX and the XD prefix") \
ENUM_ENTRY(IC_EVEX_OPSIZE, 2, "requires EVEX and the OpSize prefix") \
ENUM_ENTRY(IC_EVEX_OPSIZE_NF, 3, "requires EVEX, NF and the OpSize prefix") \
ENUM_ENTRY(IC_EVEX_OPSIZE_ADSIZE, 3, \
"requires EVEX, OPSIZE and the ADSIZE prefix") \
ENUM_ENTRY(IC_EVEX_W, 3, "requires EVEX and the W prefix") \
ENUM_ENTRY(IC_EVEX_W_NF, 4, "requires EVEX, W and NF prefix") \
ENUM_ENTRY(IC_EVEX_W_XS, 4, "requires EVEX, W, and XS prefix") \
ENUM_ENTRY(IC_EVEX_W_XD, 4, "requires EVEX, W, and XD prefix") \
ENUM_ENTRY(IC_EVEX_W_OPSIZE, 4, "requires EVEX, W, and OpSize") \
Expand Down Expand Up @@ -187,10 +191,13 @@ enum attributeBits {
ENUM_ENTRY(IC_EVEX_L2_W_XD_K, 4, "requires EVEX_K, L2, W and XD prefix") \
ENUM_ENTRY(IC_EVEX_L2_W_OPSIZE_K, 4, "requires EVEX_K, L2, W and OpSize") \
ENUM_ENTRY(IC_EVEX_B, 1, "requires an EVEX_B prefix") \
ENUM_ENTRY(IC_EVEX_B_NF, 2, "requires EVEX_NF and EVEX_B prefix") \
ENUM_ENTRY(IC_EVEX_XS_B, 2, "requires EVEX_B and the XS prefix") \
ENUM_ENTRY(IC_EVEX_XD_B, 2, "requires EVEX_B and the XD prefix") \
ENUM_ENTRY(IC_EVEX_OPSIZE_B, 2, "requires EVEX_B and the OpSize prefix") \
ENUM_ENTRY(IC_EVEX_OPSIZE_B_NF, 3, "requires EVEX_B, NF and Opsize prefix") \
ENUM_ENTRY(IC_EVEX_W_B, 3, "requires EVEX_B and the W prefix") \
ENUM_ENTRY(IC_EVEX_W_B_NF, 4, "requires EVEX_NF, EVEX_B and the W prefix") \
ENUM_ENTRY(IC_EVEX_W_XS_B, 4, "requires EVEX_B, W, and XS prefix") \
ENUM_ENTRY(IC_EVEX_W_XD_B, 4, "requires EVEX_B, W, and XD prefix") \
ENUM_ENTRY(IC_EVEX_W_OPSIZE_B, 4, "requires EVEX_B, W, and OpSize") \
Expand Down
7 changes: 7 additions & 0 deletions llvm/lib/Target/X86/AsmParser/X86AsmParser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,8 @@ class X86AsmParser : public MCTargetAsmParser {

// Does this instruction use apx extended register?
bool UseApxExtendedReg = false;
// Is this instruction explicitly required not to update flags?
bool ForcedNoFlag = false;

private:
SMLoc consumeToken() {
Expand Down Expand Up @@ -3125,6 +3127,7 @@ bool X86AsmParser::ParseInstruction(ParseInstructionInfo &Info, StringRef Name,
ForcedVEXEncoding = VEXEncoding_Default;
ForcedDispEncoding = DispEncoding_Default;
UseApxExtendedReg = false;
ForcedNoFlag = false;

// Parse pseudo prefixes.
while (true) {
Expand All @@ -3149,6 +3152,8 @@ bool X86AsmParser::ParseInstruction(ParseInstructionInfo &Info, StringRef Name,
ForcedDispEncoding = DispEncoding_Disp8;
else if (Prefix == "disp32")
ForcedDispEncoding = DispEncoding_Disp32;
else if (Prefix == "nf")
ForcedNoFlag = true;
else
return Error(NameLoc, "unknown prefix");

Expand Down Expand Up @@ -3996,6 +4001,8 @@ unsigned X86AsmParser::checkTargetMatchPredicate(MCInst &Inst) {

if (UseApxExtendedReg && !X86II::canUseApxExtendedReg(MCID))
return Match_Unsupported;
if (ForcedNoFlag != !!(MCID.TSFlags & X86II::EVEX_NF))
return Match_Unsupported;

if (ForcedVEXEncoding == VEXEncoding_EVEX &&
(MCID.TSFlags & X86II::EncodingMask) != X86II::EVEX)
Expand Down
6 changes: 5 additions & 1 deletion llvm/lib/Target/X86/Disassembler/X86Disassembler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1169,7 +1169,11 @@ static int getInstructionID(struct InternalInstruction *insn,
attrMask |= ATTR_EVEXKZ;
if (bFromEVEX4of4(insn->vectorExtensionPrefix[3]))
attrMask |= ATTR_EVEXB;
if (aaaFromEVEX4of4(insn->vectorExtensionPrefix[3]))
// nf bit is the MSB of aaa
if (nfFromEVEX4of4(insn->vectorExtensionPrefix[3]) &&
insn->opcodeType == MAP4)
attrMask |= ATTR_EVEXNF;
else if (aaaFromEVEX4of4(insn->vectorExtensionPrefix[3]))
attrMask |= ATTR_EVEXK;
if (lFromEVEX4of4(insn->vectorExtensionPrefix[3]))
attrMask |= ATTR_VEXL;
Expand Down
1 change: 1 addition & 0 deletions llvm/lib/Target/X86/Disassembler/X86DisassemblerDecoder.h
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,7 @@ namespace X86Disassembler {
#define bFromEVEX4of4(evex) bitFromOffset4(evex)
#define v2FromEVEX4of4(evex) invertedBitFromOffset3(evex)
#define aaaFromEVEX4of4(evex) threeBitsFromOffset0(evex)
#define nfFromEVEX4of4(evex) bitFromOffset2(evex)

// These enums represent Intel registers for use by the decoder.
#define REGS_8BIT \
Expand Down
13 changes: 11 additions & 2 deletions llvm/lib/Target/X86/MCTargetDesc/X86BaseInfo.h
Original file line number Diff line number Diff line change
Expand Up @@ -870,7 +870,10 @@ enum : uint64_t {
ExplicitVEXPrefix = 2ULL << ExplicitOpPrefixShift,
/// For instructions that are promoted to EVEX space for EGPR.
ExplicitEVEXPrefix = 3ULL << ExplicitOpPrefixShift,
ExplicitOpPrefixMask = 3ULL << ExplicitOpPrefixShift
ExplicitOpPrefixMask = 3ULL << ExplicitOpPrefixShift,
/// EVEX_NF - Set if this instruction has EVEX.NF field set.
EVEX_NFShift = ExplicitOpPrefixShift + 2,
EVEX_NF = 1ULL << EVEX_NFShift
};

/// \returns true if the instruction with given opcode is a prefix.
Expand Down Expand Up @@ -992,6 +995,12 @@ inline unsigned getOperandBias(const MCInstrDesc &Desc) {
}
}

/// \returns true if the instruction has a NDD (new data destination).
inline bool hasNewDataDest(uint64_t TSFlags) {
return (TSFlags & X86II::OpMapMask) == X86II::T_MAP4 &&
(TSFlags & X86II::EVEX_B) && (TSFlags & X86II::VEX_4V);
}

/// \returns operand # for the first field of the memory operand or -1 if no
/// memory operands.
/// NOTE: This ignores tied operands. If there is a tied register which is
Expand All @@ -1018,7 +1027,7 @@ inline int getMemoryOperandNo(uint64_t TSFlags) {
return -1;
case X86II::MRMDestMem:
case X86II::MRMDestMemFSIB:
return 0;
return hasNewDataDest(TSFlags);
case X86II::MRMSrcMem:
case X86II::MRMSrcMemFSIB:
// Start from 1, skip any registers encoded in VEX_VVVV or I8IMM, or a
Expand Down
3 changes: 3 additions & 0 deletions llvm/lib/Target/X86/MCTargetDesc/X86InstPrinterCommon.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -369,6 +369,9 @@ void X86InstPrinterCommon::printInstFlags(const MCInst *MI, raw_ostream &O,
else if (Flags & X86::IP_HAS_REPEAT)
O << "\trep\t";

if (TSFlags & X86II::EVEX_NF)
O << "\t{nf}";

// These all require a pseudo prefix
if ((Flags & X86::IP_USE_VEX) ||
(TSFlags & X86II::ExplicitOpPrefixMask) == X86II::ExplicitVEXPrefix)
Expand Down
43 changes: 39 additions & 4 deletions llvm/lib/Target/X86/MCTargetDesc/X86MCCodeEmitter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -251,6 +251,7 @@ class X86OpcodePrefixHelper {
void setAAA(const MCInst &MI, unsigned OpNum) {
EVEX_aaa = getRegEncoding(MI, OpNum);
}
void setNF(bool V) { EVEX_aaa |= V << 2; }

X86OpcodePrefixHelper(const MCRegisterInfo &MRI)
: W(0), R(0), X(0), B(0), M(0), R2(0), X2(0), B2(0), VEX_4V(0), VEX_L(0),
Expand Down Expand Up @@ -987,9 +988,11 @@ X86MCCodeEmitter::emitVEXOpcodePrefix(int MemOperand, const MCInst &MI,
}

Prefix.setW(TSFlags & X86II::REX_W);
Prefix.setNF(TSFlags & X86II::EVEX_NF);

bool HasEVEX_K = TSFlags & X86II::EVEX_K;
bool HasVEX_4V = TSFlags & X86II::VEX_4V;
bool IsND = X86II::hasNewDataDest(TSFlags); // IsND implies HasVEX_4V
bool HasEVEX_RC = TSFlags & X86II::EVEX_RC;

switch (TSFlags & X86II::OpMapMask) {
Expand Down Expand Up @@ -1049,6 +1052,7 @@ X86MCCodeEmitter::emitVEXOpcodePrefix(int MemOperand, const MCInst &MI,

bool EncodeRC = false;
uint8_t EVEX_rc = 0;

unsigned CurOp = X86II::getOperandBias(Desc);

switch (TSFlags & X86II::FormMask) {
Expand All @@ -1073,16 +1077,21 @@ X86MCCodeEmitter::emitVEXOpcodePrefix(int MemOperand, const MCInst &MI,
// MemAddr, src1(VEX_4V), src2(ModR/M)
// MemAddr, src1(ModR/M), imm8
//
// NDD:
// dst(VEX_4V), MemAddr, src1(ModR/M)
Prefix.setBB2(MI, MemOperand + X86::AddrBaseReg);
Prefix.setXX2(MI, MemOperand + X86::AddrIndexReg);
Prefix.setV2(MI, MemOperand + X86::AddrIndexReg, HasVEX_4V);

if (IsND)
Prefix.set4VV2(MI, CurOp++);

CurOp += X86::AddrNumOperands;

if (HasEVEX_K)
Prefix.setAAA(MI, CurOp++);

if (HasVEX_4V)
if (!IsND && HasVEX_4V)
Prefix.set4VV2(MI, CurOp++);

Prefix.setRR2(MI, CurOp++);
Expand All @@ -1098,12 +1107,18 @@ X86MCCodeEmitter::emitVEXOpcodePrefix(int MemOperand, const MCInst &MI,
//
// FMA4:
// dst(ModR/M.reg), src1(VEX_4V), src2(ModR/M), src3(Imm[7:4])
//
// NDD:
// dst(VEX_4V), src1(ModR/M), MemAddr
if (IsND)
Prefix.set4VV2(MI, CurOp++);

Prefix.setRR2(MI, CurOp++);

if (HasEVEX_K)
Prefix.setAAA(MI, CurOp++);

if (HasVEX_4V)
if (!IsND && HasVEX_4V)
Prefix.set4VV2(MI, CurOp++);

Prefix.setBB2(MI, MemOperand + X86::AddrBaseReg);
Expand Down Expand Up @@ -1160,12 +1175,17 @@ X86MCCodeEmitter::emitVEXOpcodePrefix(int MemOperand, const MCInst &MI,
//
// FMA4:
// dst(ModR/M.reg), src1(VEX_4V), src2(Imm[7:4]), src3(ModR/M),
//
// NDD:
// dst(VEX_4V), src1(ModR/M.reg), src2(ModR/M)
if (IsND)
Prefix.set4VV2(MI, CurOp++);
Prefix.setRR2(MI, CurOp++);

if (HasEVEX_K)
Prefix.setAAA(MI, CurOp++);

if (HasVEX_4V)
if (!IsND && HasVEX_4V)
Prefix.set4VV2(MI, CurOp++);

Prefix.setBB2(MI, CurOp);
Expand Down Expand Up @@ -1209,14 +1229,19 @@ X86MCCodeEmitter::emitVEXOpcodePrefix(int MemOperand, const MCInst &MI,
// dst(ModR/M), src(ModR/M)
// dst(ModR/M), src(ModR/M), imm8
// dst(ModR/M), src1(VEX_4V), src2(ModR/M)
//
// NDD:
// dst(VEX_4V), src1(ModR/M), src2(ModR/M)
if (IsND)
Prefix.set4VV2(MI, CurOp++);
Prefix.setBB2(MI, CurOp);
Prefix.setX(MI, CurOp, 4);
++CurOp;

if (HasEVEX_K)
Prefix.setAAA(MI, CurOp++);

if (HasVEX_4V)
if (!IsND && HasVEX_4V)
Prefix.set4VV2(MI, CurOp++);

Prefix.setRR2(MI, CurOp++);
Expand Down Expand Up @@ -1508,6 +1533,8 @@ void X86MCCodeEmitter::encodeInstruction(const MCInst &MI,

unsigned OpcodeOffset = 0;

bool IsND = X86II::hasNewDataDest(TSFlags);

uint64_t Form = TSFlags & X86II::FormMask;
switch (Form) {
default:
Expand Down Expand Up @@ -1576,6 +1603,8 @@ void X86MCCodeEmitter::encodeInstruction(const MCInst &MI,

if (HasVEX_4V) // Skip 1st src (which is encoded in VEX_VVVV)
++SrcRegNum;
if (IsND) // Skip the NDD operand encoded in EVEX_VVVV
++CurOp;

emitRegModRMByte(MI.getOperand(CurOp),
getX86RegNum(MI.getOperand(SrcRegNum)), CB);
Expand All @@ -1602,6 +1631,9 @@ void X86MCCodeEmitter::encodeInstruction(const MCInst &MI,
if (HasVEX_4V) // Skip 1st src (which is encoded in VEX_VVVV)
++SrcRegNum;

if (IsND) // Skip new data destination
++CurOp;

bool ForceSIB = (Form == X86II::MRMDestMemFSIB);
emitMemModRMByte(MI, CurOp, getX86RegNum(MI.getOperand(SrcRegNum)), TSFlags,
Kind, StartByte, CB, Fixups, STI, ForceSIB);
Expand Down Expand Up @@ -1669,6 +1701,9 @@ void X86MCCodeEmitter::encodeInstruction(const MCInst &MI,
case X86II::MRMSrcMem: {
unsigned FirstMemOp = CurOp + 1;

if (IsND) // Skip new data destination
CurOp++;

if (HasEVEX_K) // Skip writemask
++FirstMemOp;

Expand Down
Loading