[llvm] X86: Stop overriding getRegClass (PR #223740)
Matt Arsenault via llvm-commits
llvm-commits at lists.llvm.org
Mon Sep 21 05:48:02 PDT 2026
https://github.com/arsenm updated https://github.com/llvm/llvm-project/pull/223740
>From 78ba1dce1a8152119a4290a1ce927b541a3f6b57 Mon Sep 17 00:00:00 2001
From: Matt Arsenault <Matthew.Arsenault at amd.com>
Date: Sun, 24 Aug 2025 10:44:00 +0900
Subject: [PATCH 1/3] X86: Stop overriding getRegClass
Making TargetInstrInfo::getRegClass virtual was an AMDGPU hack that should not
spread to other backends (X86 overrode it in #70958). The override kept GPR
operands out of the *_NOREX2 subclasses for instructions that cannot encode
r16-r31 with EGPR. Express this constraint with RegClassByHwMode instead, which
allows dropping the virtual.
This also enables the machine verifier to enforce the constraint, which was
previously ignored. Also fixes missing assembler tests enforcing the constraint.
There is custom assembler code for this case which may be deletable after this.
I don't really know about all the X86isms here, AI did most of that.
Co-authored-by: Claude (Opus 4.8) <noreply at anthropic.com>
---
llvm/include/llvm/CodeGen/TargetInstrInfo.h | 4 +-
llvm/lib/Target/X86/X86InstrAMX.td | 22 +--
llvm/lib/Target/X86/X86InstrFPStack.td | 130 +++++++++---------
llvm/lib/Target/X86/X86InstrInfo.cpp | 15 --
llvm/lib/Target/X86/X86InstrInfo.h | 9 --
llvm/lib/Target/X86/X86InstrOperands.td | 73 ++++++++--
llvm/lib/Target/X86/X86InstrPredicates.td | 14 +-
llvm/lib/Target/X86/X86InstrSSE.td | 80 +++++------
llvm/lib/Target/X86/X86InstrSystem.td | 24 ++--
llvm/lib/Target/X86/X86InstrTBM.td | 16 +--
llvm/test/MC/X86/apx/no-rex2-reject.s | 33 +++++
.../X86/apx-norex2-regclass.mir | 62 +++++++++
llvm/test/MachineVerifier/X86/lit.local.cfg | 2 +
llvm/utils/TableGen/AsmMatcherEmitter.cpp | 14 ++
llvm/utils/TableGen/X86FoldTablesEmitter.cpp | 12 +-
llvm/utils/TableGen/X86RecognizableInstr.cpp | 74 ++++++----
16 files changed, 380 insertions(+), 204 deletions(-)
create mode 100644 llvm/test/MC/X86/apx/no-rex2-reject.s
create mode 100644 llvm/test/MachineVerifier/X86/apx-norex2-regclass.mir
create mode 100644 llvm/test/MachineVerifier/X86/lit.local.cfg
diff --git a/llvm/include/llvm/CodeGen/TargetInstrInfo.h b/llvm/include/llvm/CodeGen/TargetInstrInfo.h
index b013511d33313..94a11a38f1bb7 100644
--- a/llvm/include/llvm/CodeGen/TargetInstrInfo.h
+++ b/llvm/include/llvm/CodeGen/TargetInstrInfo.h
@@ -161,8 +161,8 @@ class LLVM_ABI TargetInstrInfo : public MCInstrInfo {
/// Given a machine instruction descriptor, returns the register
/// class constraint for OpNum, or NULL.
- virtual const TargetRegisterClass *getRegClass(const MCInstrDesc &MCID,
- unsigned OpNum) const;
+ const TargetRegisterClass *getRegClass(const MCInstrDesc &MCID,
+ unsigned OpNum) const;
/// Return the register class to use for the register operand of an inline asm
/// memory operand with constraint \p C.
diff --git a/llvm/lib/Target/X86/X86InstrAMX.td b/llvm/lib/Target/X86/X86InstrAMX.td
index 418046479a8a0..01ce23511a9ef 100644
--- a/llvm/lib/Target/X86/X86InstrAMX.td
+++ b/llvm/lib/Target/X86/X86InstrAMX.td
@@ -60,18 +60,18 @@ let SchedRW = [WriteSystem] in {
// Pseduo instruction for RA.
let isPseudo = true, mayLoad = 1, hasSideEffects = 1,
Defs = [TMM0,TMM1,TMM2,TMM3,TMM4,TMM5,TMM6,TMM7] in
- def PLDTILECFGV : PseudoI<(outs), (ins opaquemem:$src), []>;
+ def PLDTILECFGV : PseudoI<(outs), (ins opaquemem_norex2:$src), []>;
let isPseudo = true, mayLoad = 1 in
def PTILELOADDV : PseudoI<(outs TILE:$dst), (ins GR16:$src1,
GR16:$src2,
- opaquemem:$src3), []>;
+ opaquemem_norex2:$src3), []>;
let isPseudo = true, mayLoad = 1 in
def PTILELOADDT1V : PseudoI<(outs TILE:$dst), (ins GR16:$src1,
GR16:$src2,
- opaquemem:$src3), []>;
+ opaquemem_norex2:$src3), []>;
let isPseudo = true, mayStore = 1 in
def PTILESTOREDV : PseudoI<(outs), (ins GR16:$src1,
- GR16:$src2, opaquemem:$src3,
+ GR16:$src2, opaquemem_norex2:$src3,
TILE:$src4), []>;
let isPseudo = true, isReMaterializable = 1, isAsCheapAsAMove = 1,
canFoldAsLoad = 1, usesCustomInserter = 1 in
@@ -83,12 +83,12 @@ let SchedRW = [WriteSystem] in {
// Pseudo instructions, using immediates instead of tile registers.
// To be translated to the actual instructions in X86ISelLowering.cpp
let mayLoad = 1 in
- def PTILELOADD : PseudoI<(outs), (ins u8imm:$src1, sibmem:$src2), []>;
+ def PTILELOADD : PseudoI<(outs), (ins u8imm:$src1, sibmem_norex2:$src2), []>;
let mayLoad = 1 in
def PTILELOADDT1 : PseudoI<(outs), (ins u8imm:$src1,
- sibmem:$src2), []>;
+ sibmem_norex2:$src2), []>;
let mayStore = 1 in
- def PTILESTORED : PseudoI<(outs), (ins i8mem:$dst, u8imm:$src), []>;
+ def PTILESTORED : PseudoI<(outs), (ins i8mem_norex2:$dst, u8imm:$src), []>;
def PTILEZERO : PseudoI<(outs), (ins u8imm:$src),
[(int_x86_tilezero timm:$src)]>;
}
@@ -355,15 +355,15 @@ let Predicates = [HasAMXMOVRS, In64BitMode], SchedRW = [WriteSystem] in {
let isPseudo = true, mayLoad = 1 in {
def PTILELOADDRSV : PseudoI<(outs TILE:$dst), (ins GR16:$src1,
GR16:$src2,
- opaquemem:$src3), []>;
+ opaquemem_norex2:$src3), []>;
def PTILELOADDRST1V : PseudoI<(outs TILE:$dst), (ins GR16:$src1,
GR16:$src2,
- opaquemem:$src3), []>;
+ opaquemem_norex2:$src3), []>;
}
let usesCustomInserter = 1, mayLoad = 1 in {
- def PTILELOADDRS : PseudoI<(outs), (ins u8imm:$src1, sibmem:$src2), []>;
- def PTILELOADDRST1 : PseudoI<(outs), (ins u8imm:$src1, sibmem:$src2), []>;
+ def PTILELOADDRS : PseudoI<(outs), (ins u8imm:$src1, sibmem_norex2:$src2), []>;
+ def PTILELOADDRST1 : PseudoI<(outs), (ins u8imm:$src1, sibmem_norex2:$src2), []>;
}
} // HasAMXMOVRS, In64BitMode
diff --git a/llvm/lib/Target/X86/X86InstrFPStack.td b/llvm/lib/Target/X86/X86InstrFPStack.td
index 6a9a74ce15f2a..4cd88c3fcf99f 100644
--- a/llvm/lib/Target/X86/X86InstrFPStack.td
+++ b/llvm/lib/Target/X86/X86InstrFPStack.td
@@ -16,29 +16,29 @@
// Clobbers EFLAGS due to OR instruction used internally.
// FIXME: Can we model this in SelectionDAG?
let usesCustomInserter = 1, hasNoSchedulingInfo = 1, Defs = [EFLAGS] in {
- def FP32_TO_INT16_IN_MEM : PseudoI<(outs), (ins i16mem:$dst, RFP32:$src),
+ def FP32_TO_INT16_IN_MEM : PseudoI<(outs), (ins i16mem_norex2:$dst, RFP32:$src),
[(X86fp_to_i16mem RFP32:$src, addr:$dst)]>;
- def FP32_TO_INT32_IN_MEM : PseudoI<(outs), (ins i32mem:$dst, RFP32:$src),
+ def FP32_TO_INT32_IN_MEM : PseudoI<(outs), (ins i32mem_norex2:$dst, RFP32:$src),
[(X86fp_to_i32mem RFP32:$src, addr:$dst)]>;
- def FP32_TO_INT64_IN_MEM : PseudoI<(outs), (ins i64mem:$dst, RFP32:$src),
+ def FP32_TO_INT64_IN_MEM : PseudoI<(outs), (ins i64mem_norex2:$dst, RFP32:$src),
[(X86fp_to_i64mem RFP32:$src, addr:$dst)]>;
- def FP64_TO_INT16_IN_MEM : PseudoI<(outs), (ins i16mem:$dst, RFP64:$src),
+ def FP64_TO_INT16_IN_MEM : PseudoI<(outs), (ins i16mem_norex2:$dst, RFP64:$src),
[(X86fp_to_i16mem RFP64:$src, addr:$dst)]>;
- def FP64_TO_INT32_IN_MEM : PseudoI<(outs), (ins i32mem:$dst, RFP64:$src),
+ def FP64_TO_INT32_IN_MEM : PseudoI<(outs), (ins i32mem_norex2:$dst, RFP64:$src),
[(X86fp_to_i32mem RFP64:$src, addr:$dst)]>;
- def FP64_TO_INT64_IN_MEM : PseudoI<(outs), (ins i64mem:$dst, RFP64:$src),
+ def FP64_TO_INT64_IN_MEM : PseudoI<(outs), (ins i64mem_norex2:$dst, RFP64:$src),
[(X86fp_to_i64mem RFP64:$src, addr:$dst)]>;
- def FP80_TO_INT16_IN_MEM : PseudoI<(outs), (ins i16mem:$dst, RFP80:$src),
+ def FP80_TO_INT16_IN_MEM : PseudoI<(outs), (ins i16mem_norex2:$dst, RFP80:$src),
[(X86fp_to_i16mem RFP80:$src, addr:$dst)]>;
- def FP80_TO_INT32_IN_MEM : PseudoI<(outs), (ins i32mem:$dst, RFP80:$src),
+ def FP80_TO_INT32_IN_MEM : PseudoI<(outs), (ins i32mem_norex2:$dst, RFP80:$src),
[(X86fp_to_i32mem RFP80:$src, addr:$dst)]>;
- def FP80_TO_INT64_IN_MEM : PseudoI<(outs), (ins i64mem:$dst, RFP80:$src),
+ def FP80_TO_INT64_IN_MEM : PseudoI<(outs), (ins i64mem_norex2:$dst, RFP80:$src),
[(X86fp_to_i64mem RFP80:$src, addr:$dst)]>;
def FP80_ADDr : PseudoI<(outs RFP80:$dst), (ins RFP80:$src1, RFP80:$src2),
[(set RFP80:$dst,
(any_X86fp80_add RFP80:$src1, RFP80:$src2))]>;
- def FP80_ADDm32 : PseudoI<(outs RFP80:$dst), (ins RFP80:$src1, f32mem:$src2),
+ def FP80_ADDm32 : PseudoI<(outs RFP80:$dst), (ins RFP80:$src1, f32mem_norex2:$src2),
[(set RFP80:$dst,
(any_X86fp80_add RFP80:$src1,
(f80 (extloadf32 addr:$src2))))]>;
@@ -90,35 +90,35 @@ multiclass FPBinary<SDPatternOperator OpNode, Format fp, string asmstring,
bit Forward = 1> {
// ST(0) = ST(0) + [mem]
def _Fp32m : FpIf32<(outs RFP32:$dst),
- (ins RFP32:$src1, f32mem:$src2), OneArgFPRW,
+ (ins RFP32:$src1, f32mem_norex2:$src2), OneArgFPRW,
[!if(Forward,
(set RFP32:$dst,
(OpNode RFP32:$src1, (loadf32 addr:$src2))),
(set RFP32:$dst,
(OpNode (loadf32 addr:$src2), RFP32:$src1)))]>;
def _Fp64m : FpIf64<(outs RFP64:$dst),
- (ins RFP64:$src1, f64mem:$src2), OneArgFPRW,
+ (ins RFP64:$src1, f64mem_norex2:$src2), OneArgFPRW,
[!if(Forward,
(set RFP64:$dst,
(OpNode RFP64:$src1, (loadf64 addr:$src2))),
(set RFP64:$dst,
(OpNode (loadf64 addr:$src2), RFP64:$src1)))]>;
def _Fp64m32: FpIf64<(outs RFP64:$dst),
- (ins RFP64:$src1, f32mem:$src2), OneArgFPRW,
+ (ins RFP64:$src1, f32mem_norex2:$src2), OneArgFPRW,
[!if(Forward,
(set RFP64:$dst,
(OpNode RFP64:$src1, (f64 (extloadf32 addr:$src2)))),
(set RFP64:$dst,
(OpNode (f64 (extloadf32 addr:$src2)), RFP64:$src1)))]>;
def _Fp80m32: FpI_<(outs RFP80:$dst),
- (ins RFP80:$src1, f32mem:$src2), OneArgFPRW,
+ (ins RFP80:$src1, f32mem_norex2:$src2), OneArgFPRW,
[!if(Forward,
(set RFP80:$dst,
(OpNode RFP80:$src1, (f80 (extloadf32 addr:$src2)))),
(set RFP80:$dst,
(OpNode (f80 (extloadf32 addr:$src2)), RFP80:$src1)))]>;
def _Fp80m64: FpI_<(outs RFP80:$dst),
- (ins RFP80:$src1, f64mem:$src2), OneArgFPRW,
+ (ins RFP80:$src1, f64mem_norex2:$src2), OneArgFPRW,
[!if(Forward,
(set RFP80:$dst,
(OpNode RFP80:$src1, (f80 (extloadf64 addr:$src2)))),
@@ -131,42 +131,42 @@ let mayLoad = 1 in
def _F64m : FPI<0xDC, fp, (outs), (ins f64mem:$src),
!strconcat("f", asmstring, "{l}\t$src")>;
// ST(0) = ST(0) + [memint]
-def _FpI16m32 : FpIf32<(outs RFP32:$dst), (ins RFP32:$src1, i16mem:$src2),
+def _FpI16m32 : FpIf32<(outs RFP32:$dst), (ins RFP32:$src1, i16mem_norex2:$src2),
OneArgFPRW,
[!if(Forward,
(set RFP32:$dst,
(OpNode RFP32:$src1, (X86fild16 addr:$src2))),
(set RFP32:$dst,
(OpNode (X86fild16 addr:$src2), RFP32:$src1)))]>;
-def _FpI32m32 : FpIf32<(outs RFP32:$dst), (ins RFP32:$src1, i32mem:$src2),
+def _FpI32m32 : FpIf32<(outs RFP32:$dst), (ins RFP32:$src1, i32mem_norex2:$src2),
OneArgFPRW,
[!if(Forward,
(set RFP32:$dst,
(OpNode RFP32:$src1, (X86fild32 addr:$src2))),
(set RFP32:$dst,
(OpNode (X86fild32 addr:$src2), RFP32:$src1)))]>;
-def _FpI16m64 : FpIf64<(outs RFP64:$dst), (ins RFP64:$src1, i16mem:$src2),
+def _FpI16m64 : FpIf64<(outs RFP64:$dst), (ins RFP64:$src1, i16mem_norex2:$src2),
OneArgFPRW,
[!if(Forward,
(set RFP64:$dst,
(OpNode RFP64:$src1, (X86fild16 addr:$src2))),
(set RFP64:$dst,
(OpNode (X86fild16 addr:$src2), RFP64:$src1)))]>;
-def _FpI32m64 : FpIf64<(outs RFP64:$dst), (ins RFP64:$src1, i32mem:$src2),
+def _FpI32m64 : FpIf64<(outs RFP64:$dst), (ins RFP64:$src1, i32mem_norex2:$src2),
OneArgFPRW,
[!if(Forward,
(set RFP64:$dst,
(OpNode RFP64:$src1, (X86fild32 addr:$src2))),
(set RFP64:$dst,
(OpNode (X86fild32 addr:$src2), RFP64:$src1)))]>;
-def _FpI16m80 : FpI_<(outs RFP80:$dst), (ins RFP80:$src1, i16mem:$src2),
+def _FpI16m80 : FpI_<(outs RFP80:$dst), (ins RFP80:$src1, i16mem_norex2:$src2),
OneArgFPRW,
[!if(Forward,
(set RFP80:$dst,
(OpNode RFP80:$src1, (X86fild16 addr:$src2))),
(set RFP80:$dst,
(OpNode (X86fild16 addr:$src2), RFP80:$src1)))]>;
-def _FpI32m80 : FpI_<(outs RFP80:$dst), (ins RFP80:$src1, i32mem:$src2),
+def _FpI32m80 : FpI_<(outs RFP80:$dst), (ins RFP80:$src1, i32mem_norex2:$src2),
OneArgFPRW,
[!if(Forward,
(set RFP80:$dst,
@@ -385,80 +385,80 @@ let mayRaiseFPException = 1 in {
// Floating point loads & stores.
let SchedRW = [WriteLoad], Uses = [FPCW] in {
let canFoldAsLoad = 1 in {
-def LD_Fp32m : FpIf32<(outs RFP32:$dst), (ins f32mem:$src), ZeroArgFP,
+def LD_Fp32m : FpIf32<(outs RFP32:$dst), (ins f32mem_norex2:$src), ZeroArgFP,
[(set RFP32:$dst, (loadf32 addr:$src))]>;
-def LD_Fp64m : FpIf64<(outs RFP64:$dst), (ins f64mem:$src), ZeroArgFP,
+def LD_Fp64m : FpIf64<(outs RFP64:$dst), (ins f64mem_norex2:$src), ZeroArgFP,
[(set RFP64:$dst, (loadf64 addr:$src))]>;
-def LD_Fp80m : FpI_<(outs RFP80:$dst), (ins f80mem:$src), ZeroArgFP,
+def LD_Fp80m : FpI_<(outs RFP80:$dst), (ins f80mem_norex2:$src), ZeroArgFP,
[(set RFP80:$dst, (loadf80 addr:$src))]>;
} // canFoldAsLoad
-def LD_Fp32m64 : FpIf64<(outs RFP64:$dst), (ins f32mem:$src), ZeroArgFP,
+def LD_Fp32m64 : FpIf64<(outs RFP64:$dst), (ins f32mem_norex2:$src), ZeroArgFP,
[(set RFP64:$dst, (f64 (extloadf32 addr:$src)))]>;
-def LD_Fp64m80 : FpI_<(outs RFP80:$dst), (ins f64mem:$src), ZeroArgFP,
+def LD_Fp64m80 : FpI_<(outs RFP80:$dst), (ins f64mem_norex2:$src), ZeroArgFP,
[(set RFP80:$dst, (f80 (extloadf64 addr:$src)))]>;
-def LD_Fp32m80 : FpI_<(outs RFP80:$dst), (ins f32mem:$src), ZeroArgFP,
+def LD_Fp32m80 : FpI_<(outs RFP80:$dst), (ins f32mem_norex2:$src), ZeroArgFP,
[(set RFP80:$dst, (f80 (extloadf32 addr:$src)))]>;
let mayRaiseFPException = 0 in {
-def ILD_Fp16m32: FpIf32<(outs RFP32:$dst), (ins i16mem:$src), ZeroArgFP,
+def ILD_Fp16m32: FpIf32<(outs RFP32:$dst), (ins i16mem_norex2:$src), ZeroArgFP,
[(set RFP32:$dst, (X86fild16 addr:$src))]>;
-def ILD_Fp32m32: FpIf32<(outs RFP32:$dst), (ins i32mem:$src), ZeroArgFP,
+def ILD_Fp32m32: FpIf32<(outs RFP32:$dst), (ins i32mem_norex2:$src), ZeroArgFP,
[(set RFP32:$dst, (X86fild32 addr:$src))]>;
-def ILD_Fp64m32: FpIf32<(outs RFP32:$dst), (ins i64mem:$src), ZeroArgFP,
+def ILD_Fp64m32: FpIf32<(outs RFP32:$dst), (ins i64mem_norex2:$src), ZeroArgFP,
[(set RFP32:$dst, (X86fild64 addr:$src))]>;
-def ILD_Fp16m64: FpIf64<(outs RFP64:$dst), (ins i16mem:$src), ZeroArgFP,
+def ILD_Fp16m64: FpIf64<(outs RFP64:$dst), (ins i16mem_norex2:$src), ZeroArgFP,
[(set RFP64:$dst, (X86fild16 addr:$src))]>;
-def ILD_Fp32m64: FpIf64<(outs RFP64:$dst), (ins i32mem:$src), ZeroArgFP,
+def ILD_Fp32m64: FpIf64<(outs RFP64:$dst), (ins i32mem_norex2:$src), ZeroArgFP,
[(set RFP64:$dst, (X86fild32 addr:$src))]>;
-def ILD_Fp64m64: FpIf64<(outs RFP64:$dst), (ins i64mem:$src), ZeroArgFP,
+def ILD_Fp64m64: FpIf64<(outs RFP64:$dst), (ins i64mem_norex2:$src), ZeroArgFP,
[(set RFP64:$dst, (X86fild64 addr:$src))]>;
-def ILD_Fp16m80: FpI_<(outs RFP80:$dst), (ins i16mem:$src), ZeroArgFP,
+def ILD_Fp16m80: FpI_<(outs RFP80:$dst), (ins i16mem_norex2:$src), ZeroArgFP,
[(set RFP80:$dst, (X86fild16 addr:$src))]>;
-def ILD_Fp32m80: FpI_<(outs RFP80:$dst), (ins i32mem:$src), ZeroArgFP,
+def ILD_Fp32m80: FpI_<(outs RFP80:$dst), (ins i32mem_norex2:$src), ZeroArgFP,
[(set RFP80:$dst, (X86fild32 addr:$src))]>;
-def ILD_Fp64m80: FpI_<(outs RFP80:$dst), (ins i64mem:$src), ZeroArgFP,
+def ILD_Fp64m80: FpI_<(outs RFP80:$dst), (ins i64mem_norex2:$src), ZeroArgFP,
[(set RFP80:$dst, (X86fild64 addr:$src))]>;
} // mayRaiseFPException = 0
} // SchedRW
let SchedRW = [WriteStore], Uses = [FPCW] in {
-def ST_Fp32m : FpIf32<(outs), (ins f32mem:$op, RFP32:$src), OneArgFP,
+def ST_Fp32m : FpIf32<(outs), (ins f32mem_norex2:$op, RFP32:$src), OneArgFP,
[(store RFP32:$src, addr:$op)]>;
-def ST_Fp64m32 : FpIf64<(outs), (ins f32mem:$op, RFP64:$src), OneArgFP,
+def ST_Fp64m32 : FpIf64<(outs), (ins f32mem_norex2:$op, RFP64:$src), OneArgFP,
[(truncstoref32 RFP64:$src, addr:$op)]>;
-def ST_Fp64m : FpIf64<(outs), (ins f64mem:$op, RFP64:$src), OneArgFP,
+def ST_Fp64m : FpIf64<(outs), (ins f64mem_norex2:$op, RFP64:$src), OneArgFP,
[(store RFP64:$src, addr:$op)]>;
-def ST_Fp80m32 : FpI_<(outs), (ins f32mem:$op, RFP80:$src), OneArgFP,
+def ST_Fp80m32 : FpI_<(outs), (ins f32mem_norex2:$op, RFP80:$src), OneArgFP,
[(truncstoref32 RFP80:$src, addr:$op)]>;
-def ST_Fp80m64 : FpI_<(outs), (ins f64mem:$op, RFP80:$src), OneArgFP,
+def ST_Fp80m64 : FpI_<(outs), (ins f64mem_norex2:$op, RFP80:$src), OneArgFP,
[(truncstoref64 RFP80:$src, addr:$op)]>;
// FST does not support 80-bit memory target; FSTP must be used.
let mayStore = 1, hasSideEffects = 0 in {
-def ST_FpP32m : FpIf32<(outs), (ins f32mem:$op, RFP32:$src), OneArgFP, []>;
-def ST_FpP64m32 : FpIf64<(outs), (ins f32mem:$op, RFP64:$src), OneArgFP, []>;
-def ST_FpP64m : FpIf64<(outs), (ins f64mem:$op, RFP64:$src), OneArgFP, []>;
-def ST_FpP80m32 : FpI_<(outs), (ins f32mem:$op, RFP80:$src), OneArgFP, []>;
-def ST_FpP80m64 : FpI_<(outs), (ins f64mem:$op, RFP80:$src), OneArgFP, []>;
+def ST_FpP32m : FpIf32<(outs), (ins f32mem_norex2:$op, RFP32:$src), OneArgFP, []>;
+def ST_FpP64m32 : FpIf64<(outs), (ins f32mem_norex2:$op, RFP64:$src), OneArgFP, []>;
+def ST_FpP64m : FpIf64<(outs), (ins f64mem_norex2:$op, RFP64:$src), OneArgFP, []>;
+def ST_FpP80m32 : FpI_<(outs), (ins f32mem_norex2:$op, RFP80:$src), OneArgFP, []>;
+def ST_FpP80m64 : FpI_<(outs), (ins f64mem_norex2:$op, RFP80:$src), OneArgFP, []>;
} // mayStore
-def ST_FpP80m : FpI_<(outs), (ins f80mem:$op, RFP80:$src), OneArgFP,
+def ST_FpP80m : FpI_<(outs), (ins f80mem_norex2:$op, RFP80:$src), OneArgFP,
[(store RFP80:$src, addr:$op)]>;
let mayStore = 1, hasSideEffects = 0 in {
-def IST_Fp16m32 : FpIf32<(outs), (ins i16mem:$op, RFP32:$src), OneArgFP, []>;
-def IST_Fp32m32 : FpIf32<(outs), (ins i32mem:$op, RFP32:$src), OneArgFP,
+def IST_Fp16m32 : FpIf32<(outs), (ins i16mem_norex2:$op, RFP32:$src), OneArgFP, []>;
+def IST_Fp32m32 : FpIf32<(outs), (ins i32mem_norex2:$op, RFP32:$src), OneArgFP,
[(X86fist32 RFP32:$src, addr:$op)]>;
-def IST_Fp64m32 : FpIf32<(outs), (ins i64mem:$op, RFP32:$src), OneArgFP,
+def IST_Fp64m32 : FpIf32<(outs), (ins i64mem_norex2:$op, RFP32:$src), OneArgFP,
[(X86fist64 RFP32:$src, addr:$op)]>;
-def IST_Fp16m64 : FpIf64<(outs), (ins i16mem:$op, RFP64:$src), OneArgFP, []>;
-def IST_Fp32m64 : FpIf64<(outs), (ins i32mem:$op, RFP64:$src), OneArgFP,
+def IST_Fp16m64 : FpIf64<(outs), (ins i16mem_norex2:$op, RFP64:$src), OneArgFP, []>;
+def IST_Fp32m64 : FpIf64<(outs), (ins i32mem_norex2:$op, RFP64:$src), OneArgFP,
[(X86fist32 RFP64:$src, addr:$op)]>;
-def IST_Fp64m64 : FpIf64<(outs), (ins i64mem:$op, RFP64:$src), OneArgFP,
+def IST_Fp64m64 : FpIf64<(outs), (ins i64mem_norex2:$op, RFP64:$src), OneArgFP,
[(X86fist64 RFP64:$src, addr:$op)]>;
-def IST_Fp16m80 : FpI_<(outs), (ins i16mem:$op, RFP80:$src), OneArgFP, []>;
-def IST_Fp32m80 : FpI_<(outs), (ins i32mem:$op, RFP80:$src), OneArgFP,
+def IST_Fp16m80 : FpI_<(outs), (ins i16mem_norex2:$op, RFP80:$src), OneArgFP, []>;
+def IST_Fp32m80 : FpI_<(outs), (ins i32mem_norex2:$op, RFP80:$src), OneArgFP,
[(X86fist32 RFP80:$src, addr:$op)]>;
-def IST_Fp64m80 : FpI_<(outs), (ins i64mem:$op, RFP80:$src), OneArgFP,
+def IST_Fp64m80 : FpI_<(outs), (ins i64mem_norex2:$op, RFP80:$src), OneArgFP,
[(X86fist64 RFP80:$src, addr:$op)]>;
} // mayStore
} // SchedRW, Uses = [FPCW]
@@ -488,23 +488,23 @@ def IST_FP64m : FPI<0xDF, MRM7m, (outs), (ins i64mem:$dst), "fistp{ll}\t$dst">;
// FISTTP requires SSE3 even though it's a FPStack op.
let Predicates = [HasSSE3], SchedRW = [WriteStore], Uses = [FPCW] in {
-def ISTT_Fp16m32 : FpI_<(outs), (ins i16mem:$op, RFP32:$src), OneArgFP,
+def ISTT_Fp16m32 : FpI_<(outs), (ins i16mem_norex2:$op, RFP32:$src), OneArgFP,
[(X86fp_to_i16mem RFP32:$src, addr:$op)]>;
-def ISTT_Fp32m32 : FpI_<(outs), (ins i32mem:$op, RFP32:$src), OneArgFP,
+def ISTT_Fp32m32 : FpI_<(outs), (ins i32mem_norex2:$op, RFP32:$src), OneArgFP,
[(X86fp_to_i32mem RFP32:$src, addr:$op)]>;
-def ISTT_Fp64m32 : FpI_<(outs), (ins i64mem:$op, RFP32:$src), OneArgFP,
+def ISTT_Fp64m32 : FpI_<(outs), (ins i64mem_norex2:$op, RFP32:$src), OneArgFP,
[(X86fp_to_i64mem RFP32:$src, addr:$op)]>;
-def ISTT_Fp16m64 : FpI_<(outs), (ins i16mem:$op, RFP64:$src), OneArgFP,
+def ISTT_Fp16m64 : FpI_<(outs), (ins i16mem_norex2:$op, RFP64:$src), OneArgFP,
[(X86fp_to_i16mem RFP64:$src, addr:$op)]>;
-def ISTT_Fp32m64 : FpI_<(outs), (ins i32mem:$op, RFP64:$src), OneArgFP,
+def ISTT_Fp32m64 : FpI_<(outs), (ins i32mem_norex2:$op, RFP64:$src), OneArgFP,
[(X86fp_to_i32mem RFP64:$src, addr:$op)]>;
-def ISTT_Fp64m64 : FpI_<(outs), (ins i64mem:$op, RFP64:$src), OneArgFP,
+def ISTT_Fp64m64 : FpI_<(outs), (ins i64mem_norex2:$op, RFP64:$src), OneArgFP,
[(X86fp_to_i64mem RFP64:$src, addr:$op)]>;
-def ISTT_Fp16m80 : FpI_<(outs), (ins i16mem:$op, RFP80:$src), OneArgFP,
+def ISTT_Fp16m80 : FpI_<(outs), (ins i16mem_norex2:$op, RFP80:$src), OneArgFP,
[(X86fp_to_i16mem RFP80:$src, addr:$op)]>;
-def ISTT_Fp32m80 : FpI_<(outs), (ins i32mem:$op, RFP80:$src), OneArgFP,
+def ISTT_Fp32m80 : FpI_<(outs), (ins i32mem_norex2:$op, RFP80:$src), OneArgFP,
[(X86fp_to_i32mem RFP80:$src, addr:$op)]>;
-def ISTT_Fp64m80 : FpI_<(outs), (ins i64mem:$op, RFP80:$src), OneArgFP,
+def ISTT_Fp64m80 : FpI_<(outs), (ins i64mem_norex2:$op, RFP80:$src), OneArgFP,
[(X86fp_to_i64mem RFP80:$src, addr:$op)]>;
} // Predicates = [HasSSE3]
diff --git a/llvm/lib/Target/X86/X86InstrInfo.cpp b/llvm/lib/Target/X86/X86InstrInfo.cpp
index 09a8ae6107020..bfd274a8ae034 100644
--- a/llvm/lib/Target/X86/X86InstrInfo.cpp
+++ b/llvm/lib/Target/X86/X86InstrInfo.cpp
@@ -98,21 +98,6 @@ X86InstrInfo::X86InstrInfo(const X86Subtarget &STI)
X86::CATCHRET, (STI.is64Bit() ? X86::RET64 : X86::RET32)),
Subtarget(STI), RI(STI.getTargetTriple()) {}
-const TargetRegisterClass *X86InstrInfo::getRegClass(const MCInstrDesc &MCID,
- unsigned OpNum) const {
- auto *RC = TargetInstrInfo::getRegClass(MCID, OpNum);
- // If the target does not have egpr, then r16-r31 will be resereved for all
- // instructions.
- if (!RC || !Subtarget.hasEGPR())
- return RC;
-
- if (X86II::canUseApxExtendedReg(MCID))
- return RC;
-
- const X86RegisterInfo *RI = Subtarget.getRegisterInfo();
- return RI->constrainRegClassToNonRex2(RC);
-}
-
const TargetRegisterClass *X86InstrInfo::getInlineAsmMemoryOperandRegClass(
InlineAsm::ConstraintCode C) const {
if (Subtarget.isTarget64BitLP64())
diff --git a/llvm/lib/Target/X86/X86InstrInfo.h b/llvm/lib/Target/X86/X86InstrInfo.h
index c018fcb124e70..c58a4eaf6b35a 100644
--- a/llvm/lib/Target/X86/X86InstrInfo.h
+++ b/llvm/lib/Target/X86/X86InstrInfo.h
@@ -252,15 +252,6 @@ class X86InstrInfo final : public X86GenInstrInfo {
public:
explicit X86InstrInfo(const X86Subtarget &STI);
- /// Given a machine instruction descriptor, returns the register
- /// class constraint for OpNum, or NULL. Returned register class
- /// may be different from the definition in the TD file, e.g.
- /// GR*RegClass (definition in TD file)
- /// ->
- /// GR*_NOREX2RegClass (Returned register class)
- const TargetRegisterClass *getRegClass(const MCInstrDesc &MCID,
- unsigned OpNum) const override;
-
/// getRegisterInfo - TargetInstrInfo is a superset of MRegister info. As
/// such, whenever a client has an instance of instruction info, it should
/// always be able to get register info as well (through this method).
diff --git a/llvm/lib/Target/X86/X86InstrOperands.td b/llvm/lib/Target/X86/X86InstrOperands.td
index 4373f39c360a8..a6bb9e381cb8b 100644
--- a/llvm/lib/Target/X86/X86InstrOperands.td
+++ b/llvm/lib/Target/X86/X86InstrOperands.td
@@ -6,15 +6,42 @@
//
//===----------------------------------------------------------------------===//
+// Each class list below is positional with the mode list: X86_32, X86_64,
+// X86_64_EGPR, X86_64_X32. The norex2 operands only differ in X86_64_EGPR, where
+// they use the *_NOREX2 class to keep an EGPR-incapable instruction off r16-r31.
+
def x86_ptr_rc : RegClassByHwMode<
- [X86_32, X86_64, X86_64_X32],
- [GR32, GR64, LOW32_ADDR_ACCESS]>;
+ [X86_32, X86_64, X86_64_EGPR, X86_64_X32],
+ [GR32, GR64, GR64, LOW32_ADDR_ACCESS]>;
// A version of ptr_rc which excludes SP, ESP, and RSP. This is used for
// the index operand of an address, to conform to x86 encoding restrictions.
def ptr_rc_nosp : RegClassByHwMode<
- [X86_32, X86_64, X86_64_X32],
- [GR32_NOSP, GR64_NOSP, GR32_NOSP]>;
+ [X86_32, X86_64, X86_64_EGPR, X86_64_X32],
+ [GR32_NOSP, GR64_NOSP, GR64_NOSP, GR32_NOSP]>;
+
+// Address base/index classes for instructions that cannot encode an EGPR.
+def ptr_rc_norex2 : RegClassByHwMode<
+ [X86_32, X86_64, X86_64_EGPR, X86_64_X32],
+ [GR32, GR64, GR64_NOREX2, LOW32_ADDR_ACCESS]>;
+
+def ptr_rc_norex2_nosp : RegClassByHwMode<
+ [X86_32, X86_64, X86_64_EGPR, X86_64_X32],
+ [GR32_NOSP, GR64_NOSP, GR64_NOREX2_NOSP, GR32_NOSP]>;
+
+// Direct GPR register operands for instructions that cannot encode an EGPR.
+def gr8_norex2 : RegClassByHwMode<
+ [X86_32, X86_64, X86_64_EGPR, X86_64_X32],
+ [GR8, GR8, GR8_NOREX2, GR8]>;
+def gr16_norex2 : RegClassByHwMode<
+ [X86_32, X86_64, X86_64_EGPR, X86_64_X32],
+ [GR16, GR16, GR16_NOREX2, GR16]>;
+def gr32_norex2 : RegClassByHwMode<
+ [X86_32, X86_64, X86_64_EGPR, X86_64_X32],
+ [GR32, GR32, GR32_NOREX2, GR32]>;
+def gr64_norex2 : RegClassByHwMode<
+ [X86_32, X86_64, X86_64_EGPR, X86_64_X32],
+ [GR64, GR64, GR64_NOREX2, GR64]>;
// *mem - Operand definitions for the funky X86 addressing mode operands.
//
@@ -72,6 +99,16 @@ class X86VMemOperand<RegisterClass RC, string printMethod,
let MIOperandInfo = (ops x86_ptr_rc, i8imm, RC, i32imm, SEGMENT_REG);
}
+// A memory operand whose base and index registers cannot be an EGPR, for
+// instructions that cannot encode one in a memory address.
+class X86MemOperandNoRex2<string printMethod,
+ AsmOperandClass parserMatchClass = X86MemAsmOperand,
+ int size = 0>
+ : X86MemOperand<printMethod, parserMatchClass, size> {
+ let MIOperandInfo = (ops ptr_rc_norex2, i8imm, ptr_rc_norex2_nosp, i32imm,
+ SEGMENT_REG);
+}
+
def anymem : X86MemOperand<"printMemReference">;
// FIXME: Right now we allow any size during parsing, but we might want to
@@ -117,15 +154,31 @@ def shmem : X86MemOperand<"printwordmem", X86Mem16AsmOperand>;
def ssmem : X86MemOperand<"printdwordmem", X86Mem32AsmOperand>;
def sdmem : X86MemOperand<"printqwordmem", X86Mem64AsmOperand>;
+// norex2 variants of the memory operands, for the EGPR-incapable instructions.
+def anymem_norex2 : X86MemOperandNoRex2<"printMemReference">;
+def opaquemem_norex2 : X86MemOperandNoRex2<"printMemReference">;
+def sibmem_norex2 : X86MemOperandNoRex2<"printMemReference", X86SibMemOperand>;
+def i8mem_norex2 : X86MemOperandNoRex2<"printbytemem", X86Mem8AsmOperand, 8>;
+def i16mem_norex2 : X86MemOperandNoRex2<"printwordmem", X86Mem16AsmOperand, 16>;
+def i32mem_norex2 : X86MemOperandNoRex2<"printdwordmem", X86Mem32AsmOperand, 32>;
+def i64mem_norex2 : X86MemOperandNoRex2<"printqwordmem", X86Mem64AsmOperand, 64>;
+def i128mem_norex2 : X86MemOperandNoRex2<"printxmmwordmem", X86Mem128AsmOperand, 128>;
+def i256mem_norex2 : X86MemOperandNoRex2<"printymmwordmem", X86Mem256AsmOperand, 256>;
+def f32mem_norex2 : X86MemOperandNoRex2<"printdwordmem", X86Mem32AsmOperand, 32>;
+def f64mem_norex2 : X86MemOperandNoRex2<"printqwordmem", X86Mem64AsmOperand, 64>;
+def f80mem_norex2 : X86MemOperandNoRex2<"printtbytemem", X86Mem80AsmOperand, 80>;
+def ssmem_norex2 : X86MemOperandNoRex2<"printdwordmem", X86Mem32AsmOperand>;
+def sdmem_norex2 : X86MemOperandNoRex2<"printqwordmem", X86Mem64AsmOperand>;
+
// A version of i8mem for use on x86-64 and x32 that uses a NOREX GPR instead
// of a plain GPR, so that it doesn't potentially require a REX prefix.
def ptr_rc_norex : RegClassByHwMode<
- [X86_32, X86_64, X86_64_X32],
- [GR32_NOREX, GR64_NOREX, GR32_NOREX]>;
+ [X86_32, X86_64, X86_64_EGPR, X86_64_X32],
+ [GR32_NOREX, GR64_NOREX, GR64_NOREX, GR32_NOREX]>;
def ptr_rc_norex_nosp : RegClassByHwMode<
- [X86_32, X86_64, X86_64_X32],
- [GR32_NOREX_NOSP, GR64_NOREX_NOSP, GR32_NOREX_NOSP]>;
+ [X86_32, X86_64, X86_64_EGPR, X86_64_X32],
+ [GR32_NOREX_NOSP, GR64_NOREX_NOSP, GR64_NOREX_NOSP, GR32_NOREX_NOSP]>;
def i8mem_NOREX : X86MemOperand<"printbytemem", X86Mem8AsmOperand, 8> {
@@ -136,8 +189,8 @@ def i8mem_NOREX : X86MemOperand<"printbytemem", X86Mem8AsmOperand, 8> {
// GPRs available for tailcall.
// It represents GR32_TC, GR64_TC or GR64_TCW64.
def ptr_rc_tailcall : RegClassByHwMode<
- [X86_32, X86_64, X86_64_X32],
- [GR32_TC, GR64_TC, GR64_TC]>;
+ [X86_32, X86_64, X86_64_EGPR, X86_64_X32],
+ [GR32_TC, GR64_TC, GR64_TC, GR64_TC]>;
// Special i32mem for addresses of load folding tail calls. These are not
// allowed to use callee-saved registers since they must be scheduled
diff --git a/llvm/lib/Target/X86/X86InstrPredicates.td b/llvm/lib/Target/X86/X86InstrPredicates.td
index 1b177db55d276..86bb8b5e2631b 100644
--- a/llvm/lib/Target/X86/X86InstrPredicates.td
+++ b/llvm/lib/Target/X86/X86InstrPredicates.td
@@ -267,6 +267,18 @@ def NotUseIndirectThunkCalls : Predicate<"!Subtarget->useIndirectThunkCalls()">;
// HwModes
//===----------------------------------------------------------------------===//
+// Like HasEGPR/NoEGPR, but with an AssemblerPredicate so the modes below also
+// resolve in the MC layer. Without it the two 64-bit modes would share the same
+// MC condition and getHwMode() would report both active.
+def HasEGPRMode : Predicate<"Subtarget->hasEGPR()">,
+ AssemblerPredicate<(all_of FeatureEGPR), "egpr">;
+def NoEGPRMode : Predicate<"!Subtarget->hasEGPR()">,
+ AssemblerPredicate<(all_of (not FeatureEGPR)), "not egpr">;
+
defvar X86_32 = DefaultMode;
-def X86_64 : HwMode<[In64BitMode, NotX32Mode]>;
+// getHwMode(RegInfo) modes must be mutually exclusive, so split the 64-bit mode
+// on EGPR (x32 is left alone, as it does not use EGPR). The norex2 operands in
+// X86InstrOperands.td key on X86_64_EGPR.
+def X86_64 : HwMode<[In64BitMode, NotX32Mode, NoEGPRMode]>;
+def X86_64_EGPR : HwMode<[In64BitMode, NotX32Mode, HasEGPRMode]>;
def X86_64_X32 : HwMode<[IsX32Mode]>;
diff --git a/llvm/lib/Target/X86/X86InstrSSE.td b/llvm/lib/Target/X86/X86InstrSSE.td
index 2332cb81d54cc..4bc079fd677e1 100644
--- a/llvm/lib/Target/X86/X86InstrSSE.td
+++ b/llvm/lib/Target/X86/X86InstrSSE.td
@@ -854,7 +854,7 @@ let Constraints = "$src1 = $dst" in {
// SSE 1 & 2 - Conversion Instructions
//===----------------------------------------------------------------------===//
-multiclass sse12_cvt_s<bits<8> opc, RegisterClass SrcRC, RegisterClass DstRC,
+multiclass sse12_cvt_s<bits<8> opc, RegisterClass SrcRC, DAGOperand DstRC,
SDPatternOperator OpNode, X86MemOperand x86memop, PatFrag ld_frag,
string asm, string mem, X86FoldableSchedWrite sched,
Domain d,
@@ -902,36 +902,36 @@ let hasSideEffects = 0, Predicates = [UseAVX], ExeDomain = d in {
}
let isCodeGenOnly = 1, Predicates = [UseAVX], Uses = [MXCSR], mayRaiseFPException = 1 in {
-defm VCVTTSS2SI : sse12_cvt_s<0x2C, FR32, GR32, any_fp_to_sint, f32mem, loadf32,
+defm VCVTTSS2SI : sse12_cvt_s<0x2C, FR32, gr32_norex2, any_fp_to_sint, f32mem_norex2, loadf32,
"cvttss2si", "cvttss2si",
WriteCvtSS2I, SSEPackedSingle>,
TB, XS, VEX, VEX_LIG;
-defm VCVTTSS2SI64 : sse12_cvt_s<0x2C, FR32, GR64, any_fp_to_sint, f32mem, loadf32,
+defm VCVTTSS2SI64 : sse12_cvt_s<0x2C, FR32, gr64_norex2, any_fp_to_sint, f32mem_norex2, loadf32,
"cvttss2si", "cvttss2si",
WriteCvtSS2I, SSEPackedSingle>,
TB, XS, VEX, REX_W, VEX_LIG;
-defm VCVTTSD2SI : sse12_cvt_s<0x2C, FR64, GR32, any_fp_to_sint, f64mem, loadf64,
+defm VCVTTSD2SI : sse12_cvt_s<0x2C, FR64, gr32_norex2, any_fp_to_sint, f64mem_norex2, loadf64,
"cvttsd2si", "cvttsd2si",
WriteCvtSD2I, SSEPackedDouble>,
TB, XD, VEX, VEX_LIG;
-defm VCVTTSD2SI64 : sse12_cvt_s<0x2C, FR64, GR64, any_fp_to_sint, f64mem, loadf64,
+defm VCVTTSD2SI64 : sse12_cvt_s<0x2C, FR64, gr64_norex2, any_fp_to_sint, f64mem_norex2, loadf64,
"cvttsd2si", "cvttsd2si",
WriteCvtSD2I, SSEPackedDouble>,
TB, XD, VEX, REX_W, VEX_LIG;
-defm VCVTSS2SI : sse12_cvt_s<0x2D, FR32, GR32, lrint, f32mem, loadf32,
+defm VCVTSS2SI : sse12_cvt_s<0x2D, FR32, gr32_norex2, lrint, f32mem_norex2, loadf32,
"cvtss2si", "cvtss2si",
WriteCvtSS2I, SSEPackedSingle>,
TB, XS, VEX, VEX_LIG;
-defm VCVTSS2SI64 : sse12_cvt_s<0x2D, FR32, GR64, llrint, f32mem, loadf32,
+defm VCVTSS2SI64 : sse12_cvt_s<0x2D, FR32, gr64_norex2, llrint, f32mem_norex2, loadf32,
"cvtss2si", "cvtss2si",
WriteCvtSS2I, SSEPackedSingle>,
TB, XS, VEX, REX_W, VEX_LIG;
-defm VCVTSD2SI : sse12_cvt_s<0x2D, FR64, GR32, lrint, f64mem, loadf64,
+defm VCVTSD2SI : sse12_cvt_s<0x2D, FR64, gr32_norex2, lrint, f64mem_norex2, loadf64,
"cvtsd2si", "cvtsd2si",
WriteCvtSD2I, SSEPackedDouble>,
TB, XD, VEX, VEX_LIG;
-defm VCVTSD2SI64 : sse12_cvt_s<0x2D, FR64, GR64, llrint, f64mem, loadf64,
+defm VCVTSD2SI64 : sse12_cvt_s<0x2D, FR64, gr64_norex2, llrint, f64mem_norex2, loadf64,
"cvtsd2si", "cvtsd2si",
WriteCvtSD2I, SSEPackedDouble>,
TB, XD, VEX, REX_W, VEX_LIG;
@@ -1036,7 +1036,7 @@ let Predicates = [UseSSE2] in {
// Conversion Instructions Intrinsics - Match intrinsics which expect MM
// and/or XMM operand(s).
-multiclass sse12_cvt_sint<bits<8> opc, RegisterClass SrcRC, RegisterClass DstRC,
+multiclass sse12_cvt_sint<bits<8> opc, RegisterClass SrcRC, DAGOperand DstRC,
ValueType DstVT, ValueType SrcVT, SDNode OpNode,
Operand memop, PatFrags mem_frags, string asm,
X86FoldableSchedWrite sched, Domain d> {
@@ -1074,11 +1074,11 @@ let hasSideEffects = 0, ExeDomain = d in {
let Uses = [MXCSR], mayRaiseFPException = 1 in {
let Predicates = [UseAVX] in {
-defm VCVTSD2SI : sse12_cvt_sint<0x2D, VR128, GR32, i32, v2f64,
- X86cvts2si, sdmem, sse_load_f64, "cvtsd2si",
+defm VCVTSD2SI : sse12_cvt_sint<0x2D, VR128, gr32_norex2, i32, v2f64,
+ X86cvts2si, sdmem_norex2, sse_load_f64, "cvtsd2si",
WriteCvtSD2I, SSEPackedDouble>, TB, XD, VEX, VEX_LIG;
-defm VCVTSD2SI64 : sse12_cvt_sint<0x2D, VR128, GR64, i64, v2f64,
- X86cvts2si, sdmem, sse_load_f64, "cvtsd2si",
+defm VCVTSD2SI64 : sse12_cvt_sint<0x2D, VR128, gr64_norex2, i64, v2f64,
+ X86cvts2si, sdmem_norex2, sse_load_f64, "cvtsd2si",
WriteCvtSD2I, SSEPackedDouble>, TB, XD, VEX, REX_W, VEX_LIG;
}
defm CVTSD2SI : sse12_cvt_sint<0x2D, VR128, GR32, i32, v2f64, X86cvts2si,
@@ -1197,18 +1197,18 @@ def : Pat<(v4f32 (X86Blendi (v4f32 immAllZerosV),
// Aliases for intrinsics
let Predicates = [UseAVX], Uses = [MXCSR], mayRaiseFPException = 1 in {
-defm VCVTTSS2SI : sse12_cvt_sint<0x2C, VR128, GR32, i32, v4f32, X86cvtts2Int,
+defm VCVTTSS2SI : sse12_cvt_sint<0x2C, VR128, gr32_norex2, i32, v4f32, X86cvtts2Int,
ssmem, sse_load_f32, "cvttss2si",
WriteCvtSS2I, SSEPackedSingle>, TB, XS, VEX, VEX_LIG;
-defm VCVTTSS2SI64 : sse12_cvt_sint<0x2C, VR128, GR64, i64, v4f32,
- X86cvtts2Int, ssmem, sse_load_f32,
+defm VCVTTSS2SI64 : sse12_cvt_sint<0x2C, VR128, gr64_norex2, i64, v4f32,
+ X86cvtts2Int, ssmem_norex2, sse_load_f32,
"cvttss2si", WriteCvtSS2I, SSEPackedSingle>,
TB, XS, VEX, VEX_LIG, REX_W;
-defm VCVTTSD2SI : sse12_cvt_sint<0x2C, VR128, GR32, i32, v2f64, X86cvtts2Int,
+defm VCVTTSD2SI : sse12_cvt_sint<0x2C, VR128, gr32_norex2, i32, v2f64, X86cvtts2Int,
sdmem, sse_load_f64, "cvttsd2si",
WriteCvtSS2I, SSEPackedDouble>, TB, XD, VEX, VEX_LIG;
-defm VCVTTSD2SI64 : sse12_cvt_sint<0x2C, VR128, GR64, i64, v2f64,
- X86cvtts2Int, sdmem, sse_load_f64,
+defm VCVTTSD2SI64 : sse12_cvt_sint<0x2C, VR128, gr64_norex2, i64, v2f64,
+ X86cvtts2Int, sdmem_norex2, sse_load_f64,
"cvttsd2si", WriteCvtSS2I, SSEPackedDouble>,
TB, XD, VEX, VEX_LIG, REX_W;
}
@@ -1230,21 +1230,21 @@ defm CVTTSD2SI64 : sse12_cvt_sint<0x2C, VR128, GR64, i64, v2f64,
}
def : InstAlias<"vcvttss2si{l}\t{$src, $dst|$dst, $src}",
- (VCVTTSS2SIrr_Int GR32:$dst, VR128:$src), 0, "att">;
+ (VCVTTSS2SIrr_Int gr32_norex2:$dst, VR128:$src), 0, "att">;
def : InstAlias<"vcvttss2si{l}\t{$src, $dst|$dst, $src}",
- (VCVTTSS2SIrm_Int GR32:$dst, f32mem:$src), 0, "att">;
+ (VCVTTSS2SIrm_Int gr32_norex2:$dst, f32mem_norex2:$src), 0, "att">;
def : InstAlias<"vcvttsd2si{l}\t{$src, $dst|$dst, $src}",
- (VCVTTSD2SIrr_Int GR32:$dst, VR128:$src), 0, "att">;
+ (VCVTTSD2SIrr_Int gr32_norex2:$dst, VR128:$src), 0, "att">;
def : InstAlias<"vcvttsd2si{l}\t{$src, $dst|$dst, $src}",
- (VCVTTSD2SIrm_Int GR32:$dst, f64mem:$src), 0, "att">;
+ (VCVTTSD2SIrm_Int gr32_norex2:$dst, f64mem_norex2:$src), 0, "att">;
def : InstAlias<"vcvttss2si{q}\t{$src, $dst|$dst, $src}",
- (VCVTTSS2SI64rr_Int GR64:$dst, VR128:$src), 0, "att">;
+ (VCVTTSS2SI64rr_Int gr64_norex2:$dst, VR128:$src), 0, "att">;
def : InstAlias<"vcvttss2si{q}\t{$src, $dst|$dst, $src}",
- (VCVTTSS2SI64rm_Int GR64:$dst, f32mem:$src), 0, "att">;
+ (VCVTTSS2SI64rm_Int gr64_norex2:$dst, f32mem_norex2:$src), 0, "att">;
def : InstAlias<"vcvttsd2si{q}\t{$src, $dst|$dst, $src}",
- (VCVTTSD2SI64rr_Int GR64:$dst, VR128:$src), 0, "att">;
+ (VCVTTSD2SI64rr_Int gr64_norex2:$dst, VR128:$src), 0, "att">;
def : InstAlias<"vcvttsd2si{q}\t{$src, $dst|$dst, $src}",
- (VCVTTSD2SI64rm_Int GR64:$dst, f64mem:$src), 0, "att">;
+ (VCVTTSD2SI64rm_Int gr64_norex2:$dst, f64mem_norex2:$src), 0, "att">;
def : InstAlias<"cvttss2si{l}\t{$src, $dst|$dst, $src}",
(CVTTSS2SIrr_Int GR32:$dst, VR128:$src), 0, "att">;
@@ -1264,10 +1264,10 @@ def : InstAlias<"cvttsd2si{q}\t{$src, $dst|$dst, $src}",
(CVTTSD2SI64rm_Int GR64:$dst, f64mem:$src), 0, "att">;
let Predicates = [UseAVX], Uses = [MXCSR], mayRaiseFPException = 1 in {
-defm VCVTSS2SI : sse12_cvt_sint<0x2D, VR128, GR32, i32, v4f32, X86cvts2si,
+defm VCVTSS2SI : sse12_cvt_sint<0x2D, VR128, gr32_norex2, i32, v4f32, X86cvts2si,
ssmem, sse_load_f32, "cvtss2si",
WriteCvtSS2I, SSEPackedSingle>, TB, XS, VEX, VEX_LIG;
-defm VCVTSS2SI64 : sse12_cvt_sint<0x2D, VR128, GR64, i64, v4f32, X86cvts2si,
+defm VCVTSS2SI64 : sse12_cvt_sint<0x2D, VR128, gr64_norex2, i64, v4f32, X86cvts2si,
ssmem, sse_load_f32, "cvtss2si",
WriteCvtSS2I, SSEPackedSingle>, TB, XS, VEX, REX_W, VEX_LIG;
}
@@ -1296,21 +1296,21 @@ defm CVTDQ2PS : sse12_cvt_p<0x5B, VR128, i128mem, v4f32, v4i32, memop,
// AVX aliases
def : InstAlias<"vcvtss2si{l}\t{$src, $dst|$dst, $src}",
- (VCVTSS2SIrr_Int GR32:$dst, VR128:$src), 0, "att">;
+ (VCVTSS2SIrr_Int gr32_norex2:$dst, VR128:$src), 0, "att">;
def : InstAlias<"vcvtss2si{l}\t{$src, $dst|$dst, $src}",
- (VCVTSS2SIrm_Int GR32:$dst, ssmem:$src), 0, "att">;
+ (VCVTSS2SIrm_Int gr32_norex2:$dst, ssmem_norex2:$src), 0, "att">;
def : InstAlias<"vcvtsd2si{l}\t{$src, $dst|$dst, $src}",
- (VCVTSD2SIrr_Int GR32:$dst, VR128:$src), 0, "att">;
+ (VCVTSD2SIrr_Int gr32_norex2:$dst, VR128:$src), 0, "att">;
def : InstAlias<"vcvtsd2si{l}\t{$src, $dst|$dst, $src}",
- (VCVTSD2SIrm_Int GR32:$dst, sdmem:$src), 0, "att">;
+ (VCVTSD2SIrm_Int gr32_norex2:$dst, sdmem_norex2:$src), 0, "att">;
def : InstAlias<"vcvtss2si{q}\t{$src, $dst|$dst, $src}",
- (VCVTSS2SI64rr_Int GR64:$dst, VR128:$src), 0, "att">;
+ (VCVTSS2SI64rr_Int gr64_norex2:$dst, VR128:$src), 0, "att">;
def : InstAlias<"vcvtss2si{q}\t{$src, $dst|$dst, $src}",
- (VCVTSS2SI64rm_Int GR64:$dst, ssmem:$src), 0, "att">;
+ (VCVTSS2SI64rm_Int gr64_norex2:$dst, ssmem_norex2:$src), 0, "att">;
def : InstAlias<"vcvtsd2si{q}\t{$src, $dst|$dst, $src}",
- (VCVTSD2SI64rr_Int GR64:$dst, VR128:$src), 0, "att">;
+ (VCVTSD2SI64rr_Int gr64_norex2:$dst, VR128:$src), 0, "att">;
def : InstAlias<"vcvtsd2si{q}\t{$src, $dst|$dst, $src}",
- (VCVTSD2SI64rm_Int GR64:$dst, sdmem:$src), 0, "att">;
+ (VCVTSD2SI64rm_Int gr64_norex2:$dst, sdmem_norex2:$src), 0, "att">;
// SSE aliases
def : InstAlias<"cvtss2si{l}\t{$src, $dst|$dst, $src}",
@@ -4759,7 +4759,7 @@ multiclass SS3I_unop_rm<bits<8> opc, string OpcodeStr, ValueType vt,
Sched<[sched.XMM]>;
def rm : SS38I<opc, MRMSrcMem, (outs VR128:$dst),
- (ins i128mem:$src),
+ (ins i128mem_norex2:$src),
!strconcat(OpcodeStr, "\t{$src, $dst|$dst, $src}"),
[(set VR128:$dst,
(vt (OpNode (ld_frag addr:$src))))]>,
@@ -4776,7 +4776,7 @@ multiclass SS3I_unop_rm_y<bits<8> opc, string OpcodeStr, ValueType vt,
Sched<[sched.YMM]>;
def Yrm : SS38I<opc, MRMSrcMem, (outs VR256:$dst),
- (ins i256mem:$src),
+ (ins i256mem_norex2:$src),
!strconcat(OpcodeStr, "\t{$src, $dst|$dst, $src}"),
[(set VR256:$dst,
(vt (OpNode (load addr:$src))))]>,
diff --git a/llvm/lib/Target/X86/X86InstrSystem.td b/llvm/lib/Target/X86/X86InstrSystem.td
index daa7d3677598a..016b7ec6085ca 100644
--- a/llvm/lib/Target/X86/X86InstrSystem.td
+++ b/llvm/lib/Target/X86/X86InstrSystem.td
@@ -629,40 +629,40 @@ def XSETBV : I<0x01, MRM_D1, (outs), (ins),
let Uses = [EDX, EAX] in {
-def XSAVE : I<0xAE, MRM4m, (outs), (ins opaquemem:$dst),
+def XSAVE : I<0xAE, MRM4m, (outs), (ins opaquemem_norex2:$dst),
"xsave\t$dst",
[(int_x86_xsave addr:$dst, EDX, EAX)]>, TB, Requires<[HasXSAVE]>;
-def XSAVE64 : RI<0xAE, MRM4m, (outs), (ins opaquemem:$dst),
+def XSAVE64 : RI<0xAE, MRM4m, (outs), (ins opaquemem_norex2:$dst),
"xsave64\t$dst",
[(int_x86_xsave64 addr:$dst, EDX, EAX)]>, TB, Requires<[HasXSAVE, In64BitMode]>;
-def XRSTOR : I<0xAE, MRM5m, (outs), (ins opaquemem:$dst),
+def XRSTOR : I<0xAE, MRM5m, (outs), (ins opaquemem_norex2:$dst),
"xrstor\t$dst",
[(int_x86_xrstor addr:$dst, EDX, EAX)]>, TB, Requires<[HasXSAVE]>;
-def XRSTOR64 : RI<0xAE, MRM5m, (outs), (ins opaquemem:$dst),
+def XRSTOR64 : RI<0xAE, MRM5m, (outs), (ins opaquemem_norex2:$dst),
"xrstor64\t$dst",
[(int_x86_xrstor64 addr:$dst, EDX, EAX)]>, TB, Requires<[HasXSAVE, In64BitMode]>;
-def XSAVEOPT : I<0xAE, MRM6m, (outs), (ins opaquemem:$dst),
+def XSAVEOPT : I<0xAE, MRM6m, (outs), (ins opaquemem_norex2:$dst),
"xsaveopt\t$dst",
[(int_x86_xsaveopt addr:$dst, EDX, EAX)]>, TB, Requires<[HasXSAVEOPT]>;
-def XSAVEOPT64 : RI<0xAE, MRM6m, (outs), (ins opaquemem:$dst),
+def XSAVEOPT64 : RI<0xAE, MRM6m, (outs), (ins opaquemem_norex2:$dst),
"xsaveopt64\t$dst",
[(int_x86_xsaveopt64 addr:$dst, EDX, EAX)]>, TB, Requires<[HasXSAVEOPT, In64BitMode]>;
-def XSAVEC : I<0xC7, MRM4m, (outs), (ins opaquemem:$dst),
+def XSAVEC : I<0xC7, MRM4m, (outs), (ins opaquemem_norex2:$dst),
"xsavec\t$dst",
[(int_x86_xsavec addr:$dst, EDX, EAX)]>, TB, Requires<[HasXSAVEC]>;
-def XSAVEC64 : RI<0xC7, MRM4m, (outs), (ins opaquemem:$dst),
+def XSAVEC64 : RI<0xC7, MRM4m, (outs), (ins opaquemem_norex2:$dst),
"xsavec64\t$dst",
[(int_x86_xsavec64 addr:$dst, EDX, EAX)]>, TB, Requires<[HasXSAVEC, In64BitMode]>;
-def XSAVES : I<0xC7, MRM5m, (outs), (ins opaquemem:$dst),
+def XSAVES : I<0xC7, MRM5m, (outs), (ins opaquemem_norex2:$dst),
"xsaves\t$dst",
[(int_x86_xsaves addr:$dst, EDX, EAX)]>, TB, Requires<[HasXSAVES]>;
-def XSAVES64 : RI<0xC7, MRM5m, (outs), (ins opaquemem:$dst),
+def XSAVES64 : RI<0xC7, MRM5m, (outs), (ins opaquemem_norex2:$dst),
"xsaves64\t$dst",
[(int_x86_xsaves64 addr:$dst, EDX, EAX)]>, TB, Requires<[HasXSAVE, In64BitMode]>;
-def XRSTORS : I<0xC7, MRM3m, (outs), (ins opaquemem:$dst),
+def XRSTORS : I<0xC7, MRM3m, (outs), (ins opaquemem_norex2:$dst),
"xrstors\t$dst",
[(int_x86_xrstors addr:$dst, EDX, EAX)]>, TB, Requires<[HasXSAVES]>;
-def XRSTORS64 : RI<0xC7, MRM3m, (outs), (ins opaquemem:$dst),
+def XRSTORS64 : RI<0xC7, MRM3m, (outs), (ins opaquemem_norex2:$dst),
"xrstors64\t$dst",
[(int_x86_xrstors64 addr:$dst, EDX, EAX)]>, TB, Requires<[HasXSAVES, In64BitMode]>;
} // Uses
diff --git a/llvm/lib/Target/X86/X86InstrTBM.td b/llvm/lib/Target/X86/X86InstrTBM.td
index af07c3d90563a..2a75ddf5cbfdd 100644
--- a/llvm/lib/Target/X86/X86InstrTBM.td
+++ b/llvm/lib/Target/X86/X86InstrTBM.td
@@ -15,7 +15,7 @@
//
let Predicates = [HasTBM], Defs = [EFLAGS] in {
-multiclass tbm_bextri<bits<8> opc, RegisterClass RC, string OpcodeStr,
+multiclass tbm_bextri<bits<8> opc, DAGOperand RC, string OpcodeStr,
X86MemOperand x86memop, PatFrag ld_frag,
SDNode OpNode, Operand immtype,
SDPatternOperator immoperator,
@@ -33,15 +33,15 @@ multiclass tbm_bextri<bits<8> opc, RegisterClass RC, string OpcodeStr,
XOP, XOPA, Sched<[Sched.Folded]>;
}
-defm BEXTRI32 : tbm_bextri<0x10, GR32, "bextr{l}", i32mem, loadi32,
+defm BEXTRI32 : tbm_bextri<0x10, gr32_norex2, "bextr{l}", i32mem_norex2, loadi32,
X86bextri, i32imm, timm, WriteBEXTR>;
let ImmT = Imm32S in
-defm BEXTRI64 : tbm_bextri<0x10, GR64, "bextr{q}", i64mem, loadi64,
+defm BEXTRI64 : tbm_bextri<0x10, gr64_norex2, "bextr{q}", i64mem_norex2, loadi64,
X86bextri, i64i32imm,
i64timmSExt32, WriteBEXTR>, REX_W;
multiclass tbm_binary_rm<bits<8> opc, Format FormReg, Format FormMem,
- RegisterClass RC, string OpcodeStr,
+ DAGOperand RC, string OpcodeStr,
X86MemOperand x86memop, X86FoldableSchedWrite Sched> {
let hasSideEffects = 0 in {
def rr : I<opc, FormReg, (outs RC:$dst), (ins RC:$src),
@@ -57,10 +57,10 @@ let hasSideEffects = 0 in {
multiclass tbm_binary_intr<bits<8> opc, string OpcodeStr,
X86FoldableSchedWrite Sched,
Format FormReg, Format FormMem> {
- defm NAME#32 : tbm_binary_rm<opc, FormReg, FormMem, GR32, OpcodeStr#"{l}",
- i32mem, Sched>;
- defm NAME#64 : tbm_binary_rm<opc, FormReg, FormMem, GR64, OpcodeStr#"{q}",
- i64mem, Sched>, REX_W;
+ defm NAME#32 : tbm_binary_rm<opc, FormReg, FormMem, gr32_norex2, OpcodeStr#"{l}",
+ i32mem_norex2, Sched>;
+ defm NAME#64 : tbm_binary_rm<opc, FormReg, FormMem, gr64_norex2, OpcodeStr#"{q}",
+ i64mem_norex2, Sched>, REX_W;
}
defm BLCFILL : tbm_binary_intr<0x01, "blcfill", WriteALU, MRM1r, MRM1m>;
diff --git a/llvm/test/MC/X86/apx/no-rex2-reject.s b/llvm/test/MC/X86/apx/no-rex2-reject.s
new file mode 100644
index 0000000000000..54f64462715dc
--- /dev/null
+++ b/llvm/test/MC/X86/apx/no-rex2-reject.s
@@ -0,0 +1,33 @@
+# RUN: not llvm-mc -triple x86_64 -mattr=+xsave,+ssse3,+avx,+tbm %s 2>&1 | \
+# RUN: FileCheck --check-prefix=ERROR --implicit-check-not=error: %s
+
+# An extended GPR (r16-r31) can only be encoded by an EVEX
+# instruction, or a legacy instruction in the primary or 0F opcode map
+# (which the REX2 prefix can extend). Instructions outside that set
+# reject an r16-r31 in any operand.
+
+# XSAVE/XRSTOR are in the 0F map but are excepted from REX2 promotion,
+# so the address base cannot be an EGPR.
+# ERROR: [[#@LINE+1]]:1: error: unsupported instruction
+xsave (%r16)
+# ERROR: [[#@LINE+1]]:1: error: unsupported instruction
+xrstor (%r16)
+
+# PABSB is in the 0F38 map, so neither the base nor the index of its
+# address may be an EGPR.
+# ERROR: [[#@LINE+1]]:1: error: unsupported instruction
+pabsb (%r16), %xmm0
+# ERROR: [[#@LINE+1]]:1: error: unsupported instruction
+pabsb (%rax,%r16), %xmm0
+
+# TBM is XOP-encoded.
+# ERROR: [[#@LINE+1]]:1: error: unsupported instruction
+bextr $1, (%r16), %eax
+# ERROR: [[#@LINE+1]]:1: error: unsupported instruction
+blcfill %r16d, %eax
+
+# The VEX form of cvtsd2si cannot write an EGPR. The EVEX form can,
+# but only with AVX512, so force VEX to select the restricted
+# encoding.
+# ERROR: [[#@LINE+1]]:1: error: unsupported instruction
+{vex} vcvtsd2si %xmm0, %r16d
diff --git a/llvm/test/MachineVerifier/X86/apx-norex2-regclass.mir b/llvm/test/MachineVerifier/X86/apx-norex2-regclass.mir
new file mode 100644
index 0000000000000..7e0d98e486bf2
--- /dev/null
+++ b/llvm/test/MachineVerifier/X86/apx-norex2-regclass.mir
@@ -0,0 +1,62 @@
+# RUN: not --crash llc -mtriple=x86_64 \
+# RUN: -mattr=+ssse3,+avx,+tbm,+amx-tile,+egpr -run-pass=none -filetype=null %s \
+# RUN: 2>&1 | FileCheck %s -implicit-check-not="Bad machine code"
+
+# The *_norex2 operands resolve to the *_NOREX2 register classes in the
+# X86_64_EGPR HwMode, so the machine verifier now rejects an r16-r31 (EGPR)
+# operand on an instruction that cannot encode one. This is what previously
+# required the X86InstrInfo::getRegClass override; the encoding restriction is
+# otherwise only caught when emitting an object file.
+
+---
+name: egpr_regclass
+tracksRegLiveness: true
+body: |
+ bb.0:
+ liveins: $r16, $r17, $rbx, $xmm0, $rdi, $rax
+
+ ; PABSB is an SSSE3 T8 instruction (a legacy map other than OB/TB), so
+ ; X86II::canUseApxExtendedReg is false and its address base cannot be an
+ ; EGPR.
+ ; CHECK: *** Bad machine code: Illegal physical register for instruction ***
+ ; CHECK: - instruction: renamable $xmm1 = PABSBrm renamable $r16
+ ; CHECK: $r16 is not a GR64_NOREX2 register.
+ renamable $xmm1 = PABSBrm renamable $r16, 1, $noreg, 0, $noreg
+
+ ; The address index is constrained the same way (the _nosp variant).
+ ; CHECK: *** Bad machine code: Illegal physical register for instruction ***
+ ; CHECK: - instruction: renamable $xmm2 = PABSBrm renamable $rdi, 4, renamable $r17
+ ; CHECK: $r17 is not a GR64_NOREX2_NOSP register.
+ renamable $xmm2 = PABSBrm renamable $rdi, 4, renamable $r17, 0, $noreg
+
+ ; A non-EGPR base and index are legal in the same subtarget.
+ renamable $xmm3 = PABSBrm renamable $rbx, 1, $noreg, 0, $noreg
+
+ ; TBM is XOP-encoded; its address base cannot be an EGPR.
+ ; CHECK: *** Bad machine code: Illegal physical register for instruction ***
+ ; CHECK: - instruction: renamable $ecx = BEXTRI32mi renamable $r16
+ ; CHECK: $r16 is not a GR64_NOREX2 register.
+ renamable $ecx = BEXTRI32mi renamable $r16, 1, $noreg, 0, $noreg, 2571, implicit-def $eflags
+
+ ; x87 load pseudo; the address base cannot be an EGPR.
+ ; CHECK: *** Bad machine code: Illegal physical register for instruction ***
+ ; CHECK: - instruction: renamable $fp0 = LD_Fp32m renamable $r16
+ ; CHECK: $r16 is not a GR64_NOREX2 register.
+ renamable $fp0 = LD_Fp32m renamable $r16, 1, $noreg, 0, $noreg, implicit-def dead $fpsw, implicit $fpcw
+
+ ; AMX tile-load pseudo with a SIB address; the base cannot be an EGPR.
+ ; CHECK: *** Bad machine code: Illegal physical register for instruction ***
+ ; CHECK: - instruction: PTILELOADD 4, renamable $r16
+ ; CHECK: $r16 is not a GR64_NOREX2 register.
+ PTILELOADD 4, renamable $r16, 1, killed renamable $rax, 0, $noreg
+
+ ; The VEX encoding of cvtsd2si cannot write an EGPR (the EVEX form can, but
+ ; is a separate instruction), so the GPR def is constrained.
+ ; CHECK: *** Bad machine code: Illegal physical register for instruction ***
+ ; CHECK: - instruction: renamable $r18d = VCVTSD2SIrr_Int
+ ; CHECK: $r18d is not a GR32_NOREX2 register.
+ renamable $r18d = VCVTSD2SIrr_Int renamable $xmm0, implicit $mxcsr
+
+ ; MOV32rm is EGPR-capable, so an EGPR def is accepted.
+ renamable $r19d = MOV32rm renamable $rdi, 1, $noreg, 0, $noreg
+...
diff --git a/llvm/test/MachineVerifier/X86/lit.local.cfg b/llvm/test/MachineVerifier/X86/lit.local.cfg
new file mode 100644
index 0000000000000..42bf50dcc13c3
--- /dev/null
+++ b/llvm/test/MachineVerifier/X86/lit.local.cfg
@@ -0,0 +1,2 @@
+if not "X86" in config.root.targets:
+ config.unsupported = True
diff --git a/llvm/utils/TableGen/AsmMatcherEmitter.cpp b/llvm/utils/TableGen/AsmMatcherEmitter.cpp
index 8ca01a191179a..842eccc1506a7 100644
--- a/llvm/utils/TableGen/AsmMatcherEmitter.cpp
+++ b/llvm/utils/TableGen/AsmMatcherEmitter.cpp
@@ -236,6 +236,11 @@ struct ClassInfo {
return Kind >= RegisterClassByHwMode0 && Kind < UserClass0;
}
+ /// Check if this is a register class, either plain or by-hwmode.
+ bool isAnyRegisterClass() const {
+ return isRegisterClass() || isRegisterClassByHwMode();
+ }
+
/// isUserClass() - Check if this is a user defined class.
bool isUserClass() const { return Kind >= UserClass0; }
@@ -654,6 +659,15 @@ struct MatchableInfo {
// Compare lexicographically by operand. The matcher validates that other
// orderings wouldn't be ambiguous using \see couldMatchAmbiguouslyWith().
for (const auto &[LHSOp, RHSOp] : zip_equal(AsmOperands, RHS.AsmOperands)) {
+ // A RegisterClassByHwMode and a plain RegisterClass in the same slot
+ // accept overlapping registers, but operator< always sorts the former
+ // after the latter, which would defeat the position-order tiebreak below
+ // (e.g. VEX before EVEX on X86). Skip such slots.
+ if (LHSOp.Class->isAnyRegisterClass() &&
+ RHSOp.Class->isAnyRegisterClass() &&
+ LHSOp.Class->isRegisterClassByHwMode() !=
+ RHSOp.Class->isRegisterClassByHwMode())
+ continue;
if (*LHSOp.Class < *RHSOp.Class)
return true;
if (*RHSOp.Class < *LHSOp.Class)
diff --git a/llvm/utils/TableGen/X86FoldTablesEmitter.cpp b/llvm/utils/TableGen/X86FoldTablesEmitter.cpp
index a909d4f0378b8..26cf655cc7f33 100644
--- a/llvm/utils/TableGen/X86FoldTablesEmitter.cpp
+++ b/llvm/utils/TableGen/X86FoldTablesEmitter.cpp
@@ -371,6 +371,13 @@ static bool isNOREXRegClass(const Record *Op) {
return Op->getName().contains("_NOREX");
}
+// A register operand may be a RegisterClassLike, possibly wrapped by
+// RegisterOperand
+static bool isRegOrRegByHwModeOperand(const Record *Op) {
+ return Op->isSubClassOf("RegisterClassLike") ||
+ Op->isSubClassOf("RegisterOperand");
+}
+
// Function object - Operator() returns true if the given Reg instruction
// matches the Mem instruction of this object.
namespace {
@@ -454,7 +461,8 @@ class IsMatch {
if (MemOpRec == RegOpRec)
continue;
- if (isRegisterOperand(MemOpRec) && isRegisterOperand(RegOpRec) &&
+ if (isRegOrRegByHwModeOperand(MemOpRec) &&
+ isRegOrRegByHwModeOperand(RegOpRec) &&
((getRegOperandSize(MemOpRec) != getRegOperandSize(RegOpRec)) ||
(isNOREXRegClass(MemOpRec) != isNOREXRegClass(RegOpRec))))
return false;
@@ -471,7 +479,7 @@ class IsMatch {
if (FoundFoldedOp)
return false;
- assert(isRegisterOperand(RegOpRec) && isMemoryOperand(MemOpRec));
+ assert(isRegOrRegByHwModeOperand(RegOpRec) && isMemoryOperand(MemOpRec));
FoundFoldedOp = true;
}
diff --git a/llvm/utils/TableGen/X86RecognizableInstr.cpp b/llvm/utils/TableGen/X86RecognizableInstr.cpp
index 44b76ae7e8487..ec82a98979818 100644
--- a/llvm/utils/TableGen/X86RecognizableInstr.cpp
+++ b/llvm/utils/TableGen/X86RecognizableInstr.cpp
@@ -56,7 +56,20 @@ bool X86Disassembler::isImmediateOperand(const Record *Rec) {
Rec->getValueAsString("OperandType") == "OPERAND_IMMEDIATE";
}
+// A RegClassByHwMode resolves to a different register class per subtarget, but
+// every mode maps to a class with the same encoding and width. Return one of
+// them as a representative so the operand can be treated like a plain register
+// class (for encoding, size, etc.) instead of enumerating each by-hwmode
+// operand name in the switches below.
+static const Record *getRegClassByHwModeRepresentative(const Record *Rec) {
+ const ListInit *Objects = Rec->getValueAsListInit("Objects");
+ assert(Objects->size() && "RegClassByHwMode with no register classes");
+ return Objects->getElementAsRecord(0);
+}
+
unsigned X86Disassembler::getRegOperandSize(const Record *RegRec) {
+ if (RegRec->isSubClassOf("RegClassByHwMode"))
+ RegRec = getRegClassByHwModeRepresentative(RegRec);
if (RegRec->isSubClassOf("RegisterClass"))
return RegRec->getValueAsInt("Alignment");
if (RegRec->isSubClassOf("RegisterOperand"))
@@ -435,7 +448,10 @@ void RecognizableInstr::handleOperand(bool optional, unsigned &operandIndex,
++operandIndex;
}
- StringRef typeName = (*Operands)[operandIndex].Rec->getName();
+ const Record *OpRec = (*Operands)[operandIndex].Rec;
+ if (OpRec->isSubClassOf("RegClassByHwMode"))
+ OpRec = getRegClassByHwModeRepresentative(OpRec);
+ StringRef typeName = OpRec->getName();
OperandEncoding encoding = encodingFromString(typeName, OpSize);
// Adjust the encoding type for an operand based on the instruction.
@@ -1018,21 +1034,21 @@ OperandType RecognizableInstr::typeFromString(StringRef Str, bool hasREX_W,
}
// clang-format off
OperandType Type =
- Switch.Case("i16mem", TYPE_M)
+ Switch.Cases({"i16mem", "i16mem_norex2"}, TYPE_M)
.Case("i16imm", TYPE_IMM)
.Case("i16i8imm", TYPE_IMM)
.Case("GR16", TYPE_R16)
.Case("GR16orGR32orGR64", TYPE_R16)
- .Case("i32mem", TYPE_M)
+ .Cases({"i32mem", "i32mem_norex2"}, TYPE_M)
.Case("i32imm", TYPE_IMM)
.Case("i32i8imm", TYPE_IMM)
.Case("GR32", TYPE_R32)
.Case("GR32orGR64", TYPE_R32)
- .Case("i64mem", TYPE_M)
+ .Cases({"i64mem", "i64mem_norex2"}, TYPE_M)
.Case("i64i32imm", TYPE_IMM)
.Case("i64i8imm", TYPE_IMM)
.Case("GR64", TYPE_R64)
- .Case("i8mem", TYPE_M)
+ .Cases({"i8mem", "i8mem_norex2"}, TYPE_M)
.Case("i8imm", TYPE_IMM)
.Case("u4imm", TYPE_UIMM8)
.Case("u8imm", TYPE_UIMM8)
@@ -1048,19 +1064,19 @@ OperandType RecognizableInstr::typeFromString(StringRef Str, bool hasREX_W,
.Case("FR128", TYPE_XMM)
.Case("FR64", TYPE_XMM)
.Case("FR64X", TYPE_XMM)
- .Case("f64mem", TYPE_M)
- .Case("sdmem", TYPE_M)
+ .Cases({"f64mem", "f64mem_norex2"}, TYPE_M)
+ .Cases({"sdmem", "sdmem_norex2"}, TYPE_M)
.Case("FR16X", TYPE_XMM)
.Case("FR32", TYPE_XMM)
.Case("FR32X", TYPE_XMM)
- .Case("f32mem", TYPE_M)
+ .Cases({"f32mem", "f32mem_norex2"}, TYPE_M)
.Case("f16mem", TYPE_M)
- .Case("ssmem", TYPE_M)
+ .Cases({"ssmem", "ssmem_norex2"}, TYPE_M)
.Case("shmem", TYPE_M)
.Case("RST", TYPE_ST)
.Case("RSTi", TYPE_ST)
- .Case("i128mem", TYPE_M)
- .Case("i256mem", TYPE_M)
+ .Cases({"i128mem", "i128mem_norex2"}, TYPE_M)
+ .Cases({"i256mem", "i256mem_norex2"}, TYPE_M)
.Case("i512mem", TYPE_M)
.Case("i512mem_GR16", TYPE_M)
.Case("i512mem_GR32", TYPE_M)
@@ -1075,16 +1091,16 @@ OperandType RecognizableInstr::typeFromString(StringRef Str, bool hasREX_W,
.Case("brtarget32", TYPE_REL)
.Case("brtarget16", TYPE_REL)
.Case("brtarget8", TYPE_REL)
- .Case("f80mem", TYPE_M)
+ .Cases({"f80mem", "f80mem_norex2"}, TYPE_M)
.Case("lea64_8mem", TYPE_M)
.Case("lea64_16mem", TYPE_M)
.Case("lea64_32mem", TYPE_M)
.Case("lea64mem", TYPE_M)
.Case("VR64", TYPE_MM64)
.Case("i64imm", TYPE_IMM)
- .Case("anymem", TYPE_M)
- .Case("opaquemem", TYPE_M)
- .Case("sibmem", TYPE_MSIB)
+ .Cases({"anymem", "anymem_norex2"}, TYPE_M)
+ .Cases({"opaquemem", "opaquemem_norex2"}, TYPE_M)
+ .Cases({"sibmem", "sibmem_norex2"}, TYPE_MSIB)
.Case("SEGMENT_REG", TYPE_SEGMENTREG)
.Case("DEBUG_REG", TYPE_DEBUGREG)
.Case("CONTROL_REG", TYPE_CONTROLREG)
@@ -1367,33 +1383,33 @@ OperandEncoding RecognizableInstr::memoryEncodingFromString(StringRef Str,
// clang-format off
auto Encoding =
StringSwitch<OperandEncoding>(Str)
- .Case("i16mem", ENCODING_RM)
- .Case("i32mem", ENCODING_RM)
- .Case("i64mem", ENCODING_RM)
- .Case("i8mem", ENCODING_RM)
+ .Cases({"i16mem", "i16mem_norex2"}, ENCODING_RM)
+ .Cases({"i32mem", "i32mem_norex2"}, ENCODING_RM)
+ .Cases({"i64mem", "i64mem_norex2"}, ENCODING_RM)
+ .Cases({"i8mem", "i8mem_norex2"}, ENCODING_RM)
.Case("shmem", ENCODING_RM)
- .Case("ssmem", ENCODING_RM)
- .Case("sdmem", ENCODING_RM)
+ .Cases({"ssmem", "ssmem_norex2"}, ENCODING_RM)
+ .Cases({"sdmem", "sdmem_norex2"}, ENCODING_RM)
.Case("f128mem", ENCODING_RM)
.Case("f256mem", ENCODING_RM)
.Case("f512mem", ENCODING_RM)
- .Case("f64mem", ENCODING_RM)
- .Case("f32mem", ENCODING_RM)
+ .Cases({"f64mem", "f64mem_norex2"}, ENCODING_RM)
+ .Cases({"f32mem", "f32mem_norex2"}, ENCODING_RM)
.Case("f16mem", ENCODING_RM)
- .Case("i128mem", ENCODING_RM)
- .Case("i256mem", ENCODING_RM)
+ .Cases({"i128mem", "i128mem_norex2"}, ENCODING_RM)
+ .Cases({"i256mem", "i256mem_norex2"}, ENCODING_RM)
.Case("i512mem", ENCODING_RM)
.Case("i512mem_GR16", ENCODING_RM)
.Case("i512mem_GR32", ENCODING_RM)
.Case("i512mem_GR64", ENCODING_RM)
- .Case("f80mem", ENCODING_RM)
+ .Cases({"f80mem", "f80mem_norex2"}, ENCODING_RM)
.Case("lea64_8mem", ENCODING_RM)
.Case("lea64_16mem", ENCODING_RM)
.Case("lea64_32mem", ENCODING_RM)
.Case("lea64mem", ENCODING_RM)
- .Case("anymem", ENCODING_RM)
- .Case("opaquemem", ENCODING_RM)
- .Case("sibmem", ENCODING_SIB)
+ .Cases({"anymem", "anymem_norex2"}, ENCODING_RM)
+ .Cases({"opaquemem", "opaquemem_norex2"}, ENCODING_RM)
+ .Cases({"sibmem", "sibmem_norex2"}, ENCODING_SIB)
.Case("vx32mem", ENCODING_VSIB)
.Case("vx64mem", ENCODING_VSIB)
.Case("vy32mem", ENCODING_VSIB)
>From ec4db72cd006671b6328751e28ea7b51efef7490 Mon Sep 17 00:00:00 2001
From: Matt Arsenault <Matthew.Arsenault at amd.com>
Date: Mon, 21 Sep 2026 14:11:53 +0200
Subject: [PATCH 2/3] Recognize RegClassByHwMode operands in isRegisterOperand
---
llvm/utils/TableGen/X86FoldTablesEmitter.cpp | 12 ++----------
llvm/utils/TableGen/X86RecognizableInstr.cpp | 3 ++-
2 files changed, 4 insertions(+), 11 deletions(-)
diff --git a/llvm/utils/TableGen/X86FoldTablesEmitter.cpp b/llvm/utils/TableGen/X86FoldTablesEmitter.cpp
index 26cf655cc7f33..a909d4f0378b8 100644
--- a/llvm/utils/TableGen/X86FoldTablesEmitter.cpp
+++ b/llvm/utils/TableGen/X86FoldTablesEmitter.cpp
@@ -371,13 +371,6 @@ static bool isNOREXRegClass(const Record *Op) {
return Op->getName().contains("_NOREX");
}
-// A register operand may be a RegisterClassLike, possibly wrapped by
-// RegisterOperand
-static bool isRegOrRegByHwModeOperand(const Record *Op) {
- return Op->isSubClassOf("RegisterClassLike") ||
- Op->isSubClassOf("RegisterOperand");
-}
-
// Function object - Operator() returns true if the given Reg instruction
// matches the Mem instruction of this object.
namespace {
@@ -461,8 +454,7 @@ class IsMatch {
if (MemOpRec == RegOpRec)
continue;
- if (isRegOrRegByHwModeOperand(MemOpRec) &&
- isRegOrRegByHwModeOperand(RegOpRec) &&
+ if (isRegisterOperand(MemOpRec) && isRegisterOperand(RegOpRec) &&
((getRegOperandSize(MemOpRec) != getRegOperandSize(RegOpRec)) ||
(isNOREXRegClass(MemOpRec) != isNOREXRegClass(RegOpRec))))
return false;
@@ -479,7 +471,7 @@ class IsMatch {
if (FoundFoldedOp)
return false;
- assert(isRegOrRegByHwModeOperand(RegOpRec) && isMemoryOperand(MemOpRec));
+ assert(isRegisterOperand(RegOpRec) && isMemoryOperand(MemOpRec));
FoundFoldedOp = true;
}
diff --git a/llvm/utils/TableGen/X86RecognizableInstr.cpp b/llvm/utils/TableGen/X86RecognizableInstr.cpp
index ec82a98979818..cc3176bf44911 100644
--- a/llvm/utils/TableGen/X86RecognizableInstr.cpp
+++ b/llvm/utils/TableGen/X86RecognizableInstr.cpp
@@ -42,7 +42,8 @@ std::string X86Disassembler::getMnemonic(const CodeGenInstruction *I,
}
bool X86Disassembler::isRegisterOperand(const Record *Rec) {
- return Rec->isSubClassOf("RegisterClass") ||
+ // RegisterClassLike covers both RegisterClass and RegClassByHwMode.
+ return Rec->isSubClassOf("RegisterClassLike") ||
Rec->isSubClassOf("RegisterOperand");
}
>From 7c115cf8a0d7e718de107389a0b076ead3081006 Mon Sep 17 00:00:00 2001
From: Matt Arsenault <Matthew.Arsenault at amd.com>
Date: Mon, 21 Sep 2026 14:32:55 +0200
Subject: [PATCH 3/3] Mark more EGPR incompatible instruction cases
---
llvm/lib/Target/X86/X86InstrKL.td | 16 +-
llvm/lib/Target/X86/X86InstrMMX.td | 6 +-
llvm/lib/Target/X86/X86InstrOperands.td | 20 ++
llvm/lib/Target/X86/X86InstrSSE.td | 326 ++++++++++--------
llvm/test/MC/X86/apx/no-rex2-reject.s | 82 ++++-
.../X86/apx-norex2-regclass.mir | 16 +-
llvm/utils/TableGen/X86RecognizableInstr.cpp | 34 +-
7 files changed, 323 insertions(+), 177 deletions(-)
diff --git a/llvm/lib/Target/X86/X86InstrKL.td b/llvm/lib/Target/X86/X86InstrKL.td
index d5a4be45cc9b1..9582343ed6da4 100644
--- a/llvm/lib/Target/X86/X86InstrKL.td
+++ b/llvm/lib/Target/X86/X86InstrKL.td
@@ -20,22 +20,22 @@ class Encodekey<bits<8> opcode, string m>
multiclass Aesencdec<string suffix> {
def AESENC128KL#suffix : I<0xDC, MRMSrcMem, (outs VR128:$dst),
- (ins VR128:$src1, opaquemem:$src2),
+ (ins VR128:$src1, opaquemem_norex2:$src2),
"aesenc128kl\t{$src2, $src1|$src1, $src2}",
[(set VR128:$dst, EFLAGS, (X86aesenc128kl VR128:$src1, addr:$src2))]>,
NoCD8, XS;
def AESDEC128KL#suffix : I<0xDD, MRMSrcMem, (outs VR128:$dst),
- (ins VR128:$src1, opaquemem:$src2),
+ (ins VR128:$src1, opaquemem_norex2:$src2),
"aesdec128kl\t{$src2, $src1|$src1, $src2}",
[(set VR128:$dst, EFLAGS, (X86aesdec128kl VR128:$src1, addr:$src2))]>,
NoCD8, XS;
def AESENC256KL#suffix : I<0xDE, MRMSrcMem, (outs VR128:$dst),
- (ins VR128:$src1, opaquemem:$src2),
+ (ins VR128:$src1, opaquemem_norex2:$src2),
"aesenc256kl\t{$src2, $src1|$src1, $src2}",
[(set VR128:$dst, EFLAGS, (X86aesenc256kl VR128:$src1, addr:$src2))]>,
NoCD8, XS;
def AESDEC256KL#suffix : I<0xDF, MRMSrcMem, (outs VR128:$dst),
- (ins VR128:$src1, opaquemem:$src2),
+ (ins VR128:$src1, opaquemem_norex2:$src2),
"aesdec256kl\t{$src2, $src1|$src1, $src2}",
[(set VR128:$dst, EFLAGS, (X86aesdec256kl VR128:$src1, addr:$src2))]>,
NoCD8, XS;
@@ -61,10 +61,10 @@ let SchedRW = [WriteSystem] in {
} // SchedRW
multiclass Aesencdecwide<string suffix> {
- def AESENCWIDE128KL#suffix : I<0xD8, MRM0m, (outs), (ins opaquemem:$src), "aesencwide128kl\t$src", []>, NoCD8, XS;
- def AESDECWIDE128KL#suffix : I<0xD8, MRM1m, (outs), (ins opaquemem:$src), "aesdecwide128kl\t$src", []>, NoCD8, XS;
- def AESENCWIDE256KL#suffix : I<0xD8, MRM2m, (outs), (ins opaquemem:$src), "aesencwide256kl\t$src", []>, NoCD8, XS;
- def AESDECWIDE256KL#suffix : I<0xD8, MRM3m, (outs), (ins opaquemem:$src), "aesdecwide256kl\t$src", []>, NoCD8, XS;
+ def AESENCWIDE128KL#suffix : I<0xD8, MRM0m, (outs), (ins opaquemem_norex2:$src), "aesencwide128kl\t$src", []>, NoCD8, XS;
+ def AESDECWIDE128KL#suffix : I<0xD8, MRM1m, (outs), (ins opaquemem_norex2:$src), "aesdecwide128kl\t$src", []>, NoCD8, XS;
+ def AESENCWIDE256KL#suffix : I<0xD8, MRM2m, (outs), (ins opaquemem_norex2:$src), "aesencwide256kl\t$src", []>, NoCD8, XS;
+ def AESDECWIDE256KL#suffix : I<0xD8, MRM3m, (outs), (ins opaquemem_norex2:$src), "aesdecwide256kl\t$src", []>, NoCD8, XS;
}
let SchedRW = [WriteSystem], Uses = [XMM0, XMM1, XMM2, XMM3, XMM4, XMM5, XMM6, XMM7],
diff --git a/llvm/lib/Target/X86/X86InstrMMX.td b/llvm/lib/Target/X86/X86InstrMMX.td
index a603e8330c445..3c8a75bcc85e0 100644
--- a/llvm/lib/Target/X86/X86InstrMMX.td
+++ b/llvm/lib/Target/X86/X86InstrMMX.td
@@ -78,7 +78,7 @@ multiclass SS3I_unop_rm_int_mm<bits<8> opc, string OpcodeStr,
[(set VR64:$dst, (IntId64 VR64:$src))]>,
Sched<[sched]>;
- def rm : MMXSS38I<opc, MRMSrcMem, (outs VR64:$dst), (ins i64mem:$src),
+ def rm : MMXSS38I<opc, MRMSrcMem, (outs VR64:$dst), (ins i64mem_norex2:$src),
!strconcat(OpcodeStr, "\t{$src, $dst|$dst, $src}"),
[(set VR64:$dst, (IntId64 (load_mmx addr:$src)))]>,
Sched<[sched.Folded]>;
@@ -96,7 +96,7 @@ multiclass SS3I_binop_rm_int_mm<bits<8> opc, string OpcodeStr,
[(set VR64:$dst, (IntId64 VR64:$src1, VR64:$src2))]>,
Sched<[sched]>;
def rm : MMXSS38I<opc, MRMSrcMem, (outs VR64:$dst),
- (ins VR64:$src1, i64mem:$src2),
+ (ins VR64:$src1, i64mem_norex2:$src2),
!strconcat(OpcodeStr, "\t{$src2, $dst|$dst, $src2}"),
[(set VR64:$dst,
(IntId64 VR64:$src1, (load_mmx addr:$src2)))]>,
@@ -113,7 +113,7 @@ multiclass ssse3_palign_mm<string asm, Intrinsic IntId,
[(set VR64:$dst, (IntId VR64:$src1, VR64:$src2, (i8 timm:$src3)))]>,
Sched<[sched]>;
def rmi : MMXSS3AI<0x0F, MRMSrcMem, (outs VR64:$dst),
- (ins VR64:$src1, i64mem:$src2, u8imm:$src3),
+ (ins VR64:$src1, i64mem_norex2:$src2, u8imm:$src3),
!strconcat(asm, "\t{$src3, $src2, $dst|$dst, $src2, $src3}"),
[(set VR64:$dst, (IntId VR64:$src1, (load_mmx addr:$src2),
(i8 timm:$src3)))]>,
diff --git a/llvm/lib/Target/X86/X86InstrOperands.td b/llvm/lib/Target/X86/X86InstrOperands.td
index a6bb9e381cb8b..09c7eab4d06cd 100644
--- a/llvm/lib/Target/X86/X86InstrOperands.td
+++ b/llvm/lib/Target/X86/X86InstrOperands.td
@@ -109,6 +109,14 @@ class X86MemOperandNoRex2<string printMethod,
SEGMENT_REG);
}
+// A gather mem operand whose base register cannot be an EGPR (the index is a
+// vector register). Used by VEX gathers, which have no in-place EVEX form.
+class X86VMemOperandNoRex2<RegisterClass RC, string printMethod,
+ AsmOperandClass parserMatchClass, int size = 0>
+ : X86MemOperand<printMethod, parserMatchClass, size> {
+ let MIOperandInfo = (ops ptr_rc_norex2, i8imm, RC, i32imm, SEGMENT_REG);
+}
+
def anymem : X86MemOperand<"printMemReference">;
// FIXME: Right now we allow any size during parsing, but we might want to
@@ -143,6 +151,12 @@ def vx64mem : X86VMemOperand<VR128, "printqwordmem", X86Mem64_RC128Operand, 6
def vy32mem : X86VMemOperand<VR256, "printdwordmem", X86Mem32_RC256Operand, 32>;
def vy64mem : X86VMemOperand<VR256, "printqwordmem", X86Mem64_RC256Operand, 64>;
+// norex2 gather mem operands, for VEX gathers (no in-place EVEX form).
+def vx32mem_norex2 : X86VMemOperandNoRex2<VR128, "printdwordmem", X86Mem32_RC128Operand, 32>;
+def vx64mem_norex2 : X86VMemOperandNoRex2<VR128, "printqwordmem", X86Mem64_RC128Operand, 64>;
+def vy32mem_norex2 : X86VMemOperandNoRex2<VR256, "printdwordmem", X86Mem32_RC256Operand, 32>;
+def vy64mem_norex2 : X86VMemOperandNoRex2<VR256, "printqwordmem", X86Mem64_RC256Operand, 64>;
+
def vx32xmem : X86VMemOperand<VR128X, "printdwordmem", X86Mem32_RC128XOperand, 32>;
def vx64xmem : X86VMemOperand<VR128X, "printqwordmem", X86Mem64_RC128XOperand, 64>;
def vy32xmem : X86VMemOperand<VR256X, "printdwordmem", X86Mem32_RC256XOperand, 32>;
@@ -167,6 +181,8 @@ def i256mem_norex2 : X86MemOperandNoRex2<"printymmwordmem", X86Mem256AsmOperand,
def f32mem_norex2 : X86MemOperandNoRex2<"printdwordmem", X86Mem32AsmOperand, 32>;
def f64mem_norex2 : X86MemOperandNoRex2<"printqwordmem", X86Mem64AsmOperand, 64>;
def f80mem_norex2 : X86MemOperandNoRex2<"printtbytemem", X86Mem80AsmOperand, 80>;
+def f128mem_norex2 : X86MemOperandNoRex2<"printxmmwordmem", X86Mem128AsmOperand, 128>;
+def f256mem_norex2 : X86MemOperandNoRex2<"printymmwordmem", X86Mem256AsmOperand, 256>;
def ssmem_norex2 : X86MemOperandNoRex2<"printdwordmem", X86Mem32AsmOperand>;
def sdmem_norex2 : X86MemOperandNoRex2<"printqwordmem", X86Mem64AsmOperand>;
@@ -407,6 +423,10 @@ def X86GR32orGR64AsmOperand : AsmOperandClass {
def GR32orGR64 : RegisterOperand<GR32> {
let ParserMatchClass = X86GR32orGR64AsmOperand;
}
+// A GR32orGR64 for instructions that cannot encode an EGPR.
+def GR32orGR64_norex2 : RegisterOperand<gr32_norex2> {
+ let ParserMatchClass = X86GR32orGR64AsmOperand;
+}
def X86GR16orGR32orGR64AsmOperand : AsmOperandClass {
let Name = "GR16orGR32orGR64";
diff --git a/llvm/lib/Target/X86/X86InstrSSE.td b/llvm/lib/Target/X86/X86InstrSSE.td
index 4bc079fd677e1..84cc72fdd46ef 100644
--- a/llvm/lib/Target/X86/X86InstrSSE.td
+++ b/llvm/lib/Target/X86/X86InstrSSE.td
@@ -3922,7 +3922,7 @@ let Constraints = "$src1 = $dst" in {
i128mem, SchedWriteShuffle.XMM, memop>;
defm PACKUSDW : sse4_pack<0x2B, "packusdw", v8i16, v4i32, X86Packus, VR128,
- i128mem, SchedWriteShuffle.XMM, memop>;
+ i128mem_norex2, SchedWriteShuffle.XMM, memop>;
}
} // ExeDomain = SSEPackedInt
@@ -4841,7 +4841,8 @@ multiclass SS3I_binop_rm<bits<8> opc, string OpcodeStr, SDNode OpNode,
/// SS3I_binop_rm_int - Simple SSSE3 bin op whose type can be v*{i8,i16,i32}.
multiclass SS3I_binop_rm_int<bits<8> opc, string OpcodeStr,
Intrinsic IntId128, X86FoldableSchedWrite sched,
- PatFrag ld_frag, bit Is2Addr = 1> {
+ PatFrag ld_frag, bit Is2Addr = 1,
+ X86MemOperand x86memop = i128mem> {
let isCommutable = 1 in
def rr : SS38I<opc, MRMSrcReg, (outs VR128:$dst),
(ins VR128:$src1, VR128:$src2),
@@ -4851,7 +4852,7 @@ multiclass SS3I_binop_rm_int<bits<8> opc, string OpcodeStr,
[(set VR128:$dst, (IntId128 VR128:$src1, VR128:$src2))]>,
Sched<[sched]>;
def rm : SS38I<opc, MRMSrcMem, (outs VR128:$dst),
- (ins VR128:$src1, i128mem:$src2),
+ (ins VR128:$src1, x86memop:$src2),
!if(Is2Addr,
!strconcat(OpcodeStr, "\t{$src2, $dst|$dst, $src2}"),
!strconcat(OpcodeStr, "\t{$src2, $src1, $dst|$dst, $src1, $src2}")),
@@ -4970,31 +4971,31 @@ let isCommutable = 0 in {
let ImmT = NoImm, Constraints = "$src1 = $dst" in {
let isCommutable = 0 in {
defm PHADDW : SS3I_binop_rm<0x01, "phaddw", X86hadd, v8i16, v8i16, VR128,
- memop, i128mem, SchedWritePHAdd.XMM>;
+ memop, i128mem_norex2, SchedWritePHAdd.XMM>;
defm PHADDD : SS3I_binop_rm<0x02, "phaddd", X86hadd, v4i32, v4i32, VR128,
- memop, i128mem, SchedWritePHAdd.XMM>;
+ memop, i128mem_norex2, SchedWritePHAdd.XMM>;
defm PHSUBW : SS3I_binop_rm<0x05, "phsubw", X86hsub, v8i16, v8i16, VR128,
- memop, i128mem, SchedWritePHAdd.XMM>;
+ memop, i128mem_norex2, SchedWritePHAdd.XMM>;
defm PHSUBD : SS3I_binop_rm<0x06, "phsubd", X86hsub, v4i32, v4i32, VR128,
- memop, i128mem, SchedWritePHAdd.XMM>;
+ memop, i128mem_norex2, SchedWritePHAdd.XMM>;
defm PSIGNB : SS3I_binop_rm_int<0x08, "psignb", int_x86_ssse3_psign_b_128,
- SchedWriteVecALU.XMM, memop>;
+ SchedWriteVecALU.XMM, memop, 1, i128mem_norex2>;
defm PSIGNW : SS3I_binop_rm_int<0x09, "psignw", int_x86_ssse3_psign_w_128,
- SchedWriteVecALU.XMM, memop>;
+ SchedWriteVecALU.XMM, memop, 1, i128mem_norex2>;
defm PSIGND : SS3I_binop_rm_int<0x0A, "psignd", int_x86_ssse3_psign_d_128,
- SchedWriteVecALU.XMM, memop>;
+ SchedWriteVecALU.XMM, memop, 1, i128mem_norex2>;
defm PSHUFB : SS3I_binop_rm<0x00, "pshufb", X86pshufb, v16i8, v16i8, VR128,
- memop, i128mem, SchedWriteVarShuffle.XMM>;
+ memop, i128mem_norex2, SchedWriteVarShuffle.XMM>;
defm PHADDSW : SS3I_binop_rm<0x03, "phaddsw", X86hadds, v8i16, v8i16, VR128,
- memop, i128mem, SchedWritePHAdd.XMM>;
+ memop, i128mem_norex2, SchedWritePHAdd.XMM>;
defm PHSUBSW : SS3I_binop_rm<0x07, "phsubsw", X86hsubs, v8i16, v8i16, VR128,
- memop, i128mem, SchedWritePHAdd.XMM>;
+ memop, i128mem_norex2, SchedWritePHAdd.XMM>;
defm PMADDUBSW : SS3I_binop_rm<0x04, "pmaddubsw", X86vpmaddubsw, v8i16,
- v16i8, VR128, memop, i128mem,
+ v16i8, VR128, memop, i128mem_norex2,
SchedWriteVecIMul.XMM>;
}
defm PMULHRSW : SS3I_binop_rm<0x0B, "pmulhrsw", X86mulhrs, v8i16, v8i16,
- VR128, memop, i128mem, SchedWriteVecIMul.XMM>;
+ VR128, memop, i128mem_norex2, SchedWriteVecIMul.XMM>;
}
//===---------------------------------------------------------------------===//
@@ -5034,7 +5035,7 @@ let Predicates = [HasAVX2, NoVLX_Or_NoBWI] in
defm VPALIGNRY : ssse3_palignr<"vpalignr", v32i8, VR256, load, i256mem,
SchedWriteShuffle.YMM, 0>, VEX, VVVV, VEX_L, WIG;
let Constraints = "$src1 = $dst", Predicates = [UseSSSE3] in
- defm PALIGNR : ssse3_palignr<"palignr", v16i8, VR128, memop, i128mem,
+ defm PALIGNR : ssse3_palignr<"palignr", v16i8, VR128, memop, i128mem_norex2,
SchedWriteShuffle.XMM>;
//===---------------------------------------------------------------------===//
@@ -5081,8 +5082,8 @@ multiclass SS41I_pmovx_rrrm<bits<8> opc, string OpcodeStr, X86MemOperand MemOp,
multiclass SS41I_pmovx_rm_all<bits<8> opc, string OpcodeStr,
X86MemOperand MemOp, X86MemOperand MemYOp,
- Predicate prd> {
- defm NAME : SS41I_pmovx_rrrm<opc, OpcodeStr, MemOp, VR128, VR128,
+ Predicate prd, X86MemOperand MemOpNoRex2 = MemOp> {
+ defm NAME : SS41I_pmovx_rrrm<opc, OpcodeStr, MemOpNoRex2, VR128, VR128,
SchedWriteShuffle.XMM>;
let Predicates = [HasAVX, prd] in
defm V#NAME : SS41I_pmovx_rrrm<opc, !strconcat("v", OpcodeStr), MemOp,
@@ -5095,22 +5096,24 @@ multiclass SS41I_pmovx_rm_all<bits<8> opc, string OpcodeStr,
}
multiclass SS41I_pmovx_rm<bits<8> opc, string OpcodeStr, X86MemOperand MemOp,
- X86MemOperand MemYOp, Predicate prd> {
+ X86MemOperand MemYOp, Predicate prd,
+ X86MemOperand MemOpNoRex2 = MemOp> {
defm PMOVSX#NAME : SS41I_pmovx_rm_all<opc, !strconcat("pmovsx", OpcodeStr),
- MemOp, MemYOp, prd>;
+ MemOp, MemYOp, prd, MemOpNoRex2>;
defm PMOVZX#NAME : SS41I_pmovx_rm_all<!add(opc, 0x10),
!strconcat("pmovzx", OpcodeStr),
- MemOp, MemYOp, prd>;
+ MemOp, MemYOp, prd, MemOpNoRex2>;
}
-defm BW : SS41I_pmovx_rm<0x20, "bw", i64mem, i128mem, NoVLX_Or_NoBWI>;
-defm WD : SS41I_pmovx_rm<0x23, "wd", i64mem, i128mem, NoVLX>;
-defm DQ : SS41I_pmovx_rm<0x25, "dq", i64mem, i128mem, NoVLX>;
+defm BW : SS41I_pmovx_rm<0x20, "bw", i64mem, i128mem, NoVLX_Or_NoBWI,
+ i64mem_norex2>;
+defm WD : SS41I_pmovx_rm<0x23, "wd", i64mem, i128mem, NoVLX, i64mem_norex2>;
+defm DQ : SS41I_pmovx_rm<0x25, "dq", i64mem, i128mem, NoVLX, i64mem_norex2>;
-defm BD : SS41I_pmovx_rm<0x21, "bd", i32mem, i64mem, NoVLX>;
-defm WQ : SS41I_pmovx_rm<0x24, "wq", i32mem, i64mem, NoVLX>;
+defm BD : SS41I_pmovx_rm<0x21, "bd", i32mem, i64mem, NoVLX, i32mem_norex2>;
+defm WQ : SS41I_pmovx_rm<0x24, "wq", i32mem, i64mem, NoVLX, i32mem_norex2>;
-defm BQ : SS41I_pmovx_rm<0x22, "bq", i16mem, i32mem, NoVLX>;
+defm BQ : SS41I_pmovx_rm<0x22, "bq", i16mem, i32mem, NoVLX, i16mem_norex2>;
// AVX2 Patterns
multiclass SS41I_pmovx_avx2_patterns<string OpcPrefix, string ExtTy,
@@ -5293,17 +5296,19 @@ let Predicates = [UseSSE41] in {
//===----------------------------------------------------------------------===//
/// SS41I_binop_ext8 - SSE 4.1 extract 8 bits to 32 bit reg or 8 bit mem
-multiclass SS41I_extract8<bits<8> opc, string OpcodeStr> {
- def rri : SS4AIi8<opc, MRMDestReg, (outs GR32orGR64:$dst),
+multiclass SS41I_extract8<bits<8> opc, string OpcodeStr,
+ RegisterOperand DstRC = GR32orGR64,
+ X86MemOperand x86memop = i8mem> {
+ def rri : SS4AIi8<opc, MRMDestReg, (outs DstRC:$dst),
(ins VR128:$src1, u8imm:$src2),
!strconcat(OpcodeStr,
"\t{$src2, $src1, $dst|$dst, $src1, $src2}"),
- [(set GR32orGR64:$dst, (X86pextrb (v16i8 VR128:$src1),
+ [(set DstRC:$dst, (X86pextrb (v16i8 VR128:$src1),
timm:$src2))]>,
Sched<[WriteVecExtract]>;
let hasSideEffects = 0, mayStore = 1 in
def mri : SS4AIi8<opc, MRMDestMem, (outs),
- (ins i8mem:$dst, VR128:$src1, u8imm:$src2),
+ (ins x86memop:$dst, VR128:$src1, u8imm:$src2),
!strconcat(OpcodeStr,
"\t{$src2, $src1, $dst|$dst, $src1, $src2}"),
[(store (i8 (trunc (X86pextrb (v16i8 VR128:$src1), timm:$src2))),
@@ -5313,13 +5318,16 @@ multiclass SS41I_extract8<bits<8> opc, string OpcodeStr> {
let Predicates = [HasAVX, NoBWI] in
defm VPEXTRB : SS41I_extract8<0x14, "vpextrb">, VEX, WIG;
-defm PEXTRB : SS41I_extract8<0x14, "pextrb">;
+defm PEXTRB : SS41I_extract8<0x14, "pextrb", GR32orGR64_norex2,
+ i8mem_norex2>;
/// SS41I_extract16 - SSE 4.1 extract 16 bits to memory destination
-multiclass SS41I_extract16<bits<8> opc, string OpcodeStr> {
+multiclass SS41I_extract16<bits<8> opc, string OpcodeStr,
+ RegisterOperand DstRC = GR32orGR64,
+ X86MemOperand x86memop = i16mem> {
let isCodeGenOnly = 1, ForceDisassemble = 1, hasSideEffects = 0 in
- def rri_REV : SS4AIi8<opc, MRMDestReg, (outs GR32orGR64:$dst),
+ def rri_REV : SS4AIi8<opc, MRMDestReg, (outs DstRC:$dst),
(ins VR128:$src1, u8imm:$src2),
!strconcat(OpcodeStr,
"\t{$src2, $src1, $dst|$dst, $src1, $src2}"), []>,
@@ -5327,7 +5335,7 @@ multiclass SS41I_extract16<bits<8> opc, string OpcodeStr> {
let hasSideEffects = 0, mayStore = 1 in
def mri : SS4AIi8<opc, MRMDestMem, (outs),
- (ins i16mem:$dst, VR128:$src1, u8imm:$src2),
+ (ins x86memop:$dst, VR128:$src1, u8imm:$src2),
!strconcat(OpcodeStr,
"\t{$src2, $src1, $dst|$dst, $src1, $src2}"),
[(any_store_16 (i16 (trunc (X86pextrw (v8i16 VR128:$src1), timm:$src2))),
@@ -5337,7 +5345,8 @@ multiclass SS41I_extract16<bits<8> opc, string OpcodeStr> {
let Predicates = [HasAVX, NoBWI] in
defm VPEXTRW : SS41I_extract16<0x15, "vpextrw">, VEX, WIG;
-defm PEXTRW : SS41I_extract16<0x15, "pextrw">;
+defm PEXTRW : SS41I_extract16<0x15, "pextrw", GR32orGR64_norex2,
+ i16mem_norex2>;
let Predicates = [UseSSE41] in
def : Pat<(store f16:$src, addr:$dst), (PEXTRWmri addr:$dst, (v8i16 (COPY_TO_REGCLASS FR16:$src, VR128)), 0)>;
@@ -5347,16 +5356,18 @@ let Predicates = [HasAVX, NoBWI] in
/// SS41I_extract32 - SSE 4.1 extract 32 bits to int reg or memory destination
-multiclass SS41I_extract32<bits<8> opc, string OpcodeStr> {
- def rri : SS4AIi8<opc, MRMDestReg, (outs GR32:$dst),
+multiclass SS41I_extract32<bits<8> opc, string OpcodeStr,
+ DAGOperand DstRC = GR32,
+ X86MemOperand x86memop = i32mem> {
+ def rri : SS4AIi8<opc, MRMDestReg, (outs DstRC:$dst),
(ins VR128:$src1, u8imm:$src2),
!strconcat(OpcodeStr,
"\t{$src2, $src1, $dst|$dst, $src1, $src2}"),
- [(set GR32:$dst,
+ [(set DstRC:$dst,
(extractelt (v4i32 VR128:$src1), imm:$src2))]>,
Sched<[WriteVecExtract]>;
def mri : SS4AIi8<opc, MRMDestMem, (outs),
- (ins i32mem:$dst, VR128:$src1, u8imm:$src2),
+ (ins x86memop:$dst, VR128:$src1, u8imm:$src2),
!strconcat(OpcodeStr,
"\t{$src2, $src1, $dst|$dst, $src1, $src2}"),
[(store (extractelt (v4i32 VR128:$src1), imm:$src2),
@@ -5366,19 +5377,21 @@ multiclass SS41I_extract32<bits<8> opc, string OpcodeStr> {
let Predicates = [HasAVX, NoDQI] in
defm VPEXTRD : SS41I_extract32<0x16, "vpextrd">, VEX;
-defm PEXTRD : SS41I_extract32<0x16, "pextrd">;
+defm PEXTRD : SS41I_extract32<0x16, "pextrd", gr32_norex2, i32mem_norex2>;
/// SS41I_extract32 - SSE 4.1 extract 32 bits to int reg or memory destination
-multiclass SS41I_extract64<bits<8> opc, string OpcodeStr> {
- def rri : SS4AIi8<opc, MRMDestReg, (outs GR64:$dst),
+multiclass SS41I_extract64<bits<8> opc, string OpcodeStr,
+ DAGOperand DstRC = GR64,
+ X86MemOperand x86memop = i64mem> {
+ def rri : SS4AIi8<opc, MRMDestReg, (outs DstRC:$dst),
(ins VR128:$src1, u8imm:$src2),
!strconcat(OpcodeStr,
"\t{$src2, $src1, $dst|$dst, $src1, $src2}"),
- [(set GR64:$dst,
+ [(set DstRC:$dst,
(extractelt (v2i64 VR128:$src1), imm:$src2))]>,
Sched<[WriteVecExtract]>;
def mri : SS4AIi8<opc, MRMDestMem, (outs),
- (ins i64mem:$dst, VR128:$src1, u8imm:$src2),
+ (ins x86memop:$dst, VR128:$src1, u8imm:$src2),
!strconcat(OpcodeStr,
"\t{$src2, $src1, $dst|$dst, $src1, $src2}"),
[(store (extractelt (v2i64 VR128:$src1), imm:$src2),
@@ -5388,20 +5401,23 @@ multiclass SS41I_extract64<bits<8> opc, string OpcodeStr> {
let Predicates = [HasAVX, NoDQI] in
defm VPEXTRQ : SS41I_extract64<0x16, "vpextrq">, VEX, REX_W;
-defm PEXTRQ : SS41I_extract64<0x16, "pextrq">, REX_W;
+defm PEXTRQ : SS41I_extract64<0x16, "pextrq", gr64_norex2, i64mem_norex2>,
+ REX_W;
/// SS41I_extractf32 - SSE 4.1 extract 32 bits fp value to int reg or memory
/// destination
-multiclass SS41I_extractf32<bits<8> opc, string OpcodeStr> {
- def rri : SS4AIi8<opc, MRMDestReg, (outs GR32orGR64:$dst),
+multiclass SS41I_extractf32<bits<8> opc, string OpcodeStr,
+ RegisterOperand DstRC = GR32orGR64,
+ X86MemOperand x86memop = f32mem> {
+ def rri : SS4AIi8<opc, MRMDestReg, (outs DstRC:$dst),
(ins VR128:$src1, u8imm:$src2),
!strconcat(OpcodeStr,
"\t{$src2, $src1, $dst|$dst, $src1, $src2}"),
- [(set GR32orGR64:$dst,
+ [(set DstRC:$dst,
(extractelt (bc_v4i32 (v4f32 VR128:$src1)), imm:$src2))]>,
Sched<[WriteVecExtract]>;
def mri : SS4AIi8<opc, MRMDestMem, (outs),
- (ins f32mem:$dst, VR128:$src1, u8imm:$src2),
+ (ins x86memop:$dst, VR128:$src1, u8imm:$src2),
!strconcat(OpcodeStr,
"\t{$src2, $src1, $dst|$dst, $src1, $src2}"),
[(store (extractelt (bc_v4i32 (v4f32 VR128:$src1)), imm:$src2),
@@ -5411,25 +5427,28 @@ multiclass SS41I_extractf32<bits<8> opc, string OpcodeStr> {
let ExeDomain = SSEPackedSingle in {
let Predicates = [UseAVX] in
defm VEXTRACTPS : SS41I_extractf32<0x17, "vextractps">, VEX, WIG;
- defm EXTRACTPS : SS41I_extractf32<0x17, "extractps">;
+ defm EXTRACTPS : SS41I_extractf32<0x17, "extractps", GR32orGR64_norex2,
+ f32mem_norex2>;
}
//===----------------------------------------------------------------------===//
// SSE4.1 - Insert Instructions
//===----------------------------------------------------------------------===//
-multiclass SS41I_insert8<bits<8> opc, string asm, bit Is2Addr = 1> {
+multiclass SS41I_insert8<bits<8> opc, string asm, bit Is2Addr = 1,
+ RegisterOperand SrcRC = GR32orGR64,
+ X86MemOperand x86memop = i8mem> {
def rri : SS4AIi8<opc, MRMSrcReg, (outs VR128:$dst),
- (ins VR128:$src1, GR32orGR64:$src2, u8imm:$src3),
+ (ins VR128:$src1, SrcRC:$src2, u8imm:$src3),
!if(Is2Addr,
!strconcat(asm, "\t{$src3, $src2, $dst|$dst, $src2, $src3}"),
!strconcat(asm,
"\t{$src3, $src2, $src1, $dst|$dst, $src1, $src2, $src3}")),
[(set VR128:$dst,
- (X86pinsrb VR128:$src1, GR32orGR64:$src2, timm:$src3))]>,
+ (X86pinsrb VR128:$src1, SrcRC:$src2, timm:$src3))]>,
Sched<[WriteVecInsert, ReadDefault, ReadInt2Fpu]>;
def rmi : SS4AIi8<opc, MRMSrcMem, (outs VR128:$dst),
- (ins VR128:$src1, i8mem:$src2, u8imm:$src3),
+ (ins VR128:$src1, x86memop:$src2, u8imm:$src3),
!if(Is2Addr,
!strconcat(asm, "\t{$src3, $src2, $dst|$dst, $src2, $src3}"),
!strconcat(asm,
@@ -5447,20 +5466,23 @@ let Predicates = [HasAVX, NoBWI] in {
}
let Constraints = "$src1 = $dst" in
- defm PINSRB : SS41I_insert8<0x20, "pinsrb">;
+ defm PINSRB : SS41I_insert8<0x20, "pinsrb", 1, GR32orGR64_norex2,
+ i8mem_norex2>;
-multiclass SS41I_insert32<bits<8> opc, string asm, bit Is2Addr = 1> {
+multiclass SS41I_insert32<bits<8> opc, string asm, bit Is2Addr = 1,
+ DAGOperand SrcRC = GR32,
+ X86MemOperand x86memop = i32mem> {
def rri : SS4AIi8<opc, MRMSrcReg, (outs VR128:$dst),
- (ins VR128:$src1, GR32:$src2, u8imm:$src3),
+ (ins VR128:$src1, SrcRC:$src2, u8imm:$src3),
!if(Is2Addr,
!strconcat(asm, "\t{$src3, $src2, $dst|$dst, $src2, $src3}"),
!strconcat(asm,
"\t{$src3, $src2, $src1, $dst|$dst, $src1, $src2, $src3}")),
[(set VR128:$dst,
- (v4i32 (insertelt VR128:$src1, GR32:$src2, imm:$src3)))]>,
+ (v4i32 (insertelt VR128:$src1, SrcRC:$src2, imm:$src3)))]>,
Sched<[WriteVecInsert, ReadDefault, ReadInt2Fpu]>;
def rmi : SS4AIi8<opc, MRMSrcMem, (outs VR128:$dst),
- (ins VR128:$src1, i32mem:$src2, u8imm:$src3),
+ (ins VR128:$src1, x86memop:$src2, u8imm:$src3),
!if(Is2Addr,
!strconcat(asm, "\t{$src3, $src2, $dst|$dst, $src2, $src3}"),
!strconcat(asm,
@@ -5473,20 +5495,22 @@ multiclass SS41I_insert32<bits<8> opc, string asm, bit Is2Addr = 1> {
let Predicates = [HasAVX, NoDQI] in
defm VPINSRD : SS41I_insert32<0x22, "vpinsrd", 0>, VEX, VVVV;
let Constraints = "$src1 = $dst" in
- defm PINSRD : SS41I_insert32<0x22, "pinsrd">;
+ defm PINSRD : SS41I_insert32<0x22, "pinsrd", 1, gr32_norex2, i32mem_norex2>;
-multiclass SS41I_insert64<bits<8> opc, string asm, bit Is2Addr = 1> {
+multiclass SS41I_insert64<bits<8> opc, string asm, bit Is2Addr = 1,
+ DAGOperand SrcRC = GR64,
+ X86MemOperand x86memop = i64mem> {
def rri : SS4AIi8<opc, MRMSrcReg, (outs VR128:$dst),
- (ins VR128:$src1, GR64:$src2, u8imm:$src3),
+ (ins VR128:$src1, SrcRC:$src2, u8imm:$src3),
!if(Is2Addr,
!strconcat(asm, "\t{$src3, $src2, $dst|$dst, $src2, $src3}"),
!strconcat(asm,
"\t{$src3, $src2, $src1, $dst|$dst, $src1, $src2, $src3}")),
[(set VR128:$dst,
- (v2i64 (insertelt VR128:$src1, GR64:$src2, imm:$src3)))]>,
+ (v2i64 (insertelt VR128:$src1, SrcRC:$src2, imm:$src3)))]>,
Sched<[WriteVecInsert, ReadDefault, ReadInt2Fpu]>;
def rmi : SS4AIi8<opc, MRMSrcMem, (outs VR128:$dst),
- (ins VR128:$src1, i64mem:$src2, u8imm:$src3),
+ (ins VR128:$src1, x86memop:$src2, u8imm:$src3),
!if(Is2Addr,
!strconcat(asm, "\t{$src3, $src2, $dst|$dst, $src2, $src3}"),
!strconcat(asm,
@@ -5499,13 +5523,15 @@ multiclass SS41I_insert64<bits<8> opc, string asm, bit Is2Addr = 1> {
let Predicates = [HasAVX, NoDQI] in
defm VPINSRQ : SS41I_insert64<0x22, "vpinsrq", 0>, VEX, VVVV, REX_W;
let Constraints = "$src1 = $dst" in
- defm PINSRQ : SS41I_insert64<0x22, "pinsrq">, REX_W;
+ defm PINSRQ : SS41I_insert64<0x22, "pinsrq", 1, gr64_norex2, i64mem_norex2>,
+ REX_W;
// insertps has a few different modes, there's the first two here below which
// are optimized inserts that won't zero arbitrary elements in the destination
// vector. The next one matches the intrinsic and could zero arbitrary elements
// in the target vector.
-multiclass SS41I_insertf32<bits<8> opc, string asm, bit Is2Addr = 1> {
+multiclass SS41I_insertf32<bits<8> opc, string asm, bit Is2Addr = 1,
+ X86MemOperand x86memop = f32mem> {
let isCommutable = 1 in
def rri : SS4AIi8<opc, MRMSrcReg, (outs VR128:$dst),
(ins VR128:$src1, VR128:$src2, u8imm:$src3),
@@ -5517,7 +5543,7 @@ multiclass SS41I_insertf32<bits<8> opc, string asm, bit Is2Addr = 1> {
(X86insertps VR128:$src1, VR128:$src2, timm:$src3))]>,
Sched<[SchedWriteFShuffle.XMM]>;
def rmi : SS4AIi8<opc, MRMSrcMem, (outs VR128:$dst),
- (ins VR128:$src1, f32mem:$src2, u8imm:$src3),
+ (ins VR128:$src1, x86memop:$src2, u8imm:$src3),
!if(Is2Addr,
!strconcat(asm, "\t{$src3, $src2, $dst|$dst, $src2, $src3}"),
!strconcat(asm,
@@ -5534,7 +5560,7 @@ let ExeDomain = SSEPackedSingle in {
defm VINSERTPS : SS41I_insertf32<0x21, "vinsertps", 0>,
VEX, VVVV, WIG;
let Constraints = "$src1 = $dst" in
- defm INSERTPS : SS41I_insertf32<0x21, "insertps", 1>;
+ defm INSERTPS : SS41I_insertf32<0x21, "insertps", 1, f32mem_norex2>;
}
//===----------------------------------------------------------------------===//
@@ -5611,7 +5637,7 @@ let ExeDomain = SSEPackedSingle, hasSideEffects = 0, isCodeGenOnly = 1 in {
let mayLoad = 1 in
def SSmi : SS4AIi8<opcss, MRMSrcMem,
- (outs FR32:$dst), (ins f32mem:$src1, i32u8imm:$src2),
+ (outs FR32:$dst), (ins f32mem_norex2:$src1, i32u8imm:$src2),
!strconcat(OpcodeStr,
"ss\t{$src2, $src1, $dst|$dst, $src1, $src2}"),
[]>, Sched<[sched.Folded, sched.ReadAfterFold]>;
@@ -5626,7 +5652,7 @@ let ExeDomain = SSEPackedDouble, hasSideEffects = 0, isCodeGenOnly = 1 in {
let mayLoad = 1 in
def SDmi : SS4AIi8<opcsd, MRMSrcMem,
- (outs FR64:$dst), (ins f64mem:$src1, i32u8imm:$src2),
+ (outs FR64:$dst), (ins f64mem_norex2:$src1, i32u8imm:$src2),
!strconcat(OpcodeStr,
"sd\t{$src2, $src1, $dst|$dst, $src1, $src2}"),
[]>, Sched<[sched.Folded, sched.ReadAfterFold]>;
@@ -5637,7 +5663,9 @@ let ExeDomain = SSEPackedDouble, hasSideEffects = 0, isCodeGenOnly = 1 in {
multiclass sse41_fp_unop_s_int<bits<8> opcss, bits<8> opcsd,
string OpcodeStr, X86FoldableSchedWrite sched,
ValueType VT32, ValueType VT64,
- SDNode OpNode, bit Is2Addr = 1> {
+ SDNode OpNode, bit Is2Addr = 1,
+ X86MemOperand ssmemop = ssmem,
+ X86MemOperand sdmemop = sdmem> {
let Uses = [MXCSR], mayRaiseFPException = 1 in {
let ExeDomain = SSEPackedSingle in {
def SSri_Int : SS4AIi8<opcss, MRMSrcReg,
@@ -5651,7 +5679,7 @@ let ExeDomain = SSEPackedSingle in {
Sched<[sched]>;
def SSmi_Int : SS4AIi8<opcss, MRMSrcMem,
- (outs VR128:$dst), (ins VR128:$src1, ssmem:$src2, i32u8imm:$src3),
+ (outs VR128:$dst), (ins VR128:$src1, ssmemop:$src2, i32u8imm:$src3),
!if(Is2Addr,
!strconcat(OpcodeStr,
"ss\t{$src3, $src2, $dst|$dst, $src2, $src3}"),
@@ -5674,7 +5702,7 @@ let ExeDomain = SSEPackedDouble in {
Sched<[sched]>;
def SDmi_Int : SS4AIi8<opcsd, MRMSrcMem,
- (outs VR128:$dst), (ins VR128:$src1, sdmem:$src2, i32u8imm:$src3),
+ (outs VR128:$dst), (ins VR128:$src1, sdmemop:$src2, i32u8imm:$src3),
!if(Is2Addr,
!strconcat(OpcodeStr,
"sd\t{$src3, $src2, $dst|$dst, $src2, $src3}"),
@@ -5731,17 +5759,18 @@ let Predicates = [UseAVX, OptForSize] in {
}
let ExeDomain = SSEPackedSingle in
-defm ROUNDPS : sse41_fp_unop_p<0x08, "roundps", f128mem, VR128, v4f32,
+defm ROUNDPS : sse41_fp_unop_p<0x08, "roundps", f128mem_norex2, VR128, v4f32,
memopv4f32, X86any_VRndScale, SchedWriteFRnd.XMM>;
let ExeDomain = SSEPackedDouble in
-defm ROUNDPD : sse41_fp_unop_p<0x09, "roundpd", f128mem, VR128, v2f64,
+defm ROUNDPD : sse41_fp_unop_p<0x09, "roundpd", f128mem_norex2, VR128, v2f64,
memopv2f64, X86any_VRndScale, SchedWriteFRnd.XMM>;
defm ROUND : sse41_fp_unop_s<0x0A, 0x0B, "round", SchedWriteFRnd.Scl>;
let Constraints = "$src1 = $dst" in
defm ROUND : sse41_fp_unop_s_int<0x0A, 0x0B, "round", SchedWriteFRnd.Scl,
- v4f32, v2f64, X86RndScales>;
+ v4f32, v2f64, X86RndScales, 1, ssmem_norex2,
+ sdmem_norex2>;
let Predicates = [UseSSE41] in {
def : Pat<(X86any_VRndScale FR32:$src1, timm:$src2),
@@ -5822,7 +5851,7 @@ def PTESTrr : SS48I<0x17, MRMSrcReg, (outs), (ins VR128:$src1, VR128:$src2),
"ptest\t{$src2, $src1|$src1, $src2}",
[(set EFLAGS, (X86ptest VR128:$src1, (v2i64 VR128:$src2)))]>,
Sched<[SchedWriteVecTest.XMM]>;
-def PTESTrm : SS48I<0x17, MRMSrcMem, (outs), (ins VR128:$src1, f128mem:$src2),
+def PTESTrm : SS48I<0x17, MRMSrcMem, (outs), (ins VR128:$src1, f128mem_norex2:$src2),
"ptest\t{$src2, $src1|$src1, $src2}",
[(set EFLAGS, (X86ptest VR128:$src1, (memopv2i64 addr:$src2)))]>,
Sched<[SchedWriteVecTest.XMM.Folded, SchedWriteVecTest.XMM.ReadAfterFold]>;
@@ -5908,14 +5937,15 @@ defm POPCNT64 : Lzcnt<0x88, "popcnt", null_frag, Xi64, WritePOPCNT, WritePOPCNT.
// SS41I_unop_rm_int_v16 - SSE 4.1 unary operator whose type is v8i16.
multiclass SS41I_unop_rm_int_v16<bits<8> opc, string OpcodeStr,
SDNode OpNode, PatFrag ld_frag,
- X86FoldableSchedWrite Sched> {
+ X86FoldableSchedWrite Sched,
+ X86MemOperand x86memop = i128mem> {
def rr : SS48I<opc, MRMSrcReg, (outs VR128:$dst),
(ins VR128:$src),
!strconcat(OpcodeStr, "\t{$src, $dst|$dst, $src}"),
[(set VR128:$dst, (v8i16 (OpNode (v8i16 VR128:$src))))]>,
Sched<[Sched]>;
def rm : SS48I<opc, MRMSrcMem, (outs VR128:$dst),
- (ins i128mem:$src),
+ (ins x86memop:$src),
!strconcat(OpcodeStr, "\t{$src, $dst|$dst, $src}"),
[(set VR128:$dst,
(v8i16 (OpNode (ld_frag addr:$src))))]>,
@@ -5930,7 +5960,7 @@ defm VPHMINPOSUW : SS41I_unop_rm_int_v16<0x41, "vphminposuw",
WritePHMINPOS>, VEX, WIG;
defm PHMINPOSUW : SS41I_unop_rm_int_v16<0x41, "phminposuw",
X86phminpos, memop,
- WritePHMINPOS>;
+ WritePHMINPOS, i128mem_norex2>;
/// SS48I_binop_rm - Simple SSE41 binary operator.
multiclass SS48I_binop_rm<bits<8> opc, string OpcodeStr, SDNode OpNode,
@@ -6021,23 +6051,23 @@ let Predicates = [HasAVX2, NoVLX_Or_NoBWI] in {
let Constraints = "$src1 = $dst" in {
defm PMINSB : SS48I_binop_rm<0x38, "pminsb", smin, v16i8, VR128,
- memop, i128mem, SchedWriteVecALU.XMM, 1>;
+ memop, i128mem_norex2, SchedWriteVecALU.XMM, 1>;
defm PMINSD : SS48I_binop_rm<0x39, "pminsd", smin, v4i32, VR128,
- memop, i128mem, SchedWriteVecALU.XMM, 1>;
+ memop, i128mem_norex2, SchedWriteVecALU.XMM, 1>;
defm PMINUD : SS48I_binop_rm<0x3B, "pminud", umin, v4i32, VR128,
- memop, i128mem, SchedWriteVecALU.XMM, 1>;
+ memop, i128mem_norex2, SchedWriteVecALU.XMM, 1>;
defm PMINUW : SS48I_binop_rm<0x3A, "pminuw", umin, v8i16, VR128,
- memop, i128mem, SchedWriteVecALU.XMM, 1>;
+ memop, i128mem_norex2, SchedWriteVecALU.XMM, 1>;
defm PMAXSB : SS48I_binop_rm<0x3C, "pmaxsb", smax, v16i8, VR128,
- memop, i128mem, SchedWriteVecALU.XMM, 1>;
+ memop, i128mem_norex2, SchedWriteVecALU.XMM, 1>;
defm PMAXSD : SS48I_binop_rm<0x3D, "pmaxsd", smax, v4i32, VR128,
- memop, i128mem, SchedWriteVecALU.XMM, 1>;
+ memop, i128mem_norex2, SchedWriteVecALU.XMM, 1>;
defm PMAXUD : SS48I_binop_rm<0x3F, "pmaxud", umax, v4i32, VR128,
- memop, i128mem, SchedWriteVecALU.XMM, 1>;
+ memop, i128mem_norex2, SchedWriteVecALU.XMM, 1>;
defm PMAXUW : SS48I_binop_rm<0x3E, "pmaxuw", umax, v8i16, VR128,
- memop, i128mem, SchedWriteVecALU.XMM, 1>;
+ memop, i128mem_norex2, SchedWriteVecALU.XMM, 1>;
defm PMULDQ : SS48I_binop_rm<0x28, "pmuldq", X86pmuldq, v2i64, VR128,
- memop, i128mem, SchedWriteVecIMul.XMM, 1>;
+ memop, i128mem_norex2, SchedWriteVecIMul.XMM, 1>;
}
let Predicates = [HasAVX, NoVLX] in
@@ -6060,9 +6090,9 @@ let Predicates = [HasAVX2] in
let Constraints = "$src1 = $dst" in {
defm PMULLD : SS48I_binop_rm<0x40, "pmulld", mul, v4i32, VR128,
- memop, i128mem, SchedWritePMULLD.XMM, 1>;
+ memop, i128mem_norex2, SchedWritePMULLD.XMM, 1>;
defm PCMPEQQ : SS48I_binop_rm<0x29, "pcmpeqq", X86pcmpeq, v2i64, VR128,
- memop, i128mem, SchedWriteVecALU.XMM, 1>;
+ memop, i128mem_norex2, SchedWriteVecALU.XMM, 1>;
}
/// SS41I_binop_rmi_int - SSE 4.1 binary operator with 8-bit immediate
@@ -6234,17 +6264,17 @@ let Predicates = [HasAVX2, NoAVX10_2] in {
let Constraints = "$src1 = $dst" in {
let isCommutable = 0 in {
defm MPSADBW : SS41I_binop_rmi<0x42, "mpsadbw", X86Vmpsadbw,
- v8i16, VR128, memop, i128mem, 1,
+ v8i16, VR128, memop, i128mem_norex2, 1,
SchedWriteMPSAD.XMM>;
}
let ExeDomain = SSEPackedSingle in
defm DPPS : SS41I_binop_rmi_int<0x40, "dpps", int_x86_sse41_dpps,
- VR128, memop, f128mem, 1,
+ VR128, memop, f128mem_norex2, 1,
SchedWriteDPPS.XMM>, SIMD_EXC;
let ExeDomain = SSEPackedDouble in
defm DPPD : SS41I_binop_rmi_int<0x41, "dppd", int_x86_sse41_dppd,
- VR128, memop, f128mem, 1,
+ VR128, memop, f128mem_norex2, 1,
SchedWriteDPPD.XMM>, SIMD_EXC;
}
@@ -6349,13 +6379,13 @@ def : Pat<(X86Blendi (loadv4i32 addr:$src2), VR128:$src1, timm:$src3),
}
defm BLENDPS : SS41I_blend_rmi<0x0C, "blendps", X86Blendi, v4f32,
- VR128, memop, f128mem, 1, SSEPackedSingle,
+ VR128, memop, f128mem_norex2, 1, SSEPackedSingle,
SchedWriteFBlend.XMM, BlendCommuteImm4>;
defm BLENDPD : SS41I_blend_rmi<0x0D, "blendpd", X86Blendi, v2f64,
- VR128, memop, f128mem, 1, SSEPackedDouble,
+ VR128, memop, f128mem_norex2, 1, SSEPackedDouble,
SchedWriteFBlend.XMM, BlendCommuteImm2>;
defm PBLENDW : SS41I_blend_rmi<0x0E, "pblendw", X86Blendi, v8i16,
- VR128, memop, i128mem, 1, SSEPackedInt,
+ VR128, memop, i128mem_norex2, 1, SSEPackedInt,
SchedWriteBlend.XMM, BlendCommuteImm8>;
let Predicates = [UseSSE41] in {
@@ -6553,12 +6583,12 @@ let Uses = [XMM0], Constraints = "$src1 = $dst" in {
}
let ExeDomain = SSEPackedDouble in
-defm BLENDVPD : SS41I_ternary<0x15, "blendvpd", v2f64, memopv2f64, f128mem,
+defm BLENDVPD : SS41I_ternary<0x15, "blendvpd", v2f64, memopv2f64, f128mem_norex2,
X86Blendv, SchedWriteFVarBlend.XMM>;
let ExeDomain = SSEPackedSingle in
-defm BLENDVPS : SS41I_ternary<0x14, "blendvps", v4f32, memopv4f32, f128mem,
+defm BLENDVPS : SS41I_ternary<0x14, "blendvps", v4f32, memopv4f32, f128mem_norex2,
X86Blendv, SchedWriteFVarBlend.XMM>;
-defm PBLENDVB : SS41I_ternary<0x10, "pblendvb", v16i8, memopv16i8, i128mem,
+defm PBLENDVB : SS41I_ternary<0x10, "pblendvb", v16i8, memopv16i8, i128mem_norex2,
X86Blendv, SchedWriteVarBlend.XMM>;
// Aliases with the implicit xmm0 argument
@@ -6594,7 +6624,7 @@ let Predicates = [HasAVX2, NoVLX] in
def VMOVNTDQAYrm : SS48I<0x2A, MRMSrcMem, (outs VR256:$dst), (ins i256mem:$src),
"vmovntdqa\t{$src, $dst|$dst, $src}", []>,
Sched<[SchedWriteVecMoveLSNT.YMM.RM]>, VEX, VEX_L, WIG;
-def MOVNTDQArm : SS48I<0x2A, MRMSrcMem, (outs VR128:$dst), (ins i128mem:$src),
+def MOVNTDQArm : SS48I<0x2A, MRMSrcMem, (outs VR128:$dst), (ins i128mem_norex2:$src),
"movntdqa\t{$src, $dst|$dst, $src}", []>,
Sched<[SchedWriteVecMoveLSNT.XMM.RM]>;
@@ -6689,20 +6719,20 @@ let Predicates = [HasAVX2] in
let Constraints = "$src1 = $dst" in
defm PCMPGTQ : SS42I_binop_rm<0x37, "pcmpgtq", X86pcmpgt, v2i64, VR128,
- memop, i128mem, SchedWriteVecALU.XMM>;
+ memop, i128mem_norex2, SchedWriteVecALU.XMM>;
//===----------------------------------------------------------------------===//
// SSE4.2 - String/text Processing Instructions
//===----------------------------------------------------------------------===//
-multiclass pcmpistrm_SS42AI<string asm> {
+multiclass pcmpistrm_SS42AI<string asm, X86MemOperand x86memop = i128mem> {
def rri : SS42AI<0x62, MRMSrcReg, (outs),
(ins VR128:$src1, VR128:$src2, u8imm:$src3),
!strconcat(asm, "\t{$src3, $src2, $src1|$src1, $src2, $src3}"),
[]>, Sched<[WritePCmpIStrM]>;
let mayLoad = 1 in
def rmi :SS42AI<0x62, MRMSrcMem, (outs),
- (ins VR128:$src1, i128mem:$src2, u8imm:$src3),
+ (ins VR128:$src1, x86memop:$src2, u8imm:$src3),
!strconcat(asm, "\t{$src3, $src2, $src1|$src1, $src2, $src3}"),
[]>, Sched<[WritePCmpIStrM.Folded, WritePCmpIStrM.ReadAfterFold]>;
}
@@ -6710,17 +6740,17 @@ multiclass pcmpistrm_SS42AI<string asm> {
let Defs = [XMM0, EFLAGS], hasSideEffects = 0 in {
let Predicates = [HasAVX] in
defm VPCMPISTRM : pcmpistrm_SS42AI<"vpcmpistrm">, VEX, WIG;
- defm PCMPISTRM : pcmpistrm_SS42AI<"pcmpistrm"> ;
+ defm PCMPISTRM : pcmpistrm_SS42AI<"pcmpistrm", i128mem_norex2> ;
}
-multiclass SS42AI_pcmpestrm<string asm> {
+multiclass SS42AI_pcmpestrm<string asm, X86MemOperand x86memop = i128mem> {
def rri : SS42AI<0x60, MRMSrcReg, (outs),
(ins VR128:$src1, VR128:$src3, u8imm:$src5),
!strconcat(asm, "\t{$src5, $src3, $src1|$src1, $src3, $src5}"),
[]>, Sched<[WritePCmpEStrM]>;
let mayLoad = 1 in
def rmi : SS42AI<0x60, MRMSrcMem, (outs),
- (ins VR128:$src1, i128mem:$src3, u8imm:$src5),
+ (ins VR128:$src1, x86memop:$src3, u8imm:$src5),
!strconcat(asm, "\t{$src5, $src3, $src1|$src1, $src3, $src5}"),
[]>, Sched<[WritePCmpEStrM.Folded, WritePCmpEStrM.ReadAfterFold]>;
}
@@ -6728,14 +6758,14 @@ multiclass SS42AI_pcmpestrm<string asm> {
let Defs = [XMM0, EFLAGS], Uses = [EAX, EDX], hasSideEffects = 0 in {
let Predicates = [HasAVX] in
defm VPCMPESTRM : SS42AI_pcmpestrm<"vpcmpestrm">, VEX;
- defm PCMPESTRM : SS42AI_pcmpestrm<"pcmpestrm">;
+ defm PCMPESTRM : SS42AI_pcmpestrm<"pcmpestrm", i128mem_norex2>;
}
let Defs = [XMM0, EFLAGS], Uses = [RAX, RDX], hasSideEffects = 0 in {
let Predicates = [HasAVX, In64BitMode] in
defm VPCMPESTRMQ : SS42AI_pcmpestrm<"vpcmpestrmq">, VEX, REX_W;
let Predicates = [UseSSE42, In64BitMode] in
- defm PCMPESTRMQ : SS42AI_pcmpestrm<"pcmpestrmq">, REX_W;
+ defm PCMPESTRMQ : SS42AI_pcmpestrm<"pcmpestrmq", i128mem_norex2>, REX_W;
}
def : InstAlias<"vpcmpestrm{l}\t{$src5, $src3, $src1|$src1, $src3, $src5}",
@@ -6745,16 +6775,16 @@ def : InstAlias<"vpcmpestrm{l}\t{$src5, $src3, $src1|$src1, $src3, $src5}",
def : InstAlias<"pcmpestrm{l}\t{$src5, $src3, $src1|$src1, $src3, $src5}",
(PCMPESTRMrri VR128:$src1, VR128:$src3, u8imm:$src5), 0, "att">;
def : InstAlias<"pcmpestrm{l}\t{$src5, $src3, $src1|$src1, $src3, $src5}",
- (PCMPESTRMrmi VR128:$src1, i128mem:$src3, u8imm:$src5), 0, "att">;
+ (PCMPESTRMrmi VR128:$src1, i128mem_norex2:$src3, u8imm:$src5), 0, "att">;
-multiclass SS42AI_pcmpistri<string asm> {
+multiclass SS42AI_pcmpistri<string asm, X86MemOperand x86memop = i128mem> {
def rri : SS42AI<0x63, MRMSrcReg, (outs),
(ins VR128:$src1, VR128:$src2, u8imm:$src3),
!strconcat(asm, "\t{$src3, $src2, $src1|$src1, $src2, $src3}"),
[]>, Sched<[WritePCmpIStrI]>;
let mayLoad = 1 in
def rmi : SS42AI<0x63, MRMSrcMem, (outs),
- (ins VR128:$src1, i128mem:$src2, u8imm:$src3),
+ (ins VR128:$src1, x86memop:$src2, u8imm:$src3),
!strconcat(asm, "\t{$src3, $src2, $src1|$src1, $src2, $src3}"),
[]>, Sched<[WritePCmpIStrI.Folded, WritePCmpIStrI.ReadAfterFold]>;
}
@@ -6762,17 +6792,17 @@ multiclass SS42AI_pcmpistri<string asm> {
let Defs = [ECX, EFLAGS], hasSideEffects = 0 in {
let Predicates = [HasAVX] in
defm VPCMPISTRI : SS42AI_pcmpistri<"vpcmpistri">, VEX, WIG;
- defm PCMPISTRI : SS42AI_pcmpistri<"pcmpistri">;
+ defm PCMPISTRI : SS42AI_pcmpistri<"pcmpistri", i128mem_norex2>;
}
-multiclass SS42AI_pcmpestri<string asm> {
+multiclass SS42AI_pcmpestri<string asm, X86MemOperand x86memop = i128mem> {
def rri : SS42AI<0x61, MRMSrcReg, (outs),
(ins VR128:$src1, VR128:$src3, u8imm:$src5),
!strconcat(asm, "\t{$src5, $src3, $src1|$src1, $src3, $src5}"),
[]>, Sched<[WritePCmpEStrI]>;
let mayLoad = 1 in
def rmi : SS42AI<0x61, MRMSrcMem, (outs),
- (ins VR128:$src1, i128mem:$src3, u8imm:$src5),
+ (ins VR128:$src1, x86memop:$src3, u8imm:$src5),
!strconcat(asm, "\t{$src5, $src3, $src1|$src1, $src3, $src5}"),
[]>, Sched<[WritePCmpEStrI.Folded, WritePCmpEStrI.ReadAfterFold]>;
}
@@ -6780,14 +6810,14 @@ multiclass SS42AI_pcmpestri<string asm> {
let Defs = [ECX, EFLAGS], Uses = [EAX, EDX], hasSideEffects = 0 in {
let Predicates = [HasAVX] in
defm VPCMPESTRI : SS42AI_pcmpestri<"vpcmpestri">, VEX;
- defm PCMPESTRI : SS42AI_pcmpestri<"pcmpestri">;
+ defm PCMPESTRI : SS42AI_pcmpestri<"pcmpestri", i128mem_norex2>;
}
let Defs = [ECX, EFLAGS], Uses = [RAX, RDX], hasSideEffects = 0 in {
let Predicates = [HasAVX, In64BitMode] in
defm VPCMPESTRIQ : SS42AI_pcmpestri<"vpcmpestriq">, VEX, REX_W;
let Predicates = [UseSSE42, In64BitMode] in
- defm PCMPESTRIQ : SS42AI_pcmpestri<"pcmpestriq">, REX_W;
+ defm PCMPESTRIQ : SS42AI_pcmpestri<"pcmpestriq", i128mem_norex2>, REX_W;
}
def : InstAlias<"vpcmpestri{l}\t{$src5, $src3, $src1|$src1, $src3, $src5}",
@@ -6797,7 +6827,7 @@ def : InstAlias<"vpcmpestri{l}\t{$src5, $src3, $src1|$src1, $src3, $src5}",
def : InstAlias<"pcmpestri{l}\t{$src5, $src3, $src1|$src1, $src3, $src5}",
(PCMPESTRIrri VR128:$src1, VR128:$src3, u8imm:$src5), 0, "att">;
def : InstAlias<"pcmpestri{l}\t{$src5, $src3, $src1|$src1, $src3, $src5}",
- (PCMPESTRIrmi VR128:$src1, i128mem:$src3, u8imm:$src5), 0, "att">;
+ (PCMPESTRIrmi VR128:$src1, i128mem_norex2:$src3, u8imm:$src5), 0, "att">;
//===----------------------------------------------------------------------===//
// SSE4.2 - CRC Instructions
@@ -6868,7 +6898,7 @@ multiclass SHAI_binop<bits<8> Opc, string OpcodeStr, Intrinsic IntId,
T8, Sched<[sched]>;
def rm : I<Opc, MRMSrcMem, (outs VR128:$dst),
- (ins VR128:$src1, i128mem:$src2),
+ (ins VR128:$src1, i128mem_norex2:$src2),
!if(UsesXMM0,
!strconcat(OpcodeStr, "\t{%xmm0, $src2, $dst|$dst, $src2, xmm0}"),
!strconcat(OpcodeStr, "\t{$src2, $dst|$dst, $src2}")),
@@ -6889,7 +6919,7 @@ let Constraints = "$src1 = $dst", Predicates = [HasSHA] in {
(i8 timm:$src3)))]>, TA,
Sched<[SchedWriteVecIMul.XMM]>;
def SHA1RNDS4rmi : Ii8<0xCC, MRMSrcMem, (outs VR128:$dst),
- (ins VR128:$src1, i128mem:$src2, u8imm:$src3),
+ (ins VR128:$src1, i128mem_norex2:$src2, u8imm:$src3),
"sha1rnds4\t{$src3, $src2, $dst|$dst, $src2, $src3}",
[(set VR128:$dst,
(int_x86_sha1rnds4 VR128:$src1,
@@ -6967,13 +6997,15 @@ let Predicates = [NoVLX, HasVAES] in {
let Constraints = "$src1 = $dst" in {
defm AESENC : AESI_binop_rm_int<0xDC, "aesenc",
- int_x86_aesni_aesenc, memop, 1>;
+ int_x86_aesni_aesenc, memop, 1, VR128, i128mem_norex2>;
defm AESENCLAST : AESI_binop_rm_int<0xDD, "aesenclast",
- int_x86_aesni_aesenclast, memop, 1>;
+ int_x86_aesni_aesenclast, memop, 1, VR128,
+ i128mem_norex2>;
defm AESDEC : AESI_binop_rm_int<0xDE, "aesdec",
- int_x86_aesni_aesdec, memop, 1>;
+ int_x86_aesni_aesdec, memop, 1, VR128, i128mem_norex2>;
defm AESDECLAST : AESI_binop_rm_int<0xDF, "aesdeclast",
- int_x86_aesni_aesdeclast, memop, 1>;
+ int_x86_aesni_aesdeclast, memop, 1, VR128,
+ i128mem_norex2>;
}
// Perform the AES InvMixColumn Transformation
@@ -6996,7 +7028,7 @@ def AESIMCrr : AES8I<0xDB, MRMSrcReg, (outs VR128:$dst),
[(set VR128:$dst,
(int_x86_aesni_aesimc VR128:$src1))]>, Sched<[WriteAESIMC]>;
def AESIMCrm : AES8I<0xDB, MRMSrcMem, (outs VR128:$dst),
- (ins i128mem:$src1),
+ (ins i128mem_norex2:$src1),
"aesimc\t{$src1, $dst|$dst, $src1}",
[(set VR128:$dst, (int_x86_aesni_aesimc (memop addr:$src1)))]>,
Sched<[WriteAESIMC.Folded]>;
@@ -7023,7 +7055,7 @@ def AESKEYGENASSISTrri : AESAI<0xDF, MRMSrcReg, (outs VR128:$dst),
(int_x86_aesni_aeskeygenassist VR128:$src1, timm:$src2))]>,
Sched<[WriteAESKeyGen]>;
def AESKEYGENASSISTrmi : AESAI<0xDF, MRMSrcMem, (outs VR128:$dst),
- (ins i128mem:$src1, u8imm:$src2),
+ (ins i128mem_norex2:$src1, u8imm:$src2),
"aeskeygenassist\t{$src2, $src1, $dst|$dst, $src1, $src2}",
[(set VR128:$dst,
(int_x86_aesni_aeskeygenassist (memop addr:$src1), timm:$src2))]>,
@@ -7051,7 +7083,7 @@ let Predicates = [NoAVX, HasPCLMUL] in {
Sched<[WriteCLMul]>;
def PCLMULQDQrmi : PCLMULIi8<0x44, MRMSrcMem, (outs VR128:$dst),
- (ins VR128:$src1, i128mem:$src2, u8imm:$src3),
+ (ins VR128:$src1, i128mem_norex2:$src2, u8imm:$src3),
"pclmulqdq\t{$src3, $src2, $dst|$dst, $src2, $src3}",
[(set VR128:$dst,
(v2i64 (X86pclmulqdq VR128:$src1, (memop addr:$src2),
@@ -7072,7 +7104,7 @@ foreach LO = ["hq","lq"] in {
(PCLMULQDQrri VR128:$dst, VR128:$src,
!add(!shl(!eq(LO,"hq"),4),!eq(HI,"hq"))), 0>;
def : InstAlias<"pclmul" # HI # LO # "dq\t{$src, $dst|$dst, $src}",
- (PCLMULQDQrmi VR128:$dst, i128mem:$src,
+ (PCLMULQDQrmi VR128:$dst, i128mem_norex2:$src,
!add(!shl(!eq(LO,"hq"),4),!eq(HI,"hq"))), 0>;
}
@@ -7426,22 +7458,22 @@ multiclass avx_movmask_rm<bits<8> opc_rm, bits<8> opc_mr, string OpcodeStr,
X86SchedWriteMaskMove schedX,
X86SchedWriteMaskMove schedY> {
def rm : AVX8I<opc_rm, MRMSrcMem, (outs VR128:$dst),
- (ins VR128:$src1, f128mem:$src2),
+ (ins VR128:$src1, f128mem_norex2:$src2),
!strconcat(OpcodeStr, "\t{$src2, $src1, $dst|$dst, $src1, $src2}"),
[(set VR128:$dst, (IntLd addr:$src2, VR128:$src1))]>,
VEX, VVVV, Sched<[schedX.RM]>;
def Yrm : AVX8I<opc_rm, MRMSrcMem, (outs VR256:$dst),
- (ins VR256:$src1, f256mem:$src2),
+ (ins VR256:$src1, f256mem_norex2:$src2),
!strconcat(OpcodeStr, "\t{$src2, $src1, $dst|$dst, $src1, $src2}"),
[(set VR256:$dst, (IntLd256 addr:$src2, VR256:$src1))]>,
VEX, VVVV, VEX_L, Sched<[schedY.RM]>;
def mr : AVX8I<opc_mr, MRMDestMem, (outs),
- (ins f128mem:$dst, VR128:$src1, VR128:$src2),
+ (ins f128mem_norex2:$dst, VR128:$src1, VR128:$src2),
!strconcat(OpcodeStr, "\t{$src2, $src1, $dst|$dst, $src1, $src2}"),
[(IntSt addr:$dst, VR128:$src1, VR128:$src2)]>,
VEX, VVVV, Sched<[schedX.MR]>;
def Ymr : AVX8I<opc_mr, MRMDestMem, (outs),
- (ins f256mem:$dst, VR256:$src1, VR256:$src2),
+ (ins f256mem_norex2:$dst, VR256:$src1, VR256:$src2),
!strconcat(OpcodeStr, "\t{$src2, $src1, $dst|$dst, $src1, $src2}"),
[(IntSt256 addr:$dst, VR256:$src1, VR256:$src2)]>,
VEX, VVVV, VEX_L, Sched<[schedY.MR]>;
@@ -8059,22 +8091,22 @@ multiclass avx2_pmovmask<string OpcodeStr,
X86SchedWriteMaskMove schedX,
X86SchedWriteMaskMove schedY> {
def rm : AVX28I<0x8c, MRMSrcMem, (outs VR128:$dst),
- (ins VR128:$src1, i128mem:$src2),
+ (ins VR128:$src1, i128mem_norex2:$src2),
!strconcat(OpcodeStr, "\t{$src2, $src1, $dst|$dst, $src1, $src2}"),
[(set VR128:$dst, (IntLd128 addr:$src2, VR128:$src1))]>,
VEX, VVVV, Sched<[schedX.RM]>;
def Yrm : AVX28I<0x8c, MRMSrcMem, (outs VR256:$dst),
- (ins VR256:$src1, i256mem:$src2),
+ (ins VR256:$src1, i256mem_norex2:$src2),
!strconcat(OpcodeStr, "\t{$src2, $src1, $dst|$dst, $src1, $src2}"),
[(set VR256:$dst, (IntLd256 addr:$src2, VR256:$src1))]>,
VEX, VVVV, VEX_L, Sched<[schedY.RM]>;
def mr : AVX28I<0x8e, MRMDestMem, (outs),
- (ins i128mem:$dst, VR128:$src1, VR128:$src2),
+ (ins i128mem_norex2:$dst, VR128:$src1, VR128:$src2),
!strconcat(OpcodeStr, "\t{$src2, $src1, $dst|$dst, $src1, $src2}"),
[(IntSt128 addr:$dst, VR128:$src1, VR128:$src2)]>,
VEX, VVVV, Sched<[schedX.MR]>;
def Ymr : AVX28I<0x8e, MRMDestMem, (outs),
- (ins i256mem:$dst, VR256:$src1, VR256:$src2),
+ (ins i256mem_norex2:$dst, VR256:$src1, VR256:$src2),
!strconcat(OpcodeStr, "\t{$src2, $src1, $dst|$dst, $src1, $src2}"),
[(IntSt256 addr:$dst, VR256:$src1, VR256:$src2)]>,
VEX, VVVV, VEX_L, Sched<[schedY.MR]>;
@@ -8193,26 +8225,26 @@ let Predicates = [HasAVX2] in {
= "@earlyclobber $dst, at earlyclobber $mask_wb, $src1 = $dst, $mask = $mask_wb"
in {
defm VPGATHERDQ : avx2_gather<0x90, "vpgatherdq",
- VR256, vx64mem, vx64mem>, REX_W;
+ VR256, vx64mem_norex2, vx64mem_norex2>, REX_W;
defm VPGATHERQQ : avx2_gather<0x91, "vpgatherqq",
- VR256, vx64mem, vy64mem>, REX_W;
+ VR256, vx64mem_norex2, vy64mem_norex2>, REX_W;
defm VPGATHERDD : avx2_gather<0x90, "vpgatherdd",
- VR256, vx32mem, vy32mem>;
+ VR256, vx32mem_norex2, vy32mem_norex2>;
defm VPGATHERQD : avx2_gather<0x91, "vpgatherqd",
- VR128, vx32mem, vy32mem>;
+ VR128, vx32mem_norex2, vy32mem_norex2>;
let ExeDomain = SSEPackedDouble in {
defm VGATHERDPD : avx2_gather<0x92, "vgatherdpd",
- VR256, vx64mem, vx64mem>, REX_W;
+ VR256, vx64mem_norex2, vx64mem_norex2>, REX_W;
defm VGATHERQPD : avx2_gather<0x93, "vgatherqpd",
- VR256, vx64mem, vy64mem>, REX_W;
+ VR256, vx64mem_norex2, vy64mem_norex2>, REX_W;
}
let ExeDomain = SSEPackedSingle in {
defm VGATHERDPS : avx2_gather<0x92, "vgatherdps",
- VR256, vx32mem, vy32mem>;
+ VR256, vx32mem_norex2, vy32mem_norex2>;
defm VGATHERQPS : avx2_gather<0x93, "vgatherqps",
- VR128, vx32mem, vy32mem>;
+ VR128, vx32mem_norex2, vy32mem_norex2>;
}
}
}
@@ -8265,7 +8297,7 @@ multiclass GF2P8AFFINE_common<bits<8> Op, string OpStr, SDNode OpNode> {
let Constraints = "$src1 = $dst",
Predicates = [HasGFNI, UseSSE2] in
defm NAME : GF2P8AFFINE_rmi<Op, OpStr, v16i8, OpNode,
- VR128, load, i128mem, SchedWriteVecIMul.XMM, 1>;
+ VR128, load, i128mem_norex2, SchedWriteVecIMul.XMM, 1>;
let Predicates = [HasGFNI, HasAVX, NoVLX] in {
defm V#NAME : GF2P8AFFINE_rmi<Op, "v"#OpStr, v16i8, OpNode, VR128,
load, i128mem, SchedWriteVecIMul.XMM>,
@@ -8280,7 +8312,7 @@ multiclass GF2P8AFFINE_common<bits<8> Op, string OpStr, SDNode OpNode> {
let Constraints = "$src1 = $dst",
Predicates = [HasGFNI, UseSSE2] in
defm GF2P8MULB : GF2P8MULB_rm<"gf2p8mulb", v16i8, VR128, memop,
- i128mem, SchedWriteVecALU.XMM, 1>;
+ i128mem_norex2, SchedWriteVecALU.XMM, 1>;
let Predicates = [HasGFNI, HasAVX, NoVLX] in {
defm VGF2P8MULB : GF2P8MULB_rm<"vgf2p8mulb", v16i8, VR128, load,
i128mem, SchedWriteVecALU.XMM>, VEX, VVVV;
diff --git a/llvm/test/MC/X86/apx/no-rex2-reject.s b/llvm/test/MC/X86/apx/no-rex2-reject.s
index 54f64462715dc..02dc2700b9def 100644
--- a/llvm/test/MC/X86/apx/no-rex2-reject.s
+++ b/llvm/test/MC/X86/apx/no-rex2-reject.s
@@ -1,4 +1,4 @@
-# RUN: not llvm-mc -triple x86_64 -mattr=+xsave,+ssse3,+avx,+tbm %s 2>&1 | \
+# RUN: not llvm-mc -triple x86_64 -mattr=+xsave,+ssse3,+sse4.2,+avx,+avx2,+tbm,+aes,+vaes,+sha,+pclmul,+gfni,+kl,+widekl %s 2>&1 | \
# RUN: FileCheck --check-prefix=ERROR --implicit-check-not=error: %s
# An extended GPR (r16-r31) can only be encoded by an EVEX
@@ -31,3 +31,83 @@ blcfill %r16d, %eax
# encoding.
# ERROR: [[#@LINE+1]]:1: error: unsupported instruction
{vex} vcvtsd2si %xmm0, %r16d
+
+# The legacy-vector 0F38/0F3A maps have no EVEX form, so their address
+# operands cannot use an EGPR. A representative from each affected family:
+
+# AES (0F38).
+# ERROR: [[#@LINE+1]]:1: error: unsupported instruction
+aesenc (%r16), %xmm0
+# ERROR: [[#@LINE+1]]:1: error: unsupported instruction
+aeskeygenassist $1, (%r16), %xmm0
+
+# Key Locker (0F38).
+# ERROR: [[#@LINE+1]]:1: error: unsupported instruction
+aesenc128kl (%r16), %xmm0
+
+# SHA (0F38/0F3A).
+# ERROR: [[#@LINE+1]]:1: error: unsupported instruction
+sha256rnds2 (%r16), %xmm0
+# ERROR: [[#@LINE+1]]:1: error: unsupported instruction
+sha1rnds4 $1, (%r16), %xmm0
+
+# PCLMULQDQ (0F3A).
+# ERROR: [[#@LINE+1]]:1: error: unsupported instruction
+pclmulqdq $1, (%r16), %xmm0
+
+# GFNI (0F38/0F3A).
+# ERROR: [[#@LINE+1]]:1: error: unsupported instruction
+gf2p8mulb (%r16), %xmm0
+# ERROR: [[#@LINE+1]]:1: error: unsupported instruction
+gf2p8affineqb $1, (%r16), %xmm0
+
+# SSE4 integer/blend/pack/compare (0F38/0F3A).
+# ERROR: [[#@LINE+1]]:1: error: unsupported instruction
+pmulld (%r16), %xmm0
+# ERROR: [[#@LINE+1]]:1: error: unsupported instruction
+blendps $1, (%r16), %xmm0
+# ERROR: [[#@LINE+1]]:1: error: unsupported instruction
+packusdw (%r16), %xmm0
+# ERROR: [[#@LINE+1]]:1: error: unsupported instruction
+pcmpgtq (%r16), %xmm0
+# ERROR: [[#@LINE+1]]:1: error: unsupported instruction
+mpsadbw $1, (%r16), %xmm0
+# ERROR: [[#@LINE+1]]:1: error: unsupported instruction
+roundps $1, (%r16), %xmm0
+# The scalar intrinsic forms take an ssmem/sdmem source.
+# ERROR: [[#@LINE+1]]:1: error: unsupported instruction
+roundss $1, (%r16), %xmm0
+# ERROR: [[#@LINE+1]]:1: error: unsupported instruction
+roundsd $1, (%r16), %xmm0
+
+# The index register is equally restricted.
+# ERROR: [[#@LINE+1]]:1: error: unsupported instruction
+pshufb (%rax,%r16), %xmm0
+
+# PMOVSX/ZX (0F38).
+# ERROR: [[#@LINE+1]]:1: error: unsupported instruction
+pmovsxbw (%r16), %xmm0
+
+# PEXTR/PINSR and EXTRACTPS have a direct GPR operand that likewise
+# cannot be an EGPR in the legacy encoding.
+# ERROR: [[#@LINE+1]]:1: error: unsupported instruction
+pextrd $1, %xmm0, %r16d
+# ERROR: [[#@LINE+1]]:1: error: unsupported instruction
+pinsrd $1, %r16d, %xmm0
+# ERROR: [[#@LINE+1]]:1: error: unsupported instruction
+extractps $1, %xmm0, %r16d
+# The 64-bit forms constrain the GPR the same way.
+# ERROR: [[#@LINE+1]]:1: error: unsupported instruction
+pextrq $1, %xmm0, %r16
+# ERROR: [[#@LINE+1]]:1: error: unsupported instruction
+pinsrq $1, %r16, %xmm0
+
+# VEX gather and maskmov have no in-place EVEX promotion, so the address
+# base cannot be an EGPR.
+# ERROR: [[#@LINE+1]]:1: error: unsupported instruction
+vgatherdps %xmm1, (%r16,%xmm2), %xmm0
+# ERROR: [[#@LINE+1]]:1: error: unsupported instruction
+vpmaskmovd %xmm1, %xmm2, (%r16)
+# The 256-bit maskmov store uses a ymm-sized memory operand.
+# ERROR: [[#@LINE+1]]:1: error: unsupported instruction
+vmaskmovps %ymm1, %ymm2, (%r16)
diff --git a/llvm/test/MachineVerifier/X86/apx-norex2-regclass.mir b/llvm/test/MachineVerifier/X86/apx-norex2-regclass.mir
index 7e0d98e486bf2..c7d37b72cea9b 100644
--- a/llvm/test/MachineVerifier/X86/apx-norex2-regclass.mir
+++ b/llvm/test/MachineVerifier/X86/apx-norex2-regclass.mir
@@ -1,5 +1,5 @@
# RUN: not --crash llc -mtriple=x86_64 \
-# RUN: -mattr=+ssse3,+avx,+tbm,+amx-tile,+egpr -run-pass=none -filetype=null %s \
+# RUN: -mattr=+sse4.2,+avx,+tbm,+amx-tile,+egpr -run-pass=none -filetype=null %s \
# RUN: 2>&1 | FileCheck %s -implicit-check-not="Bad machine code"
# The *_norex2 operands resolve to the *_NOREX2 register classes in the
@@ -59,4 +59,18 @@ body: |
; MOV32rm is EGPR-capable, so an EGPR def is accepted.
renamable $r19d = MOV32rm renamable $rdi, 1, $noreg, 0, $noreg
+
+ ; PMULLD is an SSE4.1 T8 instruction with no EVEX form, so its address
+ ; base cannot be an EGPR.
+ ; CHECK: *** Bad machine code: Illegal physical register for instruction ***
+ ; CHECK: - instruction: renamable $xmm0 = PMULLDrm renamable $xmm0{{.*}} renamable $r16
+ ; CHECK: $r16 is not a GR64_NOREX2 register.
+ renamable $xmm0 = PMULLDrm renamable $xmm0, renamable $r16, 1, $noreg, 0, $noreg
+
+ ; PEXTRD writes its result to a GPR that cannot be an EGPR in the legacy
+ ; encoding.
+ ; CHECK: *** Bad machine code: Illegal physical register for instruction ***
+ ; CHECK: - instruction: renamable $r20d = PEXTRDrri
+ ; CHECK: $r20d is not a GR32_NOREX2 register.
+ renamable $r20d = PEXTRDrri renamable $xmm0, 1
...
diff --git a/llvm/utils/TableGen/X86RecognizableInstr.cpp b/llvm/utils/TableGen/X86RecognizableInstr.cpp
index cc3176bf44911..bfdd45b3f2a94 100644
--- a/llvm/utils/TableGen/X86RecognizableInstr.cpp
+++ b/llvm/utils/TableGen/X86RecognizableInstr.cpp
@@ -69,12 +69,12 @@ static const Record *getRegClassByHwModeRepresentative(const Record *Rec) {
}
unsigned X86Disassembler::getRegOperandSize(const Record *RegRec) {
+ if (RegRec->isSubClassOf("RegisterOperand"))
+ RegRec = RegRec->getValueAsDef("RegClass");
if (RegRec->isSubClassOf("RegClassByHwMode"))
RegRec = getRegClassByHwModeRepresentative(RegRec);
if (RegRec->isSubClassOf("RegisterClass"))
return RegRec->getValueAsInt("Alignment");
- if (RegRec->isSubClassOf("RegisterOperand"))
- return RegRec->getValueAsDef("RegClass")->getValueAsInt("Alignment");
llvm_unreachable("Register operand's size not known!");
}
@@ -1044,7 +1044,7 @@ OperandType RecognizableInstr::typeFromString(StringRef Str, bool hasREX_W,
.Case("i32imm", TYPE_IMM)
.Case("i32i8imm", TYPE_IMM)
.Case("GR32", TYPE_R32)
- .Case("GR32orGR64", TYPE_R32)
+ .Cases({"GR32orGR64", "GR32orGR64_norex2"}, TYPE_R32)
.Cases({"i64mem", "i64mem_norex2"}, TYPE_M)
.Case("i64i32imm", TYPE_IMM)
.Case("i64i8imm", TYPE_IMM)
@@ -1059,8 +1059,8 @@ OperandType RecognizableInstr::typeFromString(StringRef Str, bool hasREX_W,
.Case("GR8", TYPE_R8)
.Case("VR128", TYPE_XMM)
.Case("VR128X", TYPE_XMM)
- .Case("f128mem", TYPE_M)
- .Case("f256mem", TYPE_M)
+ .Cases({"f128mem", "f128mem_norex2"}, TYPE_M)
+ .Cases({"f256mem", "f256mem_norex2"}, TYPE_M)
.Case("f512mem", TYPE_M)
.Case("FR128", TYPE_XMM)
.Case("FR64", TYPE_XMM)
@@ -1146,10 +1146,10 @@ OperandType RecognizableInstr::typeFromString(StringRef Str, bool hasREX_W,
.Case("VK4Pair", TYPE_VK_PAIR)
.Case("VK8Pair", TYPE_VK_PAIR)
.Case("VK16Pair", TYPE_VK_PAIR)
- .Case("vx32mem", TYPE_MVSIBX)
- .Case("vx64mem", TYPE_MVSIBX)
- .Case("vy32mem", TYPE_MVSIBY)
- .Case("vy64mem", TYPE_MVSIBY)
+ .Cases({"vx32mem", "vx32mem_norex2"}, TYPE_MVSIBX)
+ .Cases({"vx64mem", "vx64mem_norex2"}, TYPE_MVSIBX)
+ .Cases({"vy32mem", "vy32mem_norex2"}, TYPE_MVSIBY)
+ .Cases({"vy64mem", "vy64mem_norex2"}, TYPE_MVSIBY)
.Case("vx32xmem", TYPE_MVSIBX)
.Case("vx64xmem", TYPE_MVSIBX)
.Case("vy32xmem", TYPE_MVSIBY)
@@ -1226,7 +1226,7 @@ RecognizableInstr::rmRegisterEncodingFromString(StringRef Str, uint8_t OpSize) {
.Case("GR16", ENCODING_RM)
.Case("GR16orGR32orGR64", ENCODING_RM)
.Case("GR32", ENCODING_RM)
- .Case("GR32orGR64", ENCODING_RM)
+ .Cases({"GR32orGR64", "GR32orGR64_norex2"}, ENCODING_RM)
.Case("GR64", ENCODING_RM)
.Case("GR8", ENCODING_RM)
.Case("VR128", ENCODING_RM)
@@ -1267,7 +1267,7 @@ RecognizableInstr::roRegisterEncodingFromString(StringRef Str, uint8_t OpSize) {
.Case("GR16", ENCODING_REG)
.Case("GR16orGR32orGR64", ENCODING_REG)
.Case("GR32", ENCODING_REG)
- .Case("GR32orGR64", ENCODING_REG)
+ .Cases({"GR32orGR64", "GR32orGR64_norex2"}, ENCODING_REG)
.Case("GR64", ENCODING_REG)
.Case("GR8", ENCODING_REG)
.Case("VR128", ENCODING_REG)
@@ -1391,8 +1391,8 @@ OperandEncoding RecognizableInstr::memoryEncodingFromString(StringRef Str,
.Case("shmem", ENCODING_RM)
.Cases({"ssmem", "ssmem_norex2"}, ENCODING_RM)
.Cases({"sdmem", "sdmem_norex2"}, ENCODING_RM)
- .Case("f128mem", ENCODING_RM)
- .Case("f256mem", ENCODING_RM)
+ .Cases({"f128mem", "f128mem_norex2"}, ENCODING_RM)
+ .Cases({"f256mem", "f256mem_norex2"}, ENCODING_RM)
.Case("f512mem", ENCODING_RM)
.Cases({"f64mem", "f64mem_norex2"}, ENCODING_RM)
.Cases({"f32mem", "f32mem_norex2"}, ENCODING_RM)
@@ -1411,10 +1411,10 @@ OperandEncoding RecognizableInstr::memoryEncodingFromString(StringRef Str,
.Cases({"anymem", "anymem_norex2"}, ENCODING_RM)
.Cases({"opaquemem", "opaquemem_norex2"}, ENCODING_RM)
.Cases({"sibmem", "sibmem_norex2"}, ENCODING_SIB)
- .Case("vx32mem", ENCODING_VSIB)
- .Case("vx64mem", ENCODING_VSIB)
- .Case("vy32mem", ENCODING_VSIB)
- .Case("vy64mem", ENCODING_VSIB)
+ .Cases({"vx32mem", "vx32mem_norex2"}, ENCODING_VSIB)
+ .Cases({"vx64mem", "vx64mem_norex2"}, ENCODING_VSIB)
+ .Cases({"vy32mem", "vy32mem_norex2"}, ENCODING_VSIB)
+ .Cases({"vy64mem", "vy64mem_norex2"}, ENCODING_VSIB)
.Case("vx32xmem", ENCODING_VSIB)
.Case("vx64xmem", ENCODING_VSIB)
.Case("vy32xmem", ENCODING_VSIB)
More information about the llvm-commits
mailing list