Skip to content

Commit dd9681f

Browse files
authored
[X86][MC] Support encoding/decoding for APX variant INC/DEC/ADCX/ADOX instructions (#76721)
Four variants: promoted legacy, ND (new data destination), NF (no flags update) and NF_ND (NF + ND). The syntax of NF instructions is aligned with GNU binutils. https://sourceware.org/pipermail/binutils/2023-September/129545.html
1 parent 7df28fd commit dd9681f

File tree

13 files changed

+1003
-34
lines changed

13 files changed

+1003
-34
lines changed

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

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1650,6 +1650,9 @@ void X86MCCodeEmitter::encodeInstruction(const MCInst &MI,
16501650
if (HasVEX_4V) // Skip 1st src (which is encoded in VEX_VVVV)
16511651
++SrcRegNum;
16521652

1653+
if (IsND) // Skip new data destination
1654+
++CurOp;
1655+
16531656
emitRegModRMByte(MI.getOperand(SrcRegNum),
16541657
getX86RegNum(MI.getOperand(CurOp)), CB);
16551658
CurOp = SrcRegNum + 1;

llvm/lib/Target/X86/X86InstrArithmetic.td

Lines changed: 139 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -184,52 +184,139 @@ def IMUL64rmi32 : IMulOpMI_R<Xi64, WriteIMul64Imm>;
184184
//===----------------------------------------------------------------------===//
185185
// INC and DEC Instructions
186186
//
187-
class IncOpR_RF<X86TypeInfo t> : UnaryOpR_RF<0xFF, MRM0r, "inc", t, null_frag> {
187+
class IncOpR_RF<X86TypeInfo t, bit ndd = 0> : UnaryOpR_RF<0xFF, MRM0r, "inc", t, null_frag, ndd> {
188188
let Pattern = [(set t.RegClass:$dst, EFLAGS,
189189
(X86add_flag_nocf t.RegClass:$src1, 1))];
190190
}
191-
class DecOpR_RF<X86TypeInfo t> : UnaryOpR_RF<0xFF, MRM1r, "dec", t, null_frag> {
191+
class DecOpR_RF<X86TypeInfo t, bit ndd = 0> : UnaryOpR_RF<0xFF, MRM1r, "dec", t, null_frag, ndd> {
192192
let Pattern = [(set t.RegClass:$dst, EFLAGS,
193193
(X86sub_flag_nocf t.RegClass:$src1, 1))];
194194
}
195-
class IncOpM_M<X86TypeInfo t> : UnaryOpM_MF<0xFF, MRM0m, "inc", t, null_frag> {
195+
class IncOpR_R<X86TypeInfo t, bit ndd = 0> : UnaryOpR_R<0xFF, MRM0r, "inc", t, null_frag, ndd>;
196+
class DecOpR_R<X86TypeInfo t, bit ndd = 0> : UnaryOpR_R<0xFF, MRM1r, "dec", t, null_frag, ndd>;
197+
class IncOpM_MF<X86TypeInfo t> : UnaryOpM_MF<0xFF, MRM0m, "inc", t, null_frag> {
196198
let Pattern = [(store (add (t.LoadNode addr:$src1), 1), addr:$src1),
197199
(implicit EFLAGS)];
198200
}
199-
class DecOpM_M<X86TypeInfo t> : UnaryOpM_MF<0xFF, MRM1m, "dec", t, null_frag> {
201+
class DecOpM_MF<X86TypeInfo t> : UnaryOpM_MF<0xFF, MRM1m, "dec", t, null_frag> {
200202
let Pattern = [(store (add (t.LoadNode addr:$src1), -1), addr:$src1),
201203
(implicit EFLAGS)];
202204
}
205+
class IncOpM_RF<X86TypeInfo t> : UnaryOpM_RF<0xFF, MRM0m, "inc", t, null_frag> {
206+
let Pattern = [(set t.RegClass:$dst, EFLAGS, (add (t.LoadNode addr:$src1), 1))];
207+
}
208+
class DecOpM_RF<X86TypeInfo t> : UnaryOpM_RF<0xFF, MRM1m, "dec", t, null_frag> {
209+
let Pattern = [(set t.RegClass:$dst, EFLAGS, (add (t.LoadNode addr:$src1), -1))];
210+
}
211+
class IncOpM_M<X86TypeInfo t> : UnaryOpM_M<0xFF, MRM0m, "inc", t, null_frag>;
212+
class DecOpM_M<X86TypeInfo t> : UnaryOpM_M<0xFF, MRM1m, "dec", t, null_frag>;
213+
class IncOpM_R<X86TypeInfo t> : UnaryOpM_R<0xFF, MRM0m, "inc", t, null_frag>;
214+
class DecOpM_R<X86TypeInfo t> : UnaryOpM_R<0xFF, MRM1m, "dec", t, null_frag>;
215+
203216
// IncDec_Alt - Instructions like "inc reg" short forms.
204217
// Short forms only valid in 32-bit mode. Selected during MCInst lowering.
205218
class IncDec_Alt<bits<8> o, string m, X86TypeInfo t>
206219
: UnaryOpR_RF<o, AddRegFrm, m, t, null_frag>, Requires<[Not64BitMode]>;
207220

208221
let isConvertibleToThreeAddress = 1 in {
209-
def INC16r_alt : IncDec_Alt<0x40, "inc", Xi16>, OpSize16;
210-
def INC32r_alt : IncDec_Alt<0x40, "inc", Xi32>, OpSize32;
211-
def DEC16r_alt : IncDec_Alt<0x48, "dec", Xi16>, OpSize16;
212-
def DEC32r_alt : IncDec_Alt<0x48, "dec", Xi32>, OpSize32;
213-
def INC8r : IncOpR_RF<Xi8>;
214-
def INC16r : IncOpR_RF<Xi16>, OpSize16;
215-
def INC32r : IncOpR_RF<Xi32>, OpSize32;
216-
def INC64r : IncOpR_RF<Xi64>;
217-
def DEC8r : DecOpR_RF<Xi8>;
218-
def DEC16r : DecOpR_RF<Xi16>, OpSize16;
219-
def DEC32r : DecOpR_RF<Xi32>, OpSize32;
220-
def DEC64r : DecOpR_RF<Xi64>;
222+
def INC16r_alt : IncDec_Alt<0x40, "inc", Xi16>, OpSize16;
223+
def INC32r_alt : IncDec_Alt<0x40, "inc", Xi32>, OpSize32;
224+
def DEC16r_alt : IncDec_Alt<0x48, "dec", Xi16>, OpSize16;
225+
def DEC32r_alt : IncDec_Alt<0x48, "dec", Xi32>, OpSize32;
226+
let Predicates = [NoNDD] in {
227+
def INC8r : IncOpR_RF<Xi8>;
228+
def INC16r : IncOpR_RF<Xi16>, OpSize16;
229+
def INC32r : IncOpR_RF<Xi32>, OpSize32;
230+
def INC64r : IncOpR_RF<Xi64>;
231+
def DEC8r : DecOpR_RF<Xi8>;
232+
def DEC16r : DecOpR_RF<Xi16>, OpSize16;
233+
def DEC32r : DecOpR_RF<Xi32>, OpSize32;
234+
def DEC64r : DecOpR_RF<Xi64>;
235+
}
236+
let Predicates = [HasNDD, In64BitMode] in {
237+
def INC8r_ND : IncOpR_RF<Xi8, 1>;
238+
def INC16r_ND : IncOpR_RF<Xi16, 1>, PD;
239+
def INC32r_ND : IncOpR_RF<Xi32, 1>;
240+
def INC64r_ND : IncOpR_RF<Xi64, 1>;
241+
def DEC8r_ND : DecOpR_RF<Xi8, 1>;
242+
def DEC16r_ND : DecOpR_RF<Xi16, 1>, PD;
243+
def DEC32r_ND : DecOpR_RF<Xi32, 1>;
244+
def DEC64r_ND : DecOpR_RF<Xi64, 1>;
245+
}
246+
let Predicates = [In64BitMode], Pattern = [(null_frag)] in {
247+
def INC8r_NF : IncOpR_R<Xi8>, NF;
248+
def INC16r_NF : IncOpR_R<Xi16>, NF, PD;
249+
def INC32r_NF : IncOpR_R<Xi32>, NF;
250+
def INC64r_NF : IncOpR_R<Xi64>, NF;
251+
def DEC8r_NF : DecOpR_R<Xi8>, NF;
252+
def DEC16r_NF : DecOpR_R<Xi16>, NF, PD;
253+
def DEC32r_NF : DecOpR_R<Xi32>, NF;
254+
def DEC64r_NF : DecOpR_R<Xi64>, NF;
255+
def INC8r_NF_ND : IncOpR_R<Xi8, 1>, NF;
256+
def INC16r_NF_ND : IncOpR_R<Xi16, 1>, NF, PD;
257+
def INC32r_NF_ND : IncOpR_R<Xi32, 1>, NF;
258+
def INC64r_NF_ND : IncOpR_R<Xi64, 1>, NF;
259+
def DEC8r_NF_ND : DecOpR_R<Xi8, 1>, NF;
260+
def DEC16r_NF_ND : DecOpR_R<Xi16, 1>, NF, PD;
261+
def DEC32r_NF_ND : DecOpR_R<Xi32, 1>, NF;
262+
def DEC64r_NF_ND : DecOpR_R<Xi64, 1>, NF;
263+
def INC8r_EVEX : IncOpR_RF<Xi8>, PL;
264+
def INC16r_EVEX : IncOpR_RF<Xi16>, PL, PD;
265+
def INC32r_EVEX : IncOpR_RF<Xi32>, PL;
266+
def INC64r_EVEX : IncOpR_RF<Xi64>, PL;
267+
def DEC8r_EVEX : DecOpR_RF<Xi8>, PL;
268+
def DEC16r_EVEX : DecOpR_RF<Xi16>, PL, PD;
269+
def DEC32r_EVEX : DecOpR_RF<Xi32>, PL;
270+
def DEC64r_EVEX : DecOpR_RF<Xi64>, PL;
271+
}
221272
}
222273
let Predicates = [UseIncDec] in {
223-
def INC8m : IncOpM_M<Xi8>;
224-
def INC16m : IncOpM_M<Xi16>, OpSize16;
225-
def INC32m : IncOpM_M<Xi32>, OpSize32;
226-
def DEC8m : DecOpM_M<Xi8>;
227-
def DEC16m : DecOpM_M<Xi16>, OpSize16;
228-
def DEC32m : DecOpM_M<Xi32>, OpSize32;
274+
def INC8m : IncOpM_MF<Xi8>;
275+
def INC16m : IncOpM_MF<Xi16>, OpSize16;
276+
def INC32m : IncOpM_MF<Xi32>, OpSize32;
277+
def DEC8m : DecOpM_MF<Xi8>;
278+
def DEC16m : DecOpM_MF<Xi16>, OpSize16;
279+
def DEC32m : DecOpM_MF<Xi32>, OpSize32;
229280
}
230281
let Predicates = [UseIncDec, In64BitMode] in {
231-
def INC64m : IncOpM_M<Xi64>;
232-
def DEC64m : DecOpM_M<Xi64>;
282+
def INC64m : IncOpM_MF<Xi64>;
283+
def DEC64m : DecOpM_MF<Xi64>;
284+
}
285+
let Predicates = [HasNDD, In64BitMode, UseIncDec] in {
286+
def INC8m_ND : IncOpM_RF<Xi8>;
287+
def INC16m_ND : IncOpM_RF<Xi16>, PD;
288+
def INC32m_ND : IncOpM_RF<Xi32>;
289+
def DEC8m_ND : DecOpM_RF<Xi8>;
290+
def DEC16m_ND : DecOpM_RF<Xi16>, PD;
291+
def DEC32m_ND : DecOpM_RF<Xi32>;
292+
def INC64m_ND : IncOpM_RF<Xi64>;
293+
def DEC64m_ND : DecOpM_RF<Xi64>;
294+
}
295+
let Predicates = [In64BitMode], Pattern = [(null_frag)] in {
296+
def INC8m_NF : IncOpM_M<Xi8>, NF;
297+
def INC16m_NF : IncOpM_M<Xi16>, NF, PD;
298+
def INC32m_NF : IncOpM_M<Xi32>, NF;
299+
def INC64m_NF : IncOpM_M<Xi64>, NF;
300+
def DEC8m_NF : DecOpM_M<Xi8>, NF;
301+
def DEC16m_NF : DecOpM_M<Xi16>, NF, PD;
302+
def DEC32m_NF : DecOpM_M<Xi32>, NF;
303+
def DEC64m_NF : DecOpM_M<Xi64>, NF;
304+
def INC8m_NF_ND : IncOpM_R<Xi8>, NF;
305+
def INC16m_NF_ND : IncOpM_R<Xi16>, NF, PD;
306+
def INC32m_NF_ND : IncOpM_R<Xi32>, NF;
307+
def INC64m_NF_ND : IncOpM_R<Xi64>, NF;
308+
def DEC8m_NF_ND : DecOpM_R<Xi8>, NF;
309+
def DEC16m_NF_ND : DecOpM_R<Xi16>, NF, PD;
310+
def DEC32m_NF_ND : DecOpM_R<Xi32>, NF;
311+
def DEC64m_NF_ND : DecOpM_R<Xi64>, NF;
312+
def INC8m_EVEX : IncOpM_MF<Xi8>, PL;
313+
def INC16m_EVEX : IncOpM_MF<Xi16>, PL, PD;
314+
def INC32m_EVEX : IncOpM_MF<Xi32>, PL;
315+
def INC64m_EVEX : IncOpM_MF<Xi64>, PL;
316+
def DEC8m_EVEX : DecOpM_MF<Xi8>, PL;
317+
def DEC16m_EVEX : DecOpM_MF<Xi16>, PL, PD;
318+
def DEC32m_EVEX : DecOpM_MF<Xi32>, PL;
319+
def DEC64m_EVEX : DecOpM_MF<Xi64>, PL;
233320
}
234321

235322
//===----------------------------------------------------------------------===//
@@ -1119,14 +1206,34 @@ defm MULX64 : MulX<Xi64, WriteMULX64>, REX_W;
11191206
// We don't have patterns for these as there is no advantage over ADC for
11201207
// most code.
11211208
let Form = MRMSrcReg in {
1122-
def ADCX32rr : BinOpRRF_RF<0xF6, "adcx", Xi32, null_frag>, T8, PD;
1123-
def ADCX64rr : BinOpRRF_RF<0xF6, "adcx", Xi64, null_frag>, T8, PD;
1124-
def ADOX32rr : BinOpRRF_RF<0xF6, "adox", Xi32, null_frag>, T8, XS;
1125-
def ADOX64rr : BinOpRRF_RF<0xF6, "adox", Xi64, null_frag>, T8, XS;
1209+
def ADCX32rr : BinOpRRF_RF<0xF6, "adcx", Xi32>, T8, PD;
1210+
def ADCX64rr : BinOpRRF_RF<0xF6, "adcx", Xi64>, T8, PD;
1211+
def ADOX32rr : BinOpRRF_RF<0xF6, "adox", Xi32>, T8, XS;
1212+
def ADOX64rr : BinOpRRF_RF<0xF6, "adox", Xi64>, T8, XS;
1213+
let Predicates =[In64BitMode] in {
1214+
def ADCX32rr_EVEX : BinOpRRF_RF<0x66, "adcx", Xi32>, EVEX, T_MAP4, PD;
1215+
def ADCX64rr_EVEX : BinOpRRF_RF<0x66, "adcx", Xi64>, EVEX, T_MAP4, PD;
1216+
def ADOX32rr_EVEX : BinOpRRF_RF<0x66, "adox", Xi32>, EVEX, T_MAP4, XS;
1217+
def ADOX64rr_EVEX : BinOpRRF_RF<0x66, "adox", Xi64>, EVEX, T_MAP4, XS;
1218+
def ADCX32rr_ND : BinOpRRF_RF<0x66, "adcx", Xi32, null_frag, 1>, PD;
1219+
def ADCX64rr_ND : BinOpRRF_RF<0x66, "adcx", Xi64, null_frag, 1>, PD;
1220+
def ADOX32rr_ND : BinOpRRF_RF<0x66, "adox", Xi32, null_frag, 1>, XS;
1221+
def ADOX64rr_ND : BinOpRRF_RF<0x66, "adox", Xi64, null_frag, 1>, XS;
1222+
}
11261223
}
11271224
let Form = MRMSrcMem in {
1128-
def ADCX32rm : BinOpRMF_RF<0xF6, "adcx", Xi32, null_frag>, T8, PD;
1129-
def ADCX64rm : BinOpRMF_RF<0xF6, "adcx", Xi64, null_frag>, T8, PD;
1130-
def ADOX32rm : BinOpRMF_RF<0xF6, "adox", Xi32, null_frag>, T8, XS;
1131-
def ADOX64rm : BinOpRMF_RF<0xF6, "adox", Xi64, null_frag>, T8, XS;
1225+
def ADCX32rm : BinOpRMF_RF<0xF6, "adcx", Xi32>, T8, PD;
1226+
def ADCX64rm : BinOpRMF_RF<0xF6, "adcx", Xi64>, T8, PD;
1227+
def ADOX32rm : BinOpRMF_RF<0xF6, "adox", Xi32>, T8, XS;
1228+
def ADOX64rm : BinOpRMF_RF<0xF6, "adox", Xi64>, T8, XS;
1229+
let Predicates =[In64BitMode] in {
1230+
def ADCX32rm_EVEX : BinOpRMF_RF<0x66, "adcx", Xi32>, EVEX, T_MAP4, PD;
1231+
def ADCX64rm_EVEX : BinOpRMF_RF<0x66, "adcx", Xi64>, EVEX, T_MAP4, PD;
1232+
def ADOX32rm_EVEX : BinOpRMF_RF<0x66, "adox", Xi32>, EVEX, T_MAP4, XS;
1233+
def ADOX64rm_EVEX : BinOpRMF_RF<0x66, "adox", Xi64>, EVEX, T_MAP4, XS;
1234+
def ADCX32rm_ND : BinOpRMF_RF<0x66, "adcx", Xi32, null_frag, 1>, PD;
1235+
def ADCX64rm_ND : BinOpRMF_RF<0x66, "adcx", Xi64, null_frag, 1>, PD;
1236+
def ADOX32rm_ND : BinOpRMF_RF<0x66, "adox", Xi32, null_frag, 1>, XS;
1237+
def ADOX64rm_ND : BinOpRMF_RF<0x66, "adox", Xi64, null_frag, 1>, XS;
1238+
}
11321239
}

llvm/lib/Target/X86/X86InstrUtils.td

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1005,7 +1005,7 @@ class BinOpRR_RF_Rev<bits<8> o, string m, X86TypeInfo t, bit ndd = 0>
10051005
}
10061006
// BinOpRRF_RF - Instructions that read "reg, reg", write "reg" and read/write
10071007
// EFLAGS.
1008-
class BinOpRRF_RF<bits<8> o, string m, X86TypeInfo t, SDPatternOperator node, bit ndd = 0>
1008+
class BinOpRRF_RF<bits<8> o, string m, X86TypeInfo t, SDPatternOperator node = null_frag, bit ndd = 0>
10091009
: BinOpRR<o, m, !if(!eq(ndd, 0), binop_args, binop_ndd_args), t, (outs t.RegClass:$dst),
10101010
[(set t.RegClass:$dst, EFLAGS,
10111011
(node t.RegClass:$src1, t.RegClass:$src2,
@@ -1041,7 +1041,7 @@ class BinOpRM_RF<bits<8> o, string m, X86TypeInfo t, SDPatternOperator node, bit
10411041
(t.LoadNode addr:$src2)))]>, DefEFLAGS, NDD<ndd>;
10421042
// BinOpRMF_RF - Instructions that read "reg, [mem]", write "reg" and read/write
10431043
// EFLAGS.
1044-
class BinOpRMF_RF<bits<8> o, string m, X86TypeInfo t, SDPatternOperator node, bit ndd = 0>
1044+
class BinOpRMF_RF<bits<8> o, string m, X86TypeInfo t, SDPatternOperator node = null_frag, bit ndd = 0>
10451045
: BinOpRM<o, m, !if(!eq(ndd, 0), binop_args, binop_ndd_args), t, (outs t.RegClass:$dst),
10461046
[(set t.RegClass:$dst, EFLAGS,
10471047
(node t.RegClass:$src1, (t.LoadNode addr:$src2), EFLAGS))]>,
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
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: adcxl %r16d, %r17d
5+
# INTEL: adcx r17d, r16d
6+
0x62,0xec,0x7d,0x08,0x66,0xc8
7+
8+
# ATT: adcxl %r16d, %r17d, %r18d
9+
# INTEL: adcx r18d, r17d, r16d
10+
0x62,0xec,0x6d,0x10,0x66,0xc8
11+
12+
# ATT: adcxq %r16, %r17
13+
# INTEL: adcx r17, r16
14+
0x62,0xec,0xfd,0x08,0x66,0xc8
15+
16+
# ATT: adcxq %r16, %r17, %r18
17+
# INTEL: adcx r18, r17, r16
18+
0x62,0xec,0xed,0x10,0x66,0xc8
19+
20+
# ATT: adcxl (%r16), %r17d
21+
# INTEL: adcx r17d, dword ptr [r16]
22+
0x62,0xec,0x7d,0x08,0x66,0x08
23+
24+
# ATT: adcxl (%r16), %r17d, %r18d
25+
# INTEL: adcx r18d, r17d, dword ptr [r16]
26+
0x62,0xec,0x6d,0x10,0x66,0x08
27+
28+
# ATT: adcxq (%r16), %r17
29+
# INTEL: adcx r17, qword ptr [r16]
30+
0x62,0xec,0xfd,0x08,0x66,0x08
31+
32+
# ATT: adcxq (%r16), %r17, %r18
33+
# INTEL: adcx r18, r17, qword ptr [r16]
34+
0x62,0xec,0xed,0x10,0x66,0x08
35+
36+
# ATT: adoxl %r16d, %r17d
37+
# INTEL: adox r17d, r16d
38+
0x62,0xec,0x7e,0x08,0x66,0xc8
39+
40+
# ATT: adoxl %r16d, %r17d, %r18d
41+
# INTEL: adox r18d, r17d, r16d
42+
0x62,0xec,0x6e,0x10,0x66,0xc8
43+
44+
# ATT: adoxq %r16, %r17
45+
# INTEL: adox r17, r16
46+
0x62,0xec,0xfe,0x08,0x66,0xc8
47+
48+
# ATT: adoxq %r16, %r17, %r18
49+
# INTEL: adox r18, r17, r16
50+
0x62,0xec,0xee,0x10,0x66,0xc8
51+
52+
# ATT: adoxl (%r16), %r17d
53+
# INTEL: adox r17d, dword ptr [r16]
54+
0x62,0xec,0x7e,0x08,0x66,0x08
55+
56+
# ATT: adoxl (%r16), %r17d, %r18d
57+
# INTEL: adox r18d, r17d, dword ptr [r16]
58+
0x62,0xec,0x6e,0x10,0x66,0x08
59+
60+
# ATT: adoxq (%r16), %r17
61+
# INTEL: adox r17, qword ptr [r16]
62+
0x62,0xec,0xfe,0x08,0x66,0x08
63+
64+
# ATT: adoxq (%r16), %r17, %r18
65+
# INTEL: adox r18, r17, qword ptr [r16]
66+
0x62,0xec,0xee,0x10,0x66,0x08

0 commit comments

Comments
 (0)