Skip to content

[X86][MC] Support encoding/decoding for APX variant INC/DEC/ADCX/ADOX instructions #76721

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 3 commits into from
Jan 4, 2024
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
3 changes: 3 additions & 0 deletions llvm/lib/Target/X86/MCTargetDesc/X86MCCodeEmitter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1650,6 +1650,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;

emitRegModRMByte(MI.getOperand(SrcRegNum),
getX86RegNum(MI.getOperand(CurOp)), CB);
CurOp = SrcRegNum + 1;
Expand Down
171 changes: 139 additions & 32 deletions llvm/lib/Target/X86/X86InstrArithmetic.td
Original file line number Diff line number Diff line change
Expand Up @@ -184,52 +184,139 @@ def IMUL64rmi32 : IMulOpMI_R<Xi64, WriteIMul64Imm>;
//===----------------------------------------------------------------------===//
// INC and DEC Instructions
//
class IncOpR_RF<X86TypeInfo t> : UnaryOpR_RF<0xFF, MRM0r, "inc", t, null_frag> {
class IncOpR_RF<X86TypeInfo t, bit ndd = 0> : UnaryOpR_RF<0xFF, MRM0r, "inc", t, null_frag, ndd> {
let Pattern = [(set t.RegClass:$dst, EFLAGS,
(X86add_flag_nocf t.RegClass:$src1, 1))];
}
class DecOpR_RF<X86TypeInfo t> : UnaryOpR_RF<0xFF, MRM1r, "dec", t, null_frag> {
class DecOpR_RF<X86TypeInfo t, bit ndd = 0> : UnaryOpR_RF<0xFF, MRM1r, "dec", t, null_frag, ndd> {
let Pattern = [(set t.RegClass:$dst, EFLAGS,
(X86sub_flag_nocf t.RegClass:$src1, 1))];
}
class IncOpM_M<X86TypeInfo t> : UnaryOpM_MF<0xFF, MRM0m, "inc", t, null_frag> {
class IncOpR_R<X86TypeInfo t, bit ndd = 0> : UnaryOpR_R<0xFF, MRM0r, "inc", t, null_frag, ndd>;
class DecOpR_R<X86TypeInfo t, bit ndd = 0> : UnaryOpR_R<0xFF, MRM1r, "dec", t, null_frag, ndd>;
class IncOpM_MF<X86TypeInfo t> : UnaryOpM_MF<0xFF, MRM0m, "inc", t, null_frag> {
let Pattern = [(store (add (t.LoadNode addr:$src1), 1), addr:$src1),
(implicit EFLAGS)];
}
class DecOpM_M<X86TypeInfo t> : UnaryOpM_MF<0xFF, MRM1m, "dec", t, null_frag> {
class DecOpM_MF<X86TypeInfo t> : UnaryOpM_MF<0xFF, MRM1m, "dec", t, null_frag> {
let Pattern = [(store (add (t.LoadNode addr:$src1), -1), addr:$src1),
(implicit EFLAGS)];
}
class IncOpM_RF<X86TypeInfo t> : UnaryOpM_RF<0xFF, MRM0m, "inc", t, null_frag> {
let Pattern = [(set t.RegClass:$dst, EFLAGS, (add (t.LoadNode addr:$src1), 1))];
}
class DecOpM_RF<X86TypeInfo t> : UnaryOpM_RF<0xFF, MRM1m, "dec", t, null_frag> {
let Pattern = [(set t.RegClass:$dst, EFLAGS, (add (t.LoadNode addr:$src1), -1))];
}
class IncOpM_M<X86TypeInfo t> : UnaryOpM_M<0xFF, MRM0m, "inc", t, null_frag>;
class DecOpM_M<X86TypeInfo t> : UnaryOpM_M<0xFF, MRM1m, "dec", t, null_frag>;
class IncOpM_R<X86TypeInfo t> : UnaryOpM_R<0xFF, MRM0m, "inc", t, null_frag>;
class DecOpM_R<X86TypeInfo t> : UnaryOpM_R<0xFF, MRM1m, "dec", t, null_frag>;

// IncDec_Alt - Instructions like "inc reg" short forms.
// Short forms only valid in 32-bit mode. Selected during MCInst lowering.
class IncDec_Alt<bits<8> o, string m, X86TypeInfo t>
: UnaryOpR_RF<o, AddRegFrm, m, t, null_frag>, Requires<[Not64BitMode]>;

let isConvertibleToThreeAddress = 1 in {
def INC16r_alt : IncDec_Alt<0x40, "inc", Xi16>, OpSize16;
def INC32r_alt : IncDec_Alt<0x40, "inc", Xi32>, OpSize32;
def DEC16r_alt : IncDec_Alt<0x48, "dec", Xi16>, OpSize16;
def DEC32r_alt : IncDec_Alt<0x48, "dec", Xi32>, OpSize32;
def INC8r : IncOpR_RF<Xi8>;
def INC16r : IncOpR_RF<Xi16>, OpSize16;
def INC32r : IncOpR_RF<Xi32>, OpSize32;
def INC64r : IncOpR_RF<Xi64>;
def DEC8r : DecOpR_RF<Xi8>;
def DEC16r : DecOpR_RF<Xi16>, OpSize16;
def DEC32r : DecOpR_RF<Xi32>, OpSize32;
def DEC64r : DecOpR_RF<Xi64>;
def INC16r_alt : IncDec_Alt<0x40, "inc", Xi16>, OpSize16;
def INC32r_alt : IncDec_Alt<0x40, "inc", Xi32>, OpSize32;
def DEC16r_alt : IncDec_Alt<0x48, "dec", Xi16>, OpSize16;
def DEC32r_alt : IncDec_Alt<0x48, "dec", Xi32>, OpSize32;
let Predicates = [NoNDD] in {
def INC8r : IncOpR_RF<Xi8>;
def INC16r : IncOpR_RF<Xi16>, OpSize16;
def INC32r : IncOpR_RF<Xi32>, OpSize32;
def INC64r : IncOpR_RF<Xi64>;
def DEC8r : DecOpR_RF<Xi8>;
def DEC16r : DecOpR_RF<Xi16>, OpSize16;
def DEC32r : DecOpR_RF<Xi32>, OpSize32;
def DEC64r : DecOpR_RF<Xi64>;
}
let Predicates = [HasNDD, In64BitMode] in {
def INC8r_ND : IncOpR_RF<Xi8, 1>;
def INC16r_ND : IncOpR_RF<Xi16, 1>, PD;
def INC32r_ND : IncOpR_RF<Xi32, 1>;
def INC64r_ND : IncOpR_RF<Xi64, 1>;
def DEC8r_ND : DecOpR_RF<Xi8, 1>;
def DEC16r_ND : DecOpR_RF<Xi16, 1>, PD;
def DEC32r_ND : DecOpR_RF<Xi32, 1>;
def DEC64r_ND : DecOpR_RF<Xi64, 1>;
}
let Predicates = [In64BitMode], Pattern = [(null_frag)] in {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why set Pattern = [(null_frag)] here given both IncOpR_R and IncOpR_RF already pass null_frag by default?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We only need to set Pattern = [(null_frag)] for INC/DEC*_EVEX. I put the setting in a wider range just to reduce nested let statements. Otherwise, the code would look like

 let Predicates = [In64BitMode] in {
    def INC8r_NF
    let Pattern = [(null_frag)] in {
       def INC8r_EVEX
    }
 }

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How about move INC8r_EVEX INC8m_EVEX together with let Predicates = [In64BitMode], Pattern = [(null_frag)]?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It does not save anything b/c we can not move INC8r_NF, which needs isConvertibleToThreeAddress = 1

def INC8r_NF : IncOpR_R<Xi8>, NF;
def INC16r_NF : IncOpR_R<Xi16>, NF, PD;
def INC32r_NF : IncOpR_R<Xi32>, NF;
def INC64r_NF : IncOpR_R<Xi64>, NF;
def DEC8r_NF : DecOpR_R<Xi8>, NF;
def DEC16r_NF : DecOpR_R<Xi16>, NF, PD;
def DEC32r_NF : DecOpR_R<Xi32>, NF;
def DEC64r_NF : DecOpR_R<Xi64>, NF;
def INC8r_NF_ND : IncOpR_R<Xi8, 1>, NF;
def INC16r_NF_ND : IncOpR_R<Xi16, 1>, NF, PD;
def INC32r_NF_ND : IncOpR_R<Xi32, 1>, NF;
def INC64r_NF_ND : IncOpR_R<Xi64, 1>, NF;
def DEC8r_NF_ND : DecOpR_R<Xi8, 1>, NF;
def DEC16r_NF_ND : DecOpR_R<Xi16, 1>, NF, PD;
def DEC32r_NF_ND : DecOpR_R<Xi32, 1>, NF;
def DEC64r_NF_ND : DecOpR_R<Xi64, 1>, NF;
def INC8r_EVEX : IncOpR_RF<Xi8>, PL;
def INC16r_EVEX : IncOpR_RF<Xi16>, PL, PD;
def INC32r_EVEX : IncOpR_RF<Xi32>, PL;
def INC64r_EVEX : IncOpR_RF<Xi64>, PL;
def DEC8r_EVEX : DecOpR_RF<Xi8>, PL;
def DEC16r_EVEX : DecOpR_RF<Xi16>, PL, PD;
def DEC32r_EVEX : DecOpR_RF<Xi32>, PL;
def DEC64r_EVEX : DecOpR_RF<Xi64>, PL;
}
}
let Predicates = [UseIncDec] in {
def INC8m : IncOpM_M<Xi8>;
def INC16m : IncOpM_M<Xi16>, OpSize16;
def INC32m : IncOpM_M<Xi32>, OpSize32;
def DEC8m : DecOpM_M<Xi8>;
def DEC16m : DecOpM_M<Xi16>, OpSize16;
def DEC32m : DecOpM_M<Xi32>, OpSize32;
def INC8m : IncOpM_MF<Xi8>;
def INC16m : IncOpM_MF<Xi16>, OpSize16;
def INC32m : IncOpM_MF<Xi32>, OpSize32;
def DEC8m : DecOpM_MF<Xi8>;
def DEC16m : DecOpM_MF<Xi16>, OpSize16;
def DEC32m : DecOpM_MF<Xi32>, OpSize32;
}
let Predicates = [UseIncDec, In64BitMode] in {
def INC64m : IncOpM_M<Xi64>;
def DEC64m : DecOpM_M<Xi64>;
def INC64m : IncOpM_MF<Xi64>;
def DEC64m : DecOpM_MF<Xi64>;
}
let Predicates = [HasNDD, In64BitMode, UseIncDec] in {
def INC8m_ND : IncOpM_RF<Xi8>;
def INC16m_ND : IncOpM_RF<Xi16>, PD;
def INC32m_ND : IncOpM_RF<Xi32>;
def DEC8m_ND : DecOpM_RF<Xi8>;
def DEC16m_ND : DecOpM_RF<Xi16>, PD;
def DEC32m_ND : DecOpM_RF<Xi32>;
def INC64m_ND : IncOpM_RF<Xi64>;
def DEC64m_ND : DecOpM_RF<Xi64>;
}
let Predicates = [In64BitMode], Pattern = [(null_frag)] in {
def INC8m_NF : IncOpM_M<Xi8>, NF;
def INC16m_NF : IncOpM_M<Xi16>, NF, PD;
def INC32m_NF : IncOpM_M<Xi32>, NF;
def INC64m_NF : IncOpM_M<Xi64>, NF;
def DEC8m_NF : DecOpM_M<Xi8>, NF;
def DEC16m_NF : DecOpM_M<Xi16>, NF, PD;
def DEC32m_NF : DecOpM_M<Xi32>, NF;
def DEC64m_NF : DecOpM_M<Xi64>, NF;
def INC8m_NF_ND : IncOpM_R<Xi8>, NF;
def INC16m_NF_ND : IncOpM_R<Xi16>, NF, PD;
def INC32m_NF_ND : IncOpM_R<Xi32>, NF;
def INC64m_NF_ND : IncOpM_R<Xi64>, NF;
def DEC8m_NF_ND : DecOpM_R<Xi8>, NF;
def DEC16m_NF_ND : DecOpM_R<Xi16>, NF, PD;
def DEC32m_NF_ND : DecOpM_R<Xi32>, NF;
def DEC64m_NF_ND : DecOpM_R<Xi64>, NF;
def INC8m_EVEX : IncOpM_MF<Xi8>, PL;
def INC16m_EVEX : IncOpM_MF<Xi16>, PL, PD;
def INC32m_EVEX : IncOpM_MF<Xi32>, PL;
def INC64m_EVEX : IncOpM_MF<Xi64>, PL;
def DEC8m_EVEX : DecOpM_MF<Xi8>, PL;
def DEC16m_EVEX : DecOpM_MF<Xi16>, PL, PD;
def DEC32m_EVEX : DecOpM_MF<Xi32>, PL;
def DEC64m_EVEX : DecOpM_MF<Xi64>, PL;
}

//===----------------------------------------------------------------------===//
Expand Down Expand Up @@ -1119,14 +1206,34 @@ defm MULX64 : MulX<Xi64, WriteMULX64>, REX_W;
// We don't have patterns for these as there is no advantage over ADC for
// most code.
let Form = MRMSrcReg in {
def ADCX32rr : BinOpRRF_RF<0xF6, "adcx", Xi32, null_frag>, T8, PD;
def ADCX64rr : BinOpRRF_RF<0xF6, "adcx", Xi64, null_frag>, T8, PD;
def ADOX32rr : BinOpRRF_RF<0xF6, "adox", Xi32, null_frag>, T8, XS;
def ADOX64rr : BinOpRRF_RF<0xF6, "adox", Xi64, null_frag>, T8, XS;
def ADCX32rr : BinOpRRF_RF<0xF6, "adcx", Xi32>, T8, PD;
def ADCX64rr : BinOpRRF_RF<0xF6, "adcx", Xi64>, T8, PD;
def ADOX32rr : BinOpRRF_RF<0xF6, "adox", Xi32>, T8, XS;
def ADOX64rr : BinOpRRF_RF<0xF6, "adox", Xi64>, T8, XS;
let Predicates =[In64BitMode] in {
def ADCX32rr_EVEX : BinOpRRF_RF<0x66, "adcx", Xi32>, EVEX, T_MAP4, PD;
def ADCX64rr_EVEX : BinOpRRF_RF<0x66, "adcx", Xi64>, EVEX, T_MAP4, PD;
def ADOX32rr_EVEX : BinOpRRF_RF<0x66, "adox", Xi32>, EVEX, T_MAP4, XS;
def ADOX64rr_EVEX : BinOpRRF_RF<0x66, "adox", Xi64>, EVEX, T_MAP4, XS;
Comment on lines +1214 to +1217
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why don't set Pattern = [(null_frag)] for these?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You suggested "make null_frag a default value for BinOpRRF_RF" and I made the change. Now the Pattern is equivalent to [(null_frag)], we don't need to set it explicitly here.

def ADCX32rr_ND : BinOpRRF_RF<0x66, "adcx", Xi32, null_frag, 1>, PD;
def ADCX64rr_ND : BinOpRRF_RF<0x66, "adcx", Xi64, null_frag, 1>, PD;
def ADOX32rr_ND : BinOpRRF_RF<0x66, "adox", Xi32, null_frag, 1>, XS;
def ADOX64rr_ND : BinOpRRF_RF<0x66, "adox", Xi64, null_frag, 1>, XS;
}
}
let Form = MRMSrcMem in {
def ADCX32rm : BinOpRMF_RF<0xF6, "adcx", Xi32, null_frag>, T8, PD;
def ADCX64rm : BinOpRMF_RF<0xF6, "adcx", Xi64, null_frag>, T8, PD;
def ADOX32rm : BinOpRMF_RF<0xF6, "adox", Xi32, null_frag>, T8, XS;
def ADOX64rm : BinOpRMF_RF<0xF6, "adox", Xi64, null_frag>, T8, XS;
def ADCX32rm : BinOpRMF_RF<0xF6, "adcx", Xi32>, T8, PD;
def ADCX64rm : BinOpRMF_RF<0xF6, "adcx", Xi64>, T8, PD;
def ADOX32rm : BinOpRMF_RF<0xF6, "adox", Xi32>, T8, XS;
def ADOX64rm : BinOpRMF_RF<0xF6, "adox", Xi64>, T8, XS;
let Predicates =[In64BitMode] in {
def ADCX32rm_EVEX : BinOpRMF_RF<0x66, "adcx", Xi32>, EVEX, T_MAP4, PD;
def ADCX64rm_EVEX : BinOpRMF_RF<0x66, "adcx", Xi64>, EVEX, T_MAP4, PD;
def ADOX32rm_EVEX : BinOpRMF_RF<0x66, "adox", Xi32>, EVEX, T_MAP4, XS;
def ADOX64rm_EVEX : BinOpRMF_RF<0x66, "adox", Xi64>, EVEX, T_MAP4, XS;
def ADCX32rm_ND : BinOpRMF_RF<0x66, "adcx", Xi32, null_frag, 1>, PD;
def ADCX64rm_ND : BinOpRMF_RF<0x66, "adcx", Xi64, null_frag, 1>, PD;
def ADOX32rm_ND : BinOpRMF_RF<0x66, "adox", Xi32, null_frag, 1>, XS;
def ADOX64rm_ND : BinOpRMF_RF<0x66, "adox", Xi64, null_frag, 1>, XS;
}
}
4 changes: 2 additions & 2 deletions llvm/lib/Target/X86/X86InstrUtils.td
Original file line number Diff line number Diff line change
Expand Up @@ -1005,7 +1005,7 @@ class BinOpRR_RF_Rev<bits<8> o, string m, X86TypeInfo t, bit ndd = 0>
}
// BinOpRRF_RF - Instructions that read "reg, reg", write "reg" and read/write
// EFLAGS.
class BinOpRRF_RF<bits<8> o, string m, X86TypeInfo t, SDPatternOperator node, bit ndd = 0>
class BinOpRRF_RF<bits<8> o, string m, X86TypeInfo t, SDPatternOperator node = null_frag, bit ndd = 0>
: BinOpRR<o, m, !if(!eq(ndd, 0), binop_args, binop_ndd_args), t, (outs t.RegClass:$dst),
[(set t.RegClass:$dst, EFLAGS,
(node t.RegClass:$src1, t.RegClass:$src2,
Expand Down Expand Up @@ -1041,7 +1041,7 @@ class BinOpRM_RF<bits<8> o, string m, X86TypeInfo t, SDPatternOperator node, bit
(t.LoadNode addr:$src2)))]>, DefEFLAGS, NDD<ndd>;
// BinOpRMF_RF - Instructions that read "reg, [mem]", write "reg" and read/write
// EFLAGS.
class BinOpRMF_RF<bits<8> o, string m, X86TypeInfo t, SDPatternOperator node, bit ndd = 0>
class BinOpRMF_RF<bits<8> o, string m, X86TypeInfo t, SDPatternOperator node = null_frag, bit ndd = 0>
: BinOpRM<o, m, !if(!eq(ndd, 0), binop_args, binop_ndd_args), t, (outs t.RegClass:$dst),
[(set t.RegClass:$dst, EFLAGS,
(node t.RegClass:$src1, (t.LoadNode addr:$src2), EFLAGS))]>,
Expand Down
66 changes: 66 additions & 0 deletions llvm/test/MC/Disassembler/X86/apx/adx.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
# RUN: llvm-mc -triple x86_64 -disassemble %s | FileCheck %s --check-prefix=ATT
# RUN: llvm-mc -triple x86_64 -disassemble -output-asm-variant=1 %s | FileCheck %s --check-prefix=INTEL

# ATT: adcxl %r16d, %r17d
# INTEL: adcx r17d, r16d
0x62,0xec,0x7d,0x08,0x66,0xc8

# ATT: adcxl %r16d, %r17d, %r18d
# INTEL: adcx r18d, r17d, r16d
0x62,0xec,0x6d,0x10,0x66,0xc8

# ATT: adcxq %r16, %r17
# INTEL: adcx r17, r16
0x62,0xec,0xfd,0x08,0x66,0xc8

# ATT: adcxq %r16, %r17, %r18
# INTEL: adcx r18, r17, r16
0x62,0xec,0xed,0x10,0x66,0xc8

# ATT: adcxl (%r16), %r17d
# INTEL: adcx r17d, dword ptr [r16]
0x62,0xec,0x7d,0x08,0x66,0x08

# ATT: adcxl (%r16), %r17d, %r18d
# INTEL: adcx r18d, r17d, dword ptr [r16]
0x62,0xec,0x6d,0x10,0x66,0x08

# ATT: adcxq (%r16), %r17
# INTEL: adcx r17, qword ptr [r16]
0x62,0xec,0xfd,0x08,0x66,0x08

# ATT: adcxq (%r16), %r17, %r18
# INTEL: adcx r18, r17, qword ptr [r16]
0x62,0xec,0xed,0x10,0x66,0x08

# ATT: adoxl %r16d, %r17d
# INTEL: adox r17d, r16d
0x62,0xec,0x7e,0x08,0x66,0xc8

# ATT: adoxl %r16d, %r17d, %r18d
# INTEL: adox r18d, r17d, r16d
0x62,0xec,0x6e,0x10,0x66,0xc8

# ATT: adoxq %r16, %r17
# INTEL: adox r17, r16
0x62,0xec,0xfe,0x08,0x66,0xc8

# ATT: adoxq %r16, %r17, %r18
# INTEL: adox r18, r17, r16
0x62,0xec,0xee,0x10,0x66,0xc8

# ATT: adoxl (%r16), %r17d
# INTEL: adox r17d, dword ptr [r16]
0x62,0xec,0x7e,0x08,0x66,0x08

# ATT: adoxl (%r16), %r17d, %r18d
# INTEL: adox r18d, r17d, dword ptr [r16]
0x62,0xec,0x6e,0x10,0x66,0x08

# ATT: adoxq (%r16), %r17
# INTEL: adox r17, qword ptr [r16]
0x62,0xec,0xfe,0x08,0x66,0x08

# ATT: adoxq (%r16), %r17, %r18
# INTEL: adox r18, r17, qword ptr [r16]
0x62,0xec,0xee,0x10,0x66,0x08
Loading