Skip to content

[X86][MC] Support encoding/decoding for APX variant MUL/IMUL/DIV/IDIV instructions #76919

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 8 commits into from
Jan 5, 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
283 changes: 218 additions & 65 deletions llvm/lib/Target/X86/X86InstrArithmetic.td

Large diffs are not rendered by default.

33 changes: 33 additions & 0 deletions llvm/lib/Target/X86/X86InstrPredicates.td
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,41 @@

def TruePredicate : Predicate<"true">;

// Intel x86 instructions have three separate encoding spaces: legacy, VEX, and
// EVEX. Not all X86 instructions are extended for EGPR. The following is an
// overview of which instructions are extended and how we implement them.
//
// * Legacy space
// All instructions in legacy maps 0 and 1 that have explicit GPR or memory
// operands can use the REX2 prefix to access the EGPR, except XSAVE*/XRSTOR.
//
// * EVEX space
// All instructions in the EVEX space can access the EGPR in their
// register/memory operands.
//
// For the above intructions, the only difference in encoding is reflected in
// the REX2/EVEX prefix when EGPR is used, i.e. the opcode and opcode name are
// unchanged. We don’t add new entries in TD, and instead we extend GPR with
// R16-R31 and make them allocatable only when the feature EGPR is available.
//
// Besides, some instructions in legacy space with map 2/3 and VEX space are
// promoted into EVEX space. Encoding space changes after the promotion, opcode
// and opcode map may change too sometimes. For these instructions, we add new
// entries in TD to avoid overcomplicating the assembler and disassembler.
//
// HasEGPR is for the new entries and NoEGPR is for the entries before
// promotion, so that the promoted variant can be selected first to benefit RA.
def HasEGPR : Predicate<"Subtarget->hasEGPR()">;
def NoEGPR : Predicate<"!Subtarget->hasEGPR()">;

// APX extends some instructions with a new form that has an extra register
// operand called a new data destination (NDD). In such forms, NDD is the new
// destination register receiving the result of the computation and all other
Copy link
Contributor

Choose a reason for hiding this comment

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

receiving -> holds/preserves?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

No. It 's copied from 3.1.2.2 New Data Destination. The verb here is used as a postpositional attributive and requires the ing form.

// operands (including the original destination operand) become read-only source
// operands.
//
// HasNDD is for the new NDD entries and NoNDD is for the legacy 2-address
// entries, so that the NDD variant can be selected first to benefit RA.
def HasNDD : Predicate<"Subtarget->hasNDD()">;
def NoNDD : Predicate<"!Subtarget->hasNDD()">;
def HasCMOV : Predicate<"Subtarget->canUseCMOV()">;
Expand Down
66 changes: 66 additions & 0 deletions llvm/test/MC/Disassembler/X86/apx/div.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: {evex} divb %bl
# INTEL: {evex} div bl
0x62,0xf4,0x7c,0x08,0xf6,0xf3

# ATT: {nf} divb %bl
# INTEL: {nf} div bl
0x62,0xf4,0x7c,0x0c,0xf6,0xf3

# ATT: {evex} divw %dx
# INTEL: {evex} div dx
0x62,0xf4,0x7d,0x08,0xf7,0xf2

# ATT: {nf} divw %dx
# INTEL: {nf} div dx
0x62,0xf4,0x7d,0x0c,0xf7,0xf2

# ATT: {evex} divl %ecx
# INTEL: {evex} div ecx
0x62,0xf4,0x7c,0x08,0xf7,0xf1

# ATT: {nf} divl %ecx
# INTEL: {nf} div ecx
0x62,0xf4,0x7c,0x0c,0xf7,0xf1

# ATT: {evex} divq %r9
# INTEL: {evex} div r9
0x62,0xd4,0xfc,0x08,0xf7,0xf1

# ATT: {nf} divq %r9
# INTEL: {nf} div r9
0x62,0xd4,0xfc,0x0c,0xf7,0xf1

# ATT: {evex} divb 291(%r8,%rax,4)
# INTEL: {evex} div byte ptr [r8 + 4*rax + 291]
0x62,0xd4,0x7c,0x08,0xf6,0xb4,0x80,0x23,0x01,0x00,0x00

# ATT: {nf} divb 291(%r8,%rax,4)
# INTEL: {nf} div byte ptr [r8 + 4*rax + 291]
0x62,0xd4,0x7c,0x0c,0xf6,0xb4,0x80,0x23,0x01,0x00,0x00

# ATT: {evex} divw 291(%r8,%rax,4)
# INTEL: {evex} div word ptr [r8 + 4*rax + 291]
0x62,0xd4,0x7d,0x08,0xf7,0xb4,0x80,0x23,0x01,0x00,0x00

# ATT: {nf} divw 291(%r8,%rax,4)
# INTEL: {nf} div word ptr [r8 + 4*rax + 291]
0x62,0xd4,0x7d,0x0c,0xf7,0xb4,0x80,0x23,0x01,0x00,0x00

# ATT: {evex} divl 291(%r8,%rax,4)
# INTEL: {evex} div dword ptr [r8 + 4*rax + 291]
0x62,0xd4,0x7c,0x08,0xf7,0xb4,0x80,0x23,0x01,0x00,0x00

# ATT: {nf} divl 291(%r8,%rax,4)
# INTEL: {nf} div dword ptr [r8 + 4*rax + 291]
0x62,0xd4,0x7c,0x0c,0xf7,0xb4,0x80,0x23,0x01,0x00,0x00

# ATT: {evex} divq 291(%r8,%rax,4)
# INTEL: {evex} div qword ptr [r8 + 4*rax + 291]
0x62,0xd4,0xfc,0x08,0xf7,0xb4,0x80,0x23,0x01,0x00,0x00

# ATT: {nf} divq 291(%r8,%rax,4)
# INTEL: {nf} div qword ptr [r8 + 4*rax + 291]
0x62,0xd4,0xfc,0x0c,0xf7,0xb4,0x80,0x23,0x01,0x00,0x00
66 changes: 66 additions & 0 deletions llvm/test/MC/Disassembler/X86/apx/idiv.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: {evex} idivb %bl
# INTEL: {evex} idiv bl
0x62,0xf4,0x7c,0x08,0xf6,0xfb

# ATT: {nf} idivb %bl
# INTEL: {nf} idiv bl
0x62,0xf4,0x7c,0x0c,0xf6,0xfb

# ATT: {evex} idivw %dx
# INTEL: {evex} idiv dx
0x62,0xf4,0x7d,0x08,0xf7,0xfa

# ATT: {nf} idivw %dx
# INTEL: {nf} idiv dx
0x62,0xf4,0x7d,0x0c,0xf7,0xfa

# ATT: {evex} idivl %ecx
# INTEL: {evex} idiv ecx
0x62,0xf4,0x7c,0x08,0xf7,0xf9

# ATT: {nf} idivl %ecx
# INTEL: {nf} idiv ecx
0x62,0xf4,0x7c,0x0c,0xf7,0xf9

# ATT: {evex} idivq %r9
# INTEL: {evex} idiv r9
0x62,0xd4,0xfc,0x08,0xf7,0xf9

# ATT: {nf} idivq %r9
# INTEL: {nf} idiv r9
0x62,0xd4,0xfc,0x0c,0xf7,0xf9

# ATT: {evex} idivb 291(%r8,%rax,4)
# INTEL: {evex} idiv byte ptr [r8 + 4*rax + 291]
0x62,0xd4,0x7c,0x08,0xf6,0xbc,0x80,0x23,0x01,0x00,0x00

# ATT: {nf} idivb 291(%r8,%rax,4)
# INTEL: {nf} idiv byte ptr [r8 + 4*rax + 291]
0x62,0xd4,0x7c,0x0c,0xf6,0xbc,0x80,0x23,0x01,0x00,0x00

# ATT: {evex} idivw 291(%r8,%rax,4)
# INTEL: {evex} idiv word ptr [r8 + 4*rax + 291]
0x62,0xd4,0x7d,0x08,0xf7,0xbc,0x80,0x23,0x01,0x00,0x00

# ATT: {nf} idivw 291(%r8,%rax,4)
# INTEL: {nf} idiv word ptr [r8 + 4*rax + 291]
0x62,0xd4,0x7d,0x0c,0xf7,0xbc,0x80,0x23,0x01,0x00,0x00

# ATT: {evex} idivl 291(%r8,%rax,4)
# INTEL: {evex} idiv dword ptr [r8 + 4*rax + 291]
0x62,0xd4,0x7c,0x08,0xf7,0xbc,0x80,0x23,0x01,0x00,0x00

# ATT: {nf} idivl 291(%r8,%rax,4)
# INTEL: {nf} idiv dword ptr [r8 + 4*rax + 291]
0x62,0xd4,0x7c,0x0c,0xf7,0xbc,0x80,0x23,0x01,0x00,0x00

# ATT: {evex} idivq 291(%r8,%rax,4)
# INTEL: {evex} idiv qword ptr [r8 + 4*rax + 291]
0x62,0xd4,0xfc,0x08,0xf7,0xbc,0x80,0x23,0x01,0x00,0x00

# ATT: {nf} idivq 291(%r8,%rax,4)
# INTEL: {nf} idiv qword ptr [r8 + 4*rax + 291]
0x62,0xd4,0xfc,0x0c,0xf7,0xbc,0x80,0x23,0x01,0x00,0x00
Loading