[llvm] [X86][GlobalISel] Support fp80 for G_FPTRUNC and G_FPEXT (PR #141611)
Evgenii Kudriashov via llvm-commits
llvm-commits at lists.llvm.org
Tue Feb 17 02:48:01 PST 2026
https://github.com/e-kud updated https://github.com/llvm/llvm-project/pull/141611
>From a603218cf79bd14304479f56f3349c7075e9e696 Mon Sep 17 00:00:00 2001
From: Evgenii Kudriashov <evgenii.kudriashov at intel.com>
Date: Tue, 27 May 2025 06:51:53 -0700
Subject: [PATCH 1/6] Precommit tests
---
.../CodeGen/X86/GlobalISel/fpext-scalar.ll | 12 --
llvm/test/CodeGen/X86/isel-fptrunc-fpext.ll | 177 ++++++++++++++++++
2 files changed, 177 insertions(+), 12 deletions(-)
delete mode 100644 llvm/test/CodeGen/X86/GlobalISel/fpext-scalar.ll
create mode 100644 llvm/test/CodeGen/X86/isel-fptrunc-fpext.ll
diff --git a/llvm/test/CodeGen/X86/GlobalISel/fpext-scalar.ll b/llvm/test/CodeGen/X86/GlobalISel/fpext-scalar.ll
deleted file mode 100644
index 8501009e2915a..0000000000000
--- a/llvm/test/CodeGen/X86/GlobalISel/fpext-scalar.ll
+++ /dev/null
@@ -1,12 +0,0 @@
-; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
-; RUN: llc -mtriple=x86_64-linux-gnu -global-isel -verify-machineinstrs < %s -o - | FileCheck %s --check-prefix=CHECK
-
-define double @test(float %a) {
-; CHECK-LABEL: test:
-; CHECK: # %bb.0: # %entry
-; CHECK-NEXT: cvtss2sd %xmm0, %xmm0
-; CHECK-NEXT: retq
-entry:
- %conv = fpext float %a to double
- ret double %conv
-}
diff --git a/llvm/test/CodeGen/X86/isel-fptrunc-fpext.ll b/llvm/test/CodeGen/X86/isel-fptrunc-fpext.ll
new file mode 100644
index 0000000000000..717802110c6a6
--- /dev/null
+++ b/llvm/test/CodeGen/X86/isel-fptrunc-fpext.ll
@@ -0,0 +1,177 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
+; RUN: llc < %s -mtriple=i686-unknown-unknown -fast-isel=0 -global-isel=0 | FileCheck %s --check-prefixes X86,FASTSDAG-X86,SDAG-X86
+; RUN: llc < %s -mtriple=x86_64-unknown-unknown -mattr=+sse2 -fast-isel=0 -global-isel=0 | FileCheck %s --check-prefixes SSE,FASTSDAG-SSE,SDAG-SSE
+; RUN: llc < %s -mtriple=x86_64-unknown-unknown -mattr=+avx -fast-isel=0 -global-isel=0 | FileCheck %s --check-prefixes AVX,FASTSDAG-AVX,SDAG-AVX
+; RUN: llc < %s -mtriple=x86_64-unknown-unknown -mattr=+avx512f -fast-isel=0 -global-isel=0 | FileCheck %s --check-prefixes AVX,FASTSDAG-AVX,SDAG-AVX
+; COMM: FastISel has troubles with fp80 type
+; RUN: llc < %s -mtriple=i686-unknown-unknown -fast-isel=1 -global-isel=0 -fast-isel-abort=0 | FileCheck %s --check-prefixes X86,FASTSDAG-X86,FAST-X86
+; RUN: llc < %s -mtriple=x86_64-unknown-unknown -mattr=+sse2 -fast-isel=1 -global-isel=0 -fast-isel-abort=0 | FileCheck %s --check-prefixes SSE,FASTSDAG-SSE,FAST-SSE
+; RUN: llc < %s -mtriple=x86_64-unknown-unknown -mattr=+avx -fast-isel=1 -global-isel=0 -fast-isel-abort=0 | FileCheck %s --check-prefixes AVX,FASTSDAG-AVX,FAST-AVX
+; RUN: llc < %s -mtriple=x86_64-unknown-unknown -mattr=+avx512f -fast-isel=1 -global-isel=0 -fast-isel-abort=0 | FileCheck %s --check-prefixes AVX,FASTSDAG-AVX,FAST-AVX
+; RUN: llc < %s -mtriple=i686-unknown-unknown -fast-isel=0 -global-isel=1 -global-isel-abort=2 | FileCheck %s --check-prefixes X86,GLOBAL-X86
+; RUN: llc < %s -mtriple=x86_64-unknown-unknown -mattr=+sse2 -fast-isel=0 -global-isel=1 -global-isel-abort=2 | FileCheck %s --check-prefixes SSE,GLOBAL-SSE
+; RUN: llc < %s -mtriple=x86_64-unknown-unknown -mattr=+avx -fast-isel=0 -global-isel=1 -global-isel-abort=2 | FileCheck %s --check-prefixes AVX,GLOBAL-AVX
+; RUN: llc < %s -mtriple=x86_64-unknown-unknown -mattr=+avx512f -fast-isel=0 -global-isel=1 -global-isel-abort=2 | FileCheck %s --check-prefixes AVX,GLOBAL-AVX
+
+define double @fpext_float_to_double(float %f) {
+; X86-LABEL: fpext_float_to_double:
+; X86: # %bb.0:
+; X86-NEXT: flds {{[0-9]+}}(%esp)
+; X86-NEXT: retl
+;
+; SSE-LABEL: fpext_float_to_double:
+; SSE: # %bb.0:
+; SSE-NEXT: cvtss2sd %xmm0, %xmm0
+; SSE-NEXT: retq
+;
+; AVX-LABEL: fpext_float_to_double:
+; AVX: # %bb.0:
+; AVX-NEXT: vcvtss2sd %xmm0, %xmm0, %xmm0
+; AVX-NEXT: retq
+ %1 = fpext float %f to double
+ ret double %1
+}
+
+define x86_fp80 @fpext_float_to_x86_fp80(float %f) {
+; X86-LABEL: fpext_float_to_x86_fp80:
+; X86: # %bb.0:
+; X86-NEXT: flds {{[0-9]+}}(%esp)
+; X86-NEXT: retl
+;
+; SSE-LABEL: fpext_float_to_x86_fp80:
+; SSE: # %bb.0:
+; SSE-NEXT: movss %xmm0, -{{[0-9]+}}(%rsp)
+; SSE-NEXT: flds -{{[0-9]+}}(%rsp)
+; SSE-NEXT: retq
+;
+; AVX-LABEL: fpext_float_to_x86_fp80:
+; AVX: # %bb.0:
+; AVX-NEXT: vmovss %xmm0, -{{[0-9]+}}(%rsp)
+; AVX-NEXT: flds -{{[0-9]+}}(%rsp)
+; AVX-NEXT: retq
+ %1 = fpext float %f to x86_fp80
+ ret x86_fp80 %1
+}
+
+define x86_fp80 @fpext_double_to_x86_fp80(double %d) {
+; X86-LABEL: fpext_double_to_x86_fp80:
+; X86: # %bb.0:
+; X86-NEXT: fldl {{[0-9]+}}(%esp)
+; X86-NEXT: retl
+;
+; SSE-LABEL: fpext_double_to_x86_fp80:
+; SSE: # %bb.0:
+; SSE-NEXT: movsd %xmm0, -{{[0-9]+}}(%rsp)
+; SSE-NEXT: fldl -{{[0-9]+}}(%rsp)
+; SSE-NEXT: retq
+;
+; AVX-LABEL: fpext_double_to_x86_fp80:
+; AVX: # %bb.0:
+; AVX-NEXT: vmovsd %xmm0, -{{[0-9]+}}(%rsp)
+; AVX-NEXT: fldl -{{[0-9]+}}(%rsp)
+; AVX-NEXT: retq
+ %1 = fpext double %d to x86_fp80
+ ret x86_fp80 %1
+}
+
+define float @fptrunc_double_to_float(double %d) {
+; X86-LABEL: fptrunc_double_to_float:
+; X86: # %bb.0:
+; X86-NEXT: pushl %eax
+; X86-NEXT: .cfi_def_cfa_offset 8
+; X86-NEXT: fldl {{[0-9]+}}(%esp)
+; X86-NEXT: fstps (%esp)
+; X86-NEXT: flds (%esp)
+; X86-NEXT: popl %eax
+; X86-NEXT: .cfi_def_cfa_offset 4
+; X86-NEXT: retl
+;
+; SSE-LABEL: fptrunc_double_to_float:
+; SSE: # %bb.0:
+; SSE-NEXT: cvtsd2ss %xmm0, %xmm0
+; SSE-NEXT: retq
+;
+; AVX-LABEL: fptrunc_double_to_float:
+; AVX: # %bb.0:
+; AVX-NEXT: vcvtsd2ss %xmm0, %xmm0, %xmm0
+; AVX-NEXT: retq
+ %1 = fptrunc double %d to float
+ ret float %1
+}
+
+define float @fptrunc_x86_fp80_to_float(x86_fp80 %x) {
+; X86-LABEL: fptrunc_x86_fp80_to_float:
+; X86: # %bb.0:
+; X86-NEXT: pushl %eax
+; X86-NEXT: .cfi_def_cfa_offset 8
+; X86-NEXT: fldt {{[0-9]+}}(%esp)
+; X86-NEXT: fstps (%esp)
+; X86-NEXT: flds (%esp)
+; X86-NEXT: popl %eax
+; X86-NEXT: .cfi_def_cfa_offset 4
+; X86-NEXT: retl
+;
+; SSE-LABEL: fptrunc_x86_fp80_to_float:
+; SSE: # %bb.0:
+; SSE-NEXT: fldt {{[0-9]+}}(%rsp)
+; SSE-NEXT: fstps -{{[0-9]+}}(%rsp)
+; SSE-NEXT: movss {{.*#+}} xmm0 = mem[0],zero,zero,zero
+; SSE-NEXT: retq
+;
+; AVX-LABEL: fptrunc_x86_fp80_to_float:
+; AVX: # %bb.0:
+; AVX-NEXT: fldt {{[0-9]+}}(%rsp)
+; AVX-NEXT: fstps -{{[0-9]+}}(%rsp)
+; AVX-NEXT: vmovss {{.*#+}} xmm0 = mem[0],zero,zero,zero
+; AVX-NEXT: retq
+ %1 = fptrunc x86_fp80 %x to float
+ ret float %1
+}
+
+define double @fptrunc_x86_fp80_to_double(x86_fp80 %x) {
+; X86-LABEL: fptrunc_x86_fp80_to_double:
+; X86: # %bb.0:
+; X86-NEXT: pushl %ebp
+; X86-NEXT: .cfi_def_cfa_offset 8
+; X86-NEXT: .cfi_offset %ebp, -8
+; X86-NEXT: movl %esp, %ebp
+; X86-NEXT: .cfi_def_cfa_register %ebp
+; X86-NEXT: andl $-8, %esp
+; X86-NEXT: subl $8, %esp
+; X86-NEXT: fldt 8(%ebp)
+; X86-NEXT: fstpl (%esp)
+; X86-NEXT: fldl (%esp)
+; X86-NEXT: movl %ebp, %esp
+; X86-NEXT: popl %ebp
+; X86-NEXT: .cfi_def_cfa %esp, 4
+; X86-NEXT: retl
+;
+; SSE-LABEL: fptrunc_x86_fp80_to_double:
+; SSE: # %bb.0:
+; SSE-NEXT: fldt {{[0-9]+}}(%rsp)
+; SSE-NEXT: fstpl -{{[0-9]+}}(%rsp)
+; SSE-NEXT: movsd {{.*#+}} xmm0 = mem[0],zero
+; SSE-NEXT: retq
+;
+; AVX-LABEL: fptrunc_x86_fp80_to_double:
+; AVX: # %bb.0:
+; AVX-NEXT: fldt {{[0-9]+}}(%rsp)
+; AVX-NEXT: fstpl -{{[0-9]+}}(%rsp)
+; AVX-NEXT: vmovsd {{.*#+}} xmm0 = mem[0],zero
+; AVX-NEXT: retq
+ %1 = fptrunc x86_fp80 %x to double
+ ret double %1
+}
+;; NOTE: These prefixes are unused and the list is autogenerated. Do not add tests below this line:
+; FAST-AVX: {{.*}}
+; FAST-SSE: {{.*}}
+; FAST-X86: {{.*}}
+; FASTSDAG-AVX: {{.*}}
+; FASTSDAG-SSE: {{.*}}
+; FASTSDAG-X86: {{.*}}
+; GLOBAL-AVX: {{.*}}
+; GLOBAL-SSE: {{.*}}
+; GLOBAL-X86: {{.*}}
+; SDAG-AVX: {{.*}}
+; SDAG-SSE: {{.*}}
+; SDAG-X86: {{.*}}
>From cd09cc331958ac543785a7de80ae68a4bd5d7887 Mon Sep 17 00:00:00 2001
From: Evgenii Kudriashov <evgenii.kudriashov at intel.com>
Date: Tue, 27 May 2025 06:57:16 -0700
Subject: [PATCH 2/6] [X86][GlobalISel] Support fp80 for G_FPTRUNC and G_FPEXT
---
.../lib/Target/X86/GISel/X86LegalizerInfo.cpp | 61 ++++-
llvm/lib/Target/X86/GISel/X86LegalizerInfo.h | 3 +
llvm/test/CodeGen/X86/isel-fptrunc-fpext.ll | 244 +++++++++++++-----
3 files changed, 224 insertions(+), 84 deletions(-)
diff --git a/llvm/lib/Target/X86/GISel/X86LegalizerInfo.cpp b/llvm/lib/Target/X86/GISel/X86LegalizerInfo.cpp
index f008cb1bea839..58215d4e00202 100644
--- a/llvm/lib/Target/X86/GISel/X86LegalizerInfo.cpp
+++ b/llvm/lib/Target/X86/GISel/X86LegalizerInfo.cpp
@@ -376,9 +376,15 @@ X86LegalizerInfo::X86LegalizerInfo(const X86Subtarget &STI,
Action.legalForTypesWithMemDesc({{s8, p0, s8, 1},
{s16, p0, s16, 1},
{s32, p0, s32, 1},
- {s80, p0, s80, 1},
{p0, p0, p0, 1},
{v4s8, p0, v4s8, 1}});
+
+ if (UseX87)
+ Action.legalForTypesWithMemDesc({{s80, p0, s32, 1},
+ {s80, p0, s64, 1},
+ {s32, p0, s80, 1},
+ {s64, p0, s80, 1},
+ {s80, p0, s80, 1}});
if (Is64Bit)
Action.legalForTypesWithMemDesc(
{{s64, p0, s64, 1}, {v2s32, p0, v2s32, 1}});
@@ -476,18 +482,17 @@ X86LegalizerInfo::X86LegalizerInfo(const X86Subtarget &STI,
.widenScalarToNextPow2(1);
// fp conversions
- getActionDefinitionsBuilder(G_FPEXT).legalIf([=](const LegalityQuery &Query) {
- return (HasSSE2 && typePairInSet(0, 1, {{s64, s32}})(Query)) ||
- (HasAVX && typePairInSet(0, 1, {{v4s64, v4s32}})(Query)) ||
- (HasAVX512 && typePairInSet(0, 1, {{v8s64, v8s32}})(Query));
- });
-
- getActionDefinitionsBuilder(G_FPTRUNC).legalIf(
- [=](const LegalityQuery &Query) {
- return (HasSSE2 && typePairInSet(0, 1, {{s32, s64}})(Query)) ||
- (HasAVX && typePairInSet(0, 1, {{v4s32, v4s64}})(Query)) ||
- (HasAVX512 && typePairInSet(0, 1, {{v8s32, v8s64}})(Query));
- });
+ getActionDefinitionsBuilder(G_FPEXT)
+ .legalFor(HasSSE2, {{s64, s32}})
+ .legalFor(HasAVX, {{v4s64, v4s32}})
+ .legalFor(HasAVX512, {{v8s64, v8s32}})
+ .customFor(UseX87, {{s64, s32}, {s80, s32}, {s80, s64}});
+
+ getActionDefinitionsBuilder(G_FPTRUNC)
+ .legalFor(HasSSE2, {{s32, s64}})
+ .legalFor(HasAVX, {{v4s32, v4s64}})
+ .legalFor(HasAVX512, {{v8s32, v8s64}})
+ .customFor(UseX87, {{s32, s64}, {s32, s80}, {s64, s80}});
getActionDefinitionsBuilder(G_SITOFP)
.legalIf([=](const LegalityQuery &Query) {
@@ -671,6 +676,9 @@ bool X86LegalizerInfo::legalizeCustom(LegalizerHelper &Helper, MachineInstr &MI,
return legalizeUITOFP(MI, MRI, Helper);
case TargetOpcode::G_STORE:
return legalizeNarrowingStore(MI, MRI, Helper);
+ case TargetOpcode::G_FPEXT:
+ case TargetOpcode::G_FPTRUNC:
+ return legalizeFPExtAndTrunc(MI, MRI, Helper);
}
llvm_unreachable("expected switch to return");
}
@@ -781,6 +789,33 @@ bool X86LegalizerInfo::legalizeNarrowingStore(MachineInstr &MI,
return true;
}
+bool X86LegalizerInfo::legalizeFPExtAndTrunc(MachineInstr &MI,
+ MachineRegisterInfo &MRI,
+ LegalizerHelper &Helper) const {
+ assert((MI.getOpcode() == TargetOpcode::G_FPEXT ||
+ MI.getOpcode() == TargetOpcode::G_FPTRUNC) &&
+ "Only G_FPEXT and G_FPTRUNC are expected");
+ auto [DstReg, DstTy, SrcReg, SrcTy] = MI.getFirst2RegLLTs();
+ MachinePointerInfo PtrInfo;
+ LLT StackTy = MI.getOpcode() == TargetOpcode::G_FPEXT ? SrcTy : DstTy;
+ Align StackTyAlign = Helper.getStackTemporaryAlignment(StackTy);
+ auto StackTemp = Helper.createStackTemporary(StackTy.getSizeInBytes(),
+ StackTyAlign, PtrInfo);
+
+ MachineIRBuilder &MIRBuilder = Helper.MIRBuilder;
+ MachineFunction &MF = MIRBuilder.getMF();
+ auto *StoreMMO = MF.getMachineMemOperand(PtrInfo, MachineMemOperand::MOStore,
+ StackTy, StackTyAlign);
+ MIRBuilder.buildStore(SrcReg, StackTemp, *StoreMMO);
+
+ auto *LoadMMO = MF.getMachineMemOperand(PtrInfo, MachineMemOperand::MOLoad,
+ StackTy, StackTyAlign);
+ MIRBuilder.buildLoad(DstReg, StackTemp, *LoadMMO);
+
+ MI.eraseFromParent();
+ return true;
+}
+
bool X86LegalizerInfo::legalizeIntrinsic(LegalizerHelper &Helper,
MachineInstr &MI) const {
return true;
diff --git a/llvm/lib/Target/X86/GISel/X86LegalizerInfo.h b/llvm/lib/Target/X86/GISel/X86LegalizerInfo.h
index 54f776456397b..b224f3f46a2d5 100644
--- a/llvm/lib/Target/X86/GISel/X86LegalizerInfo.h
+++ b/llvm/lib/Target/X86/GISel/X86LegalizerInfo.h
@@ -48,6 +48,9 @@ class X86LegalizerInfo : public LegalizerInfo {
bool legalizeNarrowingStore(MachineInstr &MI, MachineRegisterInfo &MRI,
LegalizerHelper &Helper) const;
+
+ bool legalizeFPExtAndTrunc(MachineInstr &MI, MachineRegisterInfo &MRI,
+ LegalizerHelper &Helper) const;
};
} // namespace llvm
#endif
diff --git a/llvm/test/CodeGen/X86/isel-fptrunc-fpext.ll b/llvm/test/CodeGen/X86/isel-fptrunc-fpext.ll
index 717802110c6a6..0ad9b90806ce9 100644
--- a/llvm/test/CodeGen/X86/isel-fptrunc-fpext.ll
+++ b/llvm/test/CodeGen/X86/isel-fptrunc-fpext.ll
@@ -8,10 +8,11 @@
; RUN: llc < %s -mtriple=x86_64-unknown-unknown -mattr=+sse2 -fast-isel=1 -global-isel=0 -fast-isel-abort=0 | FileCheck %s --check-prefixes SSE,FASTSDAG-SSE,FAST-SSE
; RUN: llc < %s -mtriple=x86_64-unknown-unknown -mattr=+avx -fast-isel=1 -global-isel=0 -fast-isel-abort=0 | FileCheck %s --check-prefixes AVX,FASTSDAG-AVX,FAST-AVX
; RUN: llc < %s -mtriple=x86_64-unknown-unknown -mattr=+avx512f -fast-isel=1 -global-isel=0 -fast-isel-abort=0 | FileCheck %s --check-prefixes AVX,FASTSDAG-AVX,FAST-AVX
+; COMM: GlobalISel can't legalize double stores on 32bit platform due to lack of double/integer distinguish during legalization
; RUN: llc < %s -mtriple=i686-unknown-unknown -fast-isel=0 -global-isel=1 -global-isel-abort=2 | FileCheck %s --check-prefixes X86,GLOBAL-X86
-; RUN: llc < %s -mtriple=x86_64-unknown-unknown -mattr=+sse2 -fast-isel=0 -global-isel=1 -global-isel-abort=2 | FileCheck %s --check-prefixes SSE,GLOBAL-SSE
-; RUN: llc < %s -mtriple=x86_64-unknown-unknown -mattr=+avx -fast-isel=0 -global-isel=1 -global-isel-abort=2 | FileCheck %s --check-prefixes AVX,GLOBAL-AVX
-; RUN: llc < %s -mtriple=x86_64-unknown-unknown -mattr=+avx512f -fast-isel=0 -global-isel=1 -global-isel-abort=2 | FileCheck %s --check-prefixes AVX,GLOBAL-AVX
+; RUN: llc < %s -mtriple=x86_64-unknown-unknown -mattr=+sse2 -fast-isel=0 -global-isel=1 -global-isel-abort=1 | FileCheck %s --check-prefixes SSE,GLOBAL-SSE
+; RUN: llc < %s -mtriple=x86_64-unknown-unknown -mattr=+avx -fast-isel=0 -global-isel=1 -global-isel-abort=1 | FileCheck %s --check-prefixes AVX,GLOBAL-AVX
+; RUN: llc < %s -mtriple=x86_64-unknown-unknown -mattr=+avx512f -fast-isel=0 -global-isel=1 -global-isel-abort=1 | FileCheck %s --check-prefixes AVX,GLOBAL-AVX
define double @fpext_float_to_double(float %f) {
; X86-LABEL: fpext_float_to_double:
@@ -33,58 +34,118 @@ define double @fpext_float_to_double(float %f) {
}
define x86_fp80 @fpext_float_to_x86_fp80(float %f) {
-; X86-LABEL: fpext_float_to_x86_fp80:
-; X86: # %bb.0:
-; X86-NEXT: flds {{[0-9]+}}(%esp)
-; X86-NEXT: retl
+; FASTSDAG-X86-LABEL: fpext_float_to_x86_fp80:
+; FASTSDAG-X86: # %bb.0:
+; FASTSDAG-X86-NEXT: flds {{[0-9]+}}(%esp)
+; FASTSDAG-X86-NEXT: retl
;
-; SSE-LABEL: fpext_float_to_x86_fp80:
-; SSE: # %bb.0:
-; SSE-NEXT: movss %xmm0, -{{[0-9]+}}(%rsp)
-; SSE-NEXT: flds -{{[0-9]+}}(%rsp)
-; SSE-NEXT: retq
+; FASTSDAG-SSE-LABEL: fpext_float_to_x86_fp80:
+; FASTSDAG-SSE: # %bb.0:
+; FASTSDAG-SSE-NEXT: movss %xmm0, -{{[0-9]+}}(%rsp)
+; FASTSDAG-SSE-NEXT: flds -{{[0-9]+}}(%rsp)
+; FASTSDAG-SSE-NEXT: retq
;
-; AVX-LABEL: fpext_float_to_x86_fp80:
-; AVX: # %bb.0:
-; AVX-NEXT: vmovss %xmm0, -{{[0-9]+}}(%rsp)
-; AVX-NEXT: flds -{{[0-9]+}}(%rsp)
-; AVX-NEXT: retq
+; FASTSDAG-AVX-LABEL: fpext_float_to_x86_fp80:
+; FASTSDAG-AVX: # %bb.0:
+; FASTSDAG-AVX-NEXT: vmovss %xmm0, -{{[0-9]+}}(%rsp)
+; FASTSDAG-AVX-NEXT: flds -{{[0-9]+}}(%rsp)
+; FASTSDAG-AVX-NEXT: retq
+;
+; GLOBAL-X86-LABEL: fpext_float_to_x86_fp80:
+; GLOBAL-X86: # %bb.0:
+; GLOBAL-X86-NEXT: pushl %eax
+; GLOBAL-X86-NEXT: .cfi_def_cfa_offset 8
+; GLOBAL-X86-NEXT: movl {{[0-9]+}}(%esp), %eax
+; GLOBAL-X86-NEXT: movl %eax, (%esp)
+; GLOBAL-X86-NEXT: flds (%esp)
+; GLOBAL-X86-NEXT: popl %eax
+; GLOBAL-X86-NEXT: .cfi_def_cfa_offset 4
+; GLOBAL-X86-NEXT: retl
+;
+; GLOBAL-SSE-LABEL: fpext_float_to_x86_fp80:
+; GLOBAL-SSE: # %bb.0:
+; GLOBAL-SSE-NEXT: movd %xmm0, %eax
+; GLOBAL-SSE-NEXT: movl %eax, -{{[0-9]+}}(%rsp)
+; GLOBAL-SSE-NEXT: flds -{{[0-9]+}}(%rsp)
+; GLOBAL-SSE-NEXT: retq
+;
+; GLOBAL-AVX-LABEL: fpext_float_to_x86_fp80:
+; GLOBAL-AVX: # %bb.0:
+; GLOBAL-AVX-NEXT: vmovd %xmm0, %eax
+; GLOBAL-AVX-NEXT: movl %eax, -{{[0-9]+}}(%rsp)
+; GLOBAL-AVX-NEXT: flds -{{[0-9]+}}(%rsp)
+; GLOBAL-AVX-NEXT: retq
%1 = fpext float %f to x86_fp80
ret x86_fp80 %1
}
define x86_fp80 @fpext_double_to_x86_fp80(double %d) {
-; X86-LABEL: fpext_double_to_x86_fp80:
-; X86: # %bb.0:
-; X86-NEXT: fldl {{[0-9]+}}(%esp)
-; X86-NEXT: retl
+; FASTSDAG-X86-LABEL: fpext_double_to_x86_fp80:
+; FASTSDAG-X86: # %bb.0:
+; FASTSDAG-X86-NEXT: fldl {{[0-9]+}}(%esp)
+; FASTSDAG-X86-NEXT: retl
;
-; SSE-LABEL: fpext_double_to_x86_fp80:
-; SSE: # %bb.0:
-; SSE-NEXT: movsd %xmm0, -{{[0-9]+}}(%rsp)
-; SSE-NEXT: fldl -{{[0-9]+}}(%rsp)
-; SSE-NEXT: retq
+; FASTSDAG-SSE-LABEL: fpext_double_to_x86_fp80:
+; FASTSDAG-SSE: # %bb.0:
+; FASTSDAG-SSE-NEXT: movsd %xmm0, -{{[0-9]+}}(%rsp)
+; FASTSDAG-SSE-NEXT: fldl -{{[0-9]+}}(%rsp)
+; FASTSDAG-SSE-NEXT: retq
;
-; AVX-LABEL: fpext_double_to_x86_fp80:
-; AVX: # %bb.0:
-; AVX-NEXT: vmovsd %xmm0, -{{[0-9]+}}(%rsp)
-; AVX-NEXT: fldl -{{[0-9]+}}(%rsp)
-; AVX-NEXT: retq
+; FASTSDAG-AVX-LABEL: fpext_double_to_x86_fp80:
+; FASTSDAG-AVX: # %bb.0:
+; FASTSDAG-AVX-NEXT: vmovsd %xmm0, -{{[0-9]+}}(%rsp)
+; FASTSDAG-AVX-NEXT: fldl -{{[0-9]+}}(%rsp)
+; FASTSDAG-AVX-NEXT: retq
+;
+; GLOBAL-X86-LABEL: fpext_double_to_x86_fp80:
+; GLOBAL-X86: # %bb.0:
+; GLOBAL-X86-NEXT: pushl %ebp
+; GLOBAL-X86-NEXT: .cfi_def_cfa_offset 8
+; GLOBAL-X86-NEXT: .cfi_offset %ebp, -8
+; GLOBAL-X86-NEXT: movl %esp, %ebp
+; GLOBAL-X86-NEXT: .cfi_def_cfa_register %ebp
+; GLOBAL-X86-NEXT: andl $-8, %esp
+; GLOBAL-X86-NEXT: subl $8, %esp
+; GLOBAL-X86-NEXT: leal 8(%ebp), %eax
+; GLOBAL-X86-NEXT: movl 8(%ebp), %ecx
+; GLOBAL-X86-NEXT: movl 4(%eax), %eax
+; GLOBAL-X86-NEXT: movl %esp, %edx
+; GLOBAL-X86-NEXT: movl %ecx, (%esp)
+; GLOBAL-X86-NEXT: movl %eax, 4(%edx)
+; GLOBAL-X86-NEXT: fldl (%esp)
+; GLOBAL-X86-NEXT: movl %ebp, %esp
+; GLOBAL-X86-NEXT: popl %ebp
+; GLOBAL-X86-NEXT: .cfi_def_cfa %esp, 4
+; GLOBAL-X86-NEXT: retl
+;
+; GLOBAL-SSE-LABEL: fpext_double_to_x86_fp80:
+; GLOBAL-SSE: # %bb.0:
+; GLOBAL-SSE-NEXT: movq %xmm0, %rax
+; GLOBAL-SSE-NEXT: movq %rax, -{{[0-9]+}}(%rsp)
+; GLOBAL-SSE-NEXT: fldl -{{[0-9]+}}(%rsp)
+; GLOBAL-SSE-NEXT: retq
+;
+; GLOBAL-AVX-LABEL: fpext_double_to_x86_fp80:
+; GLOBAL-AVX: # %bb.0:
+; GLOBAL-AVX-NEXT: vmovq %xmm0, %rax
+; GLOBAL-AVX-NEXT: movq %rax, -{{[0-9]+}}(%rsp)
+; GLOBAL-AVX-NEXT: fldl -{{[0-9]+}}(%rsp)
+; GLOBAL-AVX-NEXT: retq
%1 = fpext double %d to x86_fp80
ret x86_fp80 %1
}
define float @fptrunc_double_to_float(double %d) {
-; X86-LABEL: fptrunc_double_to_float:
-; X86: # %bb.0:
-; X86-NEXT: pushl %eax
-; X86-NEXT: .cfi_def_cfa_offset 8
-; X86-NEXT: fldl {{[0-9]+}}(%esp)
-; X86-NEXT: fstps (%esp)
-; X86-NEXT: flds (%esp)
-; X86-NEXT: popl %eax
-; X86-NEXT: .cfi_def_cfa_offset 4
-; X86-NEXT: retl
+; FASTSDAG-X86-LABEL: fptrunc_double_to_float:
+; FASTSDAG-X86: # %bb.0:
+; FASTSDAG-X86-NEXT: pushl %eax
+; FASTSDAG-X86-NEXT: .cfi_def_cfa_offset 8
+; FASTSDAG-X86-NEXT: fldl {{[0-9]+}}(%esp)
+; FASTSDAG-X86-NEXT: fstps (%esp)
+; FASTSDAG-X86-NEXT: flds (%esp)
+; FASTSDAG-X86-NEXT: popl %eax
+; FASTSDAG-X86-NEXT: .cfi_def_cfa_offset 4
+; FASTSDAG-X86-NEXT: retl
;
; SSE-LABEL: fptrunc_double_to_float:
; SSE: # %bb.0:
@@ -95,6 +156,21 @@ define float @fptrunc_double_to_float(double %d) {
; AVX: # %bb.0:
; AVX-NEXT: vcvtsd2ss %xmm0, %xmm0, %xmm0
; AVX-NEXT: retq
+;
+; GLOBAL-X86-LABEL: fptrunc_double_to_float:
+; GLOBAL-X86: # %bb.0:
+; GLOBAL-X86-NEXT: pushl %eax
+; GLOBAL-X86-NEXT: .cfi_def_cfa_offset 8
+; GLOBAL-X86-NEXT: leal {{[0-9]+}}(%esp), %eax
+; GLOBAL-X86-NEXT: movl {{[0-9]+}}(%esp), %ecx
+; GLOBAL-X86-NEXT: movl 4(%eax), %eax
+; GLOBAL-X86-NEXT: movl %esp, %edx
+; GLOBAL-X86-NEXT: movl %ecx, (%esp)
+; GLOBAL-X86-NEXT: movl %eax, 4(%edx)
+; GLOBAL-X86-NEXT: flds (%esp)
+; GLOBAL-X86-NEXT: popl %eax
+; GLOBAL-X86-NEXT: .cfi_def_cfa_offset 4
+; GLOBAL-X86-NEXT: retl
%1 = fptrunc double %d to float
ret float %1
}
@@ -111,19 +187,35 @@ define float @fptrunc_x86_fp80_to_float(x86_fp80 %x) {
; X86-NEXT: .cfi_def_cfa_offset 4
; X86-NEXT: retl
;
-; SSE-LABEL: fptrunc_x86_fp80_to_float:
-; SSE: # %bb.0:
-; SSE-NEXT: fldt {{[0-9]+}}(%rsp)
-; SSE-NEXT: fstps -{{[0-9]+}}(%rsp)
-; SSE-NEXT: movss {{.*#+}} xmm0 = mem[0],zero,zero,zero
-; SSE-NEXT: retq
+; FASTSDAG-SSE-LABEL: fptrunc_x86_fp80_to_float:
+; FASTSDAG-SSE: # %bb.0:
+; FASTSDAG-SSE-NEXT: fldt {{[0-9]+}}(%rsp)
+; FASTSDAG-SSE-NEXT: fstps -{{[0-9]+}}(%rsp)
+; FASTSDAG-SSE-NEXT: movss {{.*#+}} xmm0 = mem[0],zero,zero,zero
+; FASTSDAG-SSE-NEXT: retq
;
-; AVX-LABEL: fptrunc_x86_fp80_to_float:
-; AVX: # %bb.0:
-; AVX-NEXT: fldt {{[0-9]+}}(%rsp)
-; AVX-NEXT: fstps -{{[0-9]+}}(%rsp)
-; AVX-NEXT: vmovss {{.*#+}} xmm0 = mem[0],zero,zero,zero
-; AVX-NEXT: retq
+; FASTSDAG-AVX-LABEL: fptrunc_x86_fp80_to_float:
+; FASTSDAG-AVX: # %bb.0:
+; FASTSDAG-AVX-NEXT: fldt {{[0-9]+}}(%rsp)
+; FASTSDAG-AVX-NEXT: fstps -{{[0-9]+}}(%rsp)
+; FASTSDAG-AVX-NEXT: vmovss {{.*#+}} xmm0 = mem[0],zero,zero,zero
+; FASTSDAG-AVX-NEXT: retq
+;
+; GLOBAL-SSE-LABEL: fptrunc_x86_fp80_to_float:
+; GLOBAL-SSE: # %bb.0:
+; GLOBAL-SSE-NEXT: fldt {{[0-9]+}}(%rsp)
+; GLOBAL-SSE-NEXT: fstps -{{[0-9]+}}(%rsp)
+; GLOBAL-SSE-NEXT: movl -{{[0-9]+}}(%rsp), %eax
+; GLOBAL-SSE-NEXT: movd %eax, %xmm0
+; GLOBAL-SSE-NEXT: retq
+;
+; GLOBAL-AVX-LABEL: fptrunc_x86_fp80_to_float:
+; GLOBAL-AVX: # %bb.0:
+; GLOBAL-AVX-NEXT: fldt {{[0-9]+}}(%rsp)
+; GLOBAL-AVX-NEXT: fstps -{{[0-9]+}}(%rsp)
+; GLOBAL-AVX-NEXT: movl -{{[0-9]+}}(%rsp), %eax
+; GLOBAL-AVX-NEXT: vmovd %eax, %xmm0
+; GLOBAL-AVX-NEXT: retq
%1 = fptrunc x86_fp80 %x to float
ret float %1
}
@@ -146,19 +238,35 @@ define double @fptrunc_x86_fp80_to_double(x86_fp80 %x) {
; X86-NEXT: .cfi_def_cfa %esp, 4
; X86-NEXT: retl
;
-; SSE-LABEL: fptrunc_x86_fp80_to_double:
-; SSE: # %bb.0:
-; SSE-NEXT: fldt {{[0-9]+}}(%rsp)
-; SSE-NEXT: fstpl -{{[0-9]+}}(%rsp)
-; SSE-NEXT: movsd {{.*#+}} xmm0 = mem[0],zero
-; SSE-NEXT: retq
+; FASTSDAG-SSE-LABEL: fptrunc_x86_fp80_to_double:
+; FASTSDAG-SSE: # %bb.0:
+; FASTSDAG-SSE-NEXT: fldt {{[0-9]+}}(%rsp)
+; FASTSDAG-SSE-NEXT: fstpl -{{[0-9]+}}(%rsp)
+; FASTSDAG-SSE-NEXT: movsd {{.*#+}} xmm0 = mem[0],zero
+; FASTSDAG-SSE-NEXT: retq
;
-; AVX-LABEL: fptrunc_x86_fp80_to_double:
-; AVX: # %bb.0:
-; AVX-NEXT: fldt {{[0-9]+}}(%rsp)
-; AVX-NEXT: fstpl -{{[0-9]+}}(%rsp)
-; AVX-NEXT: vmovsd {{.*#+}} xmm0 = mem[0],zero
-; AVX-NEXT: retq
+; FASTSDAG-AVX-LABEL: fptrunc_x86_fp80_to_double:
+; FASTSDAG-AVX: # %bb.0:
+; FASTSDAG-AVX-NEXT: fldt {{[0-9]+}}(%rsp)
+; FASTSDAG-AVX-NEXT: fstpl -{{[0-9]+}}(%rsp)
+; FASTSDAG-AVX-NEXT: vmovsd {{.*#+}} xmm0 = mem[0],zero
+; FASTSDAG-AVX-NEXT: retq
+;
+; GLOBAL-SSE-LABEL: fptrunc_x86_fp80_to_double:
+; GLOBAL-SSE: # %bb.0:
+; GLOBAL-SSE-NEXT: fldt {{[0-9]+}}(%rsp)
+; GLOBAL-SSE-NEXT: fstpl -{{[0-9]+}}(%rsp)
+; GLOBAL-SSE-NEXT: movq -{{[0-9]+}}(%rsp), %rax
+; GLOBAL-SSE-NEXT: movq %rax, %xmm0
+; GLOBAL-SSE-NEXT: retq
+;
+; GLOBAL-AVX-LABEL: fptrunc_x86_fp80_to_double:
+; GLOBAL-AVX: # %bb.0:
+; GLOBAL-AVX-NEXT: fldt {{[0-9]+}}(%rsp)
+; GLOBAL-AVX-NEXT: fstpl -{{[0-9]+}}(%rsp)
+; GLOBAL-AVX-NEXT: movq -{{[0-9]+}}(%rsp), %rax
+; GLOBAL-AVX-NEXT: vmovq %rax, %xmm0
+; GLOBAL-AVX-NEXT: retq
%1 = fptrunc x86_fp80 %x to double
ret double %1
}
@@ -166,12 +274,6 @@ define double @fptrunc_x86_fp80_to_double(x86_fp80 %x) {
; FAST-AVX: {{.*}}
; FAST-SSE: {{.*}}
; FAST-X86: {{.*}}
-; FASTSDAG-AVX: {{.*}}
-; FASTSDAG-SSE: {{.*}}
-; FASTSDAG-X86: {{.*}}
-; GLOBAL-AVX: {{.*}}
-; GLOBAL-SSE: {{.*}}
-; GLOBAL-X86: {{.*}}
; SDAG-AVX: {{.*}}
; SDAG-SSE: {{.*}}
; SDAG-X86: {{.*}}
>From 80998165bbd4f2d12444ce89c5238d260bac45b3 Mon Sep 17 00:00:00 2001
From: Evgenii Kudriashov <evgenii.kudriashov at intel.com>
Date: Thu, 25 Sep 2025 18:05:47 -0700
Subject: [PATCH 3/6] Generalize FPTRUNC/FPEXT lowering using mem
---
.../llvm/CodeGen/GlobalISel/LegalizerHelper.h | 1 +
.../llvm/CodeGen/GlobalISel/LegalizerInfo.h | 6 ++++
.../CodeGen/GlobalISel/LegalizerHelper.cpp | 31 ++++++++++++++++-
.../lib/Target/X86/GISel/X86LegalizerInfo.cpp | 34 ++-----------------
llvm/lib/Target/X86/GISel/X86LegalizerInfo.h | 3 --
5 files changed, 39 insertions(+), 36 deletions(-)
diff --git a/llvm/include/llvm/CodeGen/GlobalISel/LegalizerHelper.h b/llvm/include/llvm/CodeGen/GlobalISel/LegalizerHelper.h
index 22569aab236af..690f40c51fdd2 100644
--- a/llvm/include/llvm/CodeGen/GlobalISel/LegalizerHelper.h
+++ b/llvm/include/llvm/CodeGen/GlobalISel/LegalizerHelper.h
@@ -483,6 +483,7 @@ class LegalizerHelper {
LLVM_ABI LegalizeResult lowerFPTOSI(MachineInstr &MI);
LLVM_ABI LegalizeResult lowerFPTOINT_SAT(MachineInstr &MI);
+ LLVM_ABI LegalizeResult lowerFPExtAndTruncMem(MachineInstr &MI);
LLVM_ABI LegalizeResult lowerFPTRUNC_F64_TO_F16(MachineInstr &MI);
LLVM_ABI LegalizeResult lowerFPTRUNC(MachineInstr &MI);
LLVM_ABI LegalizeResult lowerFPOWI(MachineInstr &MI);
diff --git a/llvm/include/llvm/CodeGen/GlobalISel/LegalizerInfo.h b/llvm/include/llvm/CodeGen/GlobalISel/LegalizerInfo.h
index fd72a3898562e..836e87de6f62d 100644
--- a/llvm/include/llvm/CodeGen/GlobalISel/LegalizerInfo.h
+++ b/llvm/include/llvm/CodeGen/GlobalISel/LegalizerInfo.h
@@ -742,6 +742,12 @@ class LegalizeRuleSet {
LegalizeRuleSet &lowerFor(std::initializer_list<std::pair<LLT, LLT>> Types) {
return actionFor(LegalizeAction::Lower, Types);
}
+ LegalizeRuleSet &lowerFor(bool Pred,
+ std::initializer_list<std::pair<LLT, LLT>> Types) {
+ if (!Pred)
+ return *this;
+ return actionFor(LegalizeAction::Lower, Types);
+ }
/// The instruction is lowered when type indexes 0 and 1 is any type pair in
/// the given list.
LegalizeRuleSet &lowerFor(std::initializer_list<std::pair<LLT, LLT>> Types,
diff --git a/llvm/lib/CodeGen/GlobalISel/LegalizerHelper.cpp b/llvm/lib/CodeGen/GlobalISel/LegalizerHelper.cpp
index f3e036ed1b947..86ca857f92f24 100644
--- a/llvm/lib/CodeGen/GlobalISel/LegalizerHelper.cpp
+++ b/llvm/lib/CodeGen/GlobalISel/LegalizerHelper.cpp
@@ -4667,6 +4667,8 @@ LegalizerHelper::lower(MachineInstr &MI, unsigned TypeIdx, LLT LowerHintTy) {
case G_FPTOUI_SAT:
case G_FPTOSI_SAT:
return lowerFPTOINT_SAT(MI);
+ case G_FPEXT:
+ return lowerFPExtAndTruncMem(MI);
case G_FPTRUNC:
return lowerFPTRUNC(MI);
case G_FPOWI:
@@ -8408,6 +8410,33 @@ LegalizerHelper::lowerFPTOINT_SAT(MachineInstr &MI) {
return Legalized;
}
+// fp conversions using truncating and extending loads and stores.
+LegalizerHelper::LegalizeResult
+LegalizerHelper::lowerFPExtAndTruncMem(MachineInstr &MI) {
+ assert((MI.getOpcode() == TargetOpcode::G_FPEXT ||
+ MI.getOpcode() == TargetOpcode::G_FPTRUNC) &&
+ "Only G_FPEXT and G_FPTRUNC are expected");
+
+ auto [DstReg, DstTy, SrcReg, SrcTy] = MI.getFirst2RegLLTs();
+ MachinePointerInfo PtrInfo;
+ LLT StackTy = MI.getOpcode() == TargetOpcode::G_FPEXT ? SrcTy : DstTy;
+ Align StackTyAlign = getStackTemporaryAlignment(StackTy);
+ auto StackTemp =
+ createStackTemporary(StackTy.getSizeInBytes(), StackTyAlign, PtrInfo);
+
+ MachineFunction &MF = MIRBuilder.getMF();
+ auto *StoreMMO = MF.getMachineMemOperand(PtrInfo, MachineMemOperand::MOStore,
+ StackTy, StackTyAlign);
+ MIRBuilder.buildStore(SrcReg, StackTemp, *StoreMMO);
+
+ auto *LoadMMO = MF.getMachineMemOperand(PtrInfo, MachineMemOperand::MOLoad,
+ StackTy, StackTyAlign);
+ MIRBuilder.buildLoad(DstReg, StackTemp, *LoadMMO);
+
+ MI.eraseFromParent();
+ return Legalized;
+}
+
// f64 -> f16 conversion using round-to-nearest-even rounding mode.
LegalizerHelper::LegalizeResult
LegalizerHelper::lowerFPTRUNC_F64_TO_F16(MachineInstr &MI) {
@@ -8533,7 +8562,7 @@ LegalizerHelper::lowerFPTRUNC(MachineInstr &MI) {
if (DstTy.getScalarType() == S16 && SrcTy.getScalarType() == S64)
return lowerFPTRUNC_F64_TO_F16(MI);
- return UnableToLegalize;
+ return lowerFPExtAndTruncMem(MI);
}
LegalizerHelper::LegalizeResult LegalizerHelper::lowerFPOWI(MachineInstr &MI) {
diff --git a/llvm/lib/Target/X86/GISel/X86LegalizerInfo.cpp b/llvm/lib/Target/X86/GISel/X86LegalizerInfo.cpp
index 128ffbf7e49c3..e9bc5834ea69c 100644
--- a/llvm/lib/Target/X86/GISel/X86LegalizerInfo.cpp
+++ b/llvm/lib/Target/X86/GISel/X86LegalizerInfo.cpp
@@ -447,13 +447,13 @@ X86LegalizerInfo::X86LegalizerInfo(const X86Subtarget &STI,
.legalFor(HasSSE2, {{s64, s32}})
.legalFor(HasAVX, {{v4s64, v4s32}})
.legalFor(HasAVX512, {{v8s64, v8s32}})
- .customFor(UseX87, {{s64, s32}, {s80, s32}, {s80, s64}});
+ .lowerFor(UseX87, {{s64, s32}, {s80, s32}, {s80, s64}});
getActionDefinitionsBuilder(G_FPTRUNC)
.legalFor(HasSSE2, {{s32, s64}})
.legalFor(HasAVX, {{v4s32, v4s64}})
.legalFor(HasAVX512, {{v8s32, v8s64}})
- .customFor(UseX87, {{s32, s64}, {s32, s80}, {s64, s80}});
+ .lowerFor(UseX87, {{s32, s64}, {s32, s80}, {s64, s80}});
getActionDefinitionsBuilder(G_SITOFP)
.legalFor(HasSSE1, {{s32, s32}})
@@ -623,9 +623,6 @@ bool X86LegalizerInfo::legalizeCustom(LegalizerHelper &Helper, MachineInstr &MI,
return legalizeSITOFP(MI, MRI, Helper);
case TargetOpcode::G_FPTOSI:
return legalizeFPTOSI(MI, MRI, Helper);
- case TargetOpcode::G_FPEXT:
- case TargetOpcode::G_FPTRUNC:
- return legalizeFPExtAndTrunc(MI, MRI, Helper);
case TargetOpcode::G_GET_ROUNDING:
return legalizeGETROUNDING(MI, MRI, Helper);
}
@@ -870,33 +867,6 @@ bool X86LegalizerInfo::legalizeGETROUNDING(MachineInstr &MI,
return true;
}
-bool X86LegalizerInfo::legalizeFPExtAndTrunc(MachineInstr &MI,
- MachineRegisterInfo &MRI,
- LegalizerHelper &Helper) const {
- assert((MI.getOpcode() == TargetOpcode::G_FPEXT ||
- MI.getOpcode() == TargetOpcode::G_FPTRUNC) &&
- "Only G_FPEXT and G_FPTRUNC are expected");
- auto [DstReg, DstTy, SrcReg, SrcTy] = MI.getFirst2RegLLTs();
- MachinePointerInfo PtrInfo;
- LLT StackTy = MI.getOpcode() == TargetOpcode::G_FPEXT ? SrcTy : DstTy;
- Align StackTyAlign = Helper.getStackTemporaryAlignment(StackTy);
- auto StackTemp = Helper.createStackTemporary(StackTy.getSizeInBytes(),
- StackTyAlign, PtrInfo);
-
- MachineIRBuilder &MIRBuilder = Helper.MIRBuilder;
- MachineFunction &MF = MIRBuilder.getMF();
- auto *StoreMMO = MF.getMachineMemOperand(PtrInfo, MachineMemOperand::MOStore,
- StackTy, StackTyAlign);
- MIRBuilder.buildStore(SrcReg, StackTemp, *StoreMMO);
-
- auto *LoadMMO = MF.getMachineMemOperand(PtrInfo, MachineMemOperand::MOLoad,
- StackTy, StackTyAlign);
- MIRBuilder.buildLoad(DstReg, StackTemp, *LoadMMO);
-
- MI.eraseFromParent();
- return true;
-}
-
bool X86LegalizerInfo::legalizeIntrinsic(LegalizerHelper &Helper,
MachineInstr &MI) const {
return true;
diff --git a/llvm/lib/Target/X86/GISel/X86LegalizerInfo.h b/llvm/lib/Target/X86/GISel/X86LegalizerInfo.h
index 7c00531d371e7..0003552d70ee0 100644
--- a/llvm/lib/Target/X86/GISel/X86LegalizerInfo.h
+++ b/llvm/lib/Target/X86/GISel/X86LegalizerInfo.h
@@ -57,9 +57,6 @@ class X86LegalizerInfo : public LegalizerInfo {
bool legalizeGETROUNDING(MachineInstr &MI, MachineRegisterInfo &MRI,
LegalizerHelper &Helper) const;
-
- bool legalizeFPExtAndTrunc(MachineInstr &MI, MachineRegisterInfo &MRI,
- LegalizerHelper &Helper) const;
};
} // namespace llvm
#endif
>From 86ce2c00b23771f1c63db7995cfbcbd90941b037 Mon Sep 17 00:00:00 2001
From: Evgenii Kudriashov <evgenii.kudriashov at intel.com>
Date: Sat, 20 Dec 2025 02:46:54 +0100
Subject: [PATCH 4/6] Wording for FP
Co-authored-by: Matt Arsenault <arsenm2 at gmail.com>
---
llvm/lib/CodeGen/GlobalISel/LegalizerHelper.cpp | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/llvm/lib/CodeGen/GlobalISel/LegalizerHelper.cpp b/llvm/lib/CodeGen/GlobalISel/LegalizerHelper.cpp
index fdfeb1a5ec5b2..652b066099de8 100644
--- a/llvm/lib/CodeGen/GlobalISel/LegalizerHelper.cpp
+++ b/llvm/lib/CodeGen/GlobalISel/LegalizerHelper.cpp
@@ -8502,7 +8502,7 @@ LegalizerHelper::lowerFPTOINT_SAT(MachineInstr &MI) {
return Legalized;
}
-// fp conversions using truncating and extending loads and stores.
+// Floating-point conversions using truncating and extending loads and stores.
LegalizerHelper::LegalizeResult
LegalizerHelper::lowerFPExtAndTruncMem(MachineInstr &MI) {
assert((MI.getOpcode() == TargetOpcode::G_FPEXT ||
>From 1c16d73b582d2d6a269af0c75390d2927421a5cc Mon Sep 17 00:00:00 2001
From: Evgenii Kudriashov <evgenii.kudriashov at intel.com>
Date: Sun, 11 Jan 2026 05:48:23 -0800
Subject: [PATCH 5/6] Support G_FPEXTLOAD and G_FPTRUNCSTORE
---
llvm/docs/GlobalISel/GenericOpcode.rst | 30 ++++
.../CodeGen/GlobalISel/GenericMachineInstrs.h | 48 ++++++-
.../llvm/CodeGen/GlobalISel/LegalizerInfo.h | 9 ++
.../CodeGen/GlobalISel/MachineIRBuilder.h | 13 ++
llvm/include/llvm/Support/TargetOpcodes.def | 6 +
llvm/include/llvm/Target/GenericOpcodes.td | 18 +++
.../Target/GlobalISel/SelectionDAGCompat.td | 12 +-
.../CodeGen/GlobalISel/LegalizerHelper.cpp | 57 +++++++-
.../CodeGen/GlobalISel/MachineIRBuilder.cpp | 14 ++
llvm/lib/CodeGen/GlobalISel/Utils.cpp | 2 +
llvm/lib/CodeGen/MachineVerifier.cpp | 13 +-
.../lib/Target/X86/GISel/X86LegalizerInfo.cpp | 14 +-
.../Target/X86/GISel/X86RegisterBankInfo.cpp | 2 +
.../GlobalISel/legalizer-info-validation.mir | 7 +-
.../Inputs/reference_x86_vocab_print.txt | 2 +
.../reference_x86_vocab_wo=0.5_print.txt | 2 +
.../GlobalISel/legalizer-info-validation.mir | 7 +-
llvm/test/CodeGen/X86/isel-fptrunc-fpext.ll | 54 ++++---
.../test/MachineVerifier/test_g_fpextload.mir | 28 ++++
.../MachineVerifier/test_g_fptruncstore.mir | 32 +++++
.../match-table-cxx.td | 132 +++++++++---------
.../GlobalISelEmitter/GlobalISelEmitter.td | 2 +-
llvm/test/TableGen/RegClassByHwMode.td | 28 ++--
llvm/utils/TableGen/GlobalISelEmitter.cpp | 14 ++
24 files changed, 410 insertions(+), 136 deletions(-)
create mode 100644 llvm/test/MachineVerifier/test_g_fpextload.mir
create mode 100644 llvm/test/MachineVerifier/test_g_fptruncstore.mir
diff --git a/llvm/docs/GlobalISel/GenericOpcode.rst b/llvm/docs/GlobalISel/GenericOpcode.rst
index 329d9d13ebddd..35a8df99bcfde 100644
--- a/llvm/docs/GlobalISel/GenericOpcode.rst
+++ b/llvm/docs/GlobalISel/GenericOpcode.rst
@@ -919,6 +919,21 @@ Unlike in SelectionDAG, atomic loads are expressed with the same
opcodes as regular loads. G_LOAD, G_SEXTLOAD and G_ZEXTLOAD may all
have atomic memory operands.
+G_FPEXTLOAD
+^^^^^^^^^^^
+
+Generic floating-point extending load. Expects a MachineMemOperand in addition
+to explicit operands. Loads a floating-point value from memory and extends it
+to a larger floating-point type.
+
+The memory size must be smaller than the result type. For example, loading an
+f32 value from memory and extending it to f64, or loading an f16 value and
+extending it to f32.
+
+.. code-block:: none
+
+ %1:_(s64) = G_FPEXTLOAD %0:_(p0) :: (load (s32))
+
G_INDEXED_LOAD
^^^^^^^^^^^^^^
@@ -945,6 +960,21 @@ the high bits are implicitly truncated. If this is a vector store, the
high elements are discarded (i.e. this does not function as a per-lane
vector, truncating store)
+G_FPTRUNCSTORE
+^^^^^^^^^^^^^^
+
+Generic floating-point truncating store. Expects a MachineMemOperand in
+addition to explicit operands. Truncates a floating-point value to a smaller
+floating-point type and stores it to memory.
+
+The memory size must be smaller than the source value type. For example,
+truncating an f64 value to f32 and storing it, or truncating an f32 value
+to f16 and storing it.
+
+.. code-block:: none
+
+ G_FPTRUNCSTORE %0:_(s64), %1:_(p0) :: (store (s32))
+
G_INDEXED_STORE
^^^^^^^^^^^^^^^
diff --git a/llvm/include/llvm/CodeGen/GlobalISel/GenericMachineInstrs.h b/llvm/include/llvm/CodeGen/GlobalISel/GenericMachineInstrs.h
index 5faf57fd06228..e708d399bc25f 100644
--- a/llvm/include/llvm/CodeGen/GlobalISel/GenericMachineInstrs.h
+++ b/llvm/include/llvm/CodeGen/GlobalISel/GenericMachineInstrs.h
@@ -80,7 +80,7 @@ class GMemOperation : public GenericMachineInstr {
};
/// Represents any type of generic load or store.
-/// G_LOAD, G_STORE, G_ZEXTLOAD, G_SEXTLOAD.
+/// G_LOAD, G_STORE, G_ZEXTLOAD, G_SEXTLOAD, G_FPEXTLOAD, G_FPTRUNCSTORE.
class GLoadStore : public GMemOperation {
public:
/// Get the source register of the pointer value.
@@ -92,6 +92,8 @@ class GLoadStore : public GMemOperation {
case TargetOpcode::G_STORE:
case TargetOpcode::G_ZEXTLOAD:
case TargetOpcode::G_SEXTLOAD:
+ case TargetOpcode::G_FPEXTLOAD:
+ case TargetOpcode::G_FPTRUNCSTORE:
return true;
default:
return false;
@@ -145,7 +147,7 @@ class GIndexedAnyExtLoad : public GIndexedLoad {
}
};
-/// Represents a G_ZEXTLOAD.
+/// Represents a G_INDEXED_ZEXTLOAD.
class GIndexedZExtLoad : GIndexedExtLoad {
public:
static bool classof(const MachineInstr *MI) {
@@ -153,7 +155,7 @@ class GIndexedZExtLoad : GIndexedExtLoad {
}
};
-/// Represents a G_SEXTLOAD.
+/// Represents a G_INDEXED_SEXTLOAD.
class GIndexedSExtLoad : GIndexedExtLoad {
public:
static bool classof(const MachineInstr *MI) {
@@ -197,6 +199,7 @@ class GAnyLoad : public GLoadStore {
case TargetOpcode::G_LOAD:
case TargetOpcode::G_ZEXTLOAD:
case TargetOpcode::G_SEXTLOAD:
+ case TargetOpcode::G_FPEXTLOAD:
return true;
default:
return false;
@@ -212,12 +215,13 @@ class GLoad : public GAnyLoad {
}
};
-/// Represents either a G_SEXTLOAD or G_ZEXTLOAD.
+/// Represents either a G_SEXTLOAD, G_ZEXTLOAD, or G_FPEXTLOAD.
class GExtLoad : public GAnyLoad {
public:
static bool classof(const MachineInstr *MI) {
return MI->getOpcode() == TargetOpcode::G_SEXTLOAD ||
- MI->getOpcode() == TargetOpcode::G_ZEXTLOAD;
+ MI->getOpcode() == TargetOpcode::G_ZEXTLOAD ||
+ MI->getOpcode() == TargetOpcode::G_FPEXTLOAD;
}
};
@@ -237,17 +241,47 @@ class GZExtLoad : public GExtLoad {
}
};
-/// Represents a G_STORE.
-class GStore : public GLoadStore {
+/// Represents a G_FPEXTLOAD.
+class GFPExtLoad : public GAnyLoad {
+public:
+ static bool classof(const MachineInstr *MI) {
+ return MI->getOpcode() == TargetOpcode::G_FPEXTLOAD;
+ }
+};
+
+/// Represents any generic store, including truncating variants.
+class GAnyStore : public GLoadStore {
public:
/// Get the stored value register.
Register getValueReg() const { return getOperand(0).getReg(); }
+ static bool classof(const MachineInstr *MI) {
+ switch (MI->getOpcode()) {
+ case TargetOpcode::G_STORE:
+ case TargetOpcode::G_FPTRUNCSTORE:
+ return true;
+ default:
+ return false;
+ }
+ }
+};
+
+/// Represents a G_STORE.
+class GStore : public GAnyStore {
+public:
static bool classof(const MachineInstr *MI) {
return MI->getOpcode() == TargetOpcode::G_STORE;
}
};
+/// Represents a G_FPTRUNCSTORE.
+class GFPTruncStore : public GAnyStore {
+public:
+ static bool classof(const MachineInstr *MI) {
+ return MI->getOpcode() == TargetOpcode::G_FPTRUNCSTORE;
+ }
+};
+
/// Represents a G_UNMERGE_VALUES.
class GUnmerge : public GenericMachineInstr {
public:
diff --git a/llvm/include/llvm/CodeGen/GlobalISel/LegalizerInfo.h b/llvm/include/llvm/CodeGen/GlobalISel/LegalizerInfo.h
index 41d59d6fd567a..b27cde8fd31cc 100644
--- a/llvm/include/llvm/CodeGen/GlobalISel/LegalizerInfo.h
+++ b/llvm/include/llvm/CodeGen/GlobalISel/LegalizerInfo.h
@@ -680,6 +680,15 @@ class LegalizeRuleSet {
LegalityPredicates::typePairAndMemDescInSet(
typeIdx(0), typeIdx(1), /*MMOIdx*/ 0, TypesAndMemDesc));
}
+ LegalizeRuleSet &legalForTypesWithMemDesc(
+ bool Pred, std::initializer_list<LegalityPredicates::TypePairAndMemDesc>
+ TypesAndMemDesc) {
+ if (!Pred)
+ return *this;
+ return actionIf(LegalizeAction::Legal,
+ LegalityPredicates::typePairAndMemDescInSet(
+ typeIdx(0), typeIdx(1), /*MMOIdx*/ 0, TypesAndMemDesc));
+ }
/// The instruction is legal when type indexes 0 and 1 are both in the given
/// list. That is, the type pair is in the cartesian product of the list.
LegalizeRuleSet &legalForCartesianProduct(std::initializer_list<LLT> Types) {
diff --git a/llvm/include/llvm/CodeGen/GlobalISel/MachineIRBuilder.h b/llvm/include/llvm/CodeGen/GlobalISel/MachineIRBuilder.h
index 5f3f1d386569c..30cc5a7d6fbf5 100644
--- a/llvm/include/llvm/CodeGen/GlobalISel/MachineIRBuilder.h
+++ b/llvm/include/llvm/CodeGen/GlobalISel/MachineIRBuilder.h
@@ -1083,6 +1083,19 @@ class LLVM_ABI MachineIRBuilder {
MachineInstrBuilder buildStore(const SrcOp &Val, const SrcOp &Addr,
MachineMemOperand &MMO);
+ /// Build and insert `<opcode> Val, Addr, MMO`.
+ ///
+ /// Stores the value \p Val to \p Addr.
+ ///
+ /// \pre setBasicBlock or setMI must have been called.
+ /// \pre \p Val must be a generic virtual register.
+ /// \pre \p Addr must be a generic virtual register with pointer type.
+ ///
+ /// \return a MachineInstrBuilder for the newly created instruction.
+ MachineInstrBuilder buildStoreInstr(unsigned Opcode, const SrcOp &Val,
+ const SrcOp &Addr,
+ MachineMemOperand &MMO);
+
/// Build and insert a G_STORE instruction, while constructing the
/// MachineMemOperand.
MachineInstrBuilder
diff --git a/llvm/include/llvm/Support/TargetOpcodes.def b/llvm/include/llvm/Support/TargetOpcodes.def
index 0d92f50a09d38..d20c66417ffcd 100644
--- a/llvm/include/llvm/Support/TargetOpcodes.def
+++ b/llvm/include/llvm/Support/TargetOpcodes.def
@@ -409,6 +409,9 @@ HANDLE_TARGET_OPCODE(G_SEXTLOAD)
/// Generic zeroext load
HANDLE_TARGET_OPCODE(G_ZEXTLOAD)
+/// Generic floating-point extending load
+HANDLE_TARGET_OPCODE(G_FPEXTLOAD)
+
/// Generic indexed load (including anyext load)
HANDLE_TARGET_OPCODE(G_INDEXED_LOAD)
@@ -421,6 +424,9 @@ HANDLE_TARGET_OPCODE(G_INDEXED_ZEXTLOAD)
/// Generic store.
HANDLE_TARGET_OPCODE(G_STORE)
+/// Generic floating-point truncating store
+HANDLE_TARGET_OPCODE(G_FPTRUNCSTORE)
+
/// Generic indexed store.
HANDLE_TARGET_OPCODE(G_INDEXED_STORE)
diff --git a/llvm/include/llvm/Target/GenericOpcodes.td b/llvm/include/llvm/Target/GenericOpcodes.td
index 1b65b8b73527d..5c85a41beae24 100644
--- a/llvm/include/llvm/Target/GenericOpcodes.td
+++ b/llvm/include/llvm/Target/GenericOpcodes.td
@@ -1346,6 +1346,15 @@ def G_ZEXTLOAD : GenericInstruction {
let mayLoad = true;
}
+// Generic floating-point extending load. Expects a MachineMemOperand in
+// addition to explicit operands.
+def G_FPEXTLOAD : GenericInstruction {
+ let OutOperandList = (outs type0:$dst);
+ let InOperandList = (ins ptype1:$addr);
+ let hasSideEffects = false;
+ let mayLoad = true;
+}
+
// Generic indexed load. Combines a GEP with a load. $newaddr is set to $base + $offset.
// If $am is 0 (post-indexed), then the value is loaded from $base; if $am is 1 (pre-indexed)
// then the value is loaded from $newaddr.
@@ -1380,6 +1389,15 @@ def G_STORE : GenericInstruction {
let mayStore = true;
}
+// Generic floating-point truncating store. Expects a MachineMemOperand in
+// addition to explicit operands.
+def G_FPTRUNCSTORE : GenericInstruction {
+ let OutOperandList = (outs);
+ let InOperandList = (ins type0:$src, ptype1:$addr);
+ let hasSideEffects = false;
+ let mayStore = true;
+}
+
// Combines a store with a GEP. See description of G_INDEXED_LOAD for indexing behaviour.
def G_INDEXED_STORE : GenericInstruction {
let OutOperandList = (outs ptype0:$newaddr);
diff --git a/llvm/include/llvm/Target/GlobalISel/SelectionDAGCompat.td b/llvm/include/llvm/Target/GlobalISel/SelectionDAGCompat.td
index a69e089779315..917a29db7448b 100644
--- a/llvm/include/llvm/Target/GlobalISel/SelectionDAGCompat.td
+++ b/llvm/include/llvm/Target/GlobalISel/SelectionDAGCompat.td
@@ -35,6 +35,11 @@ class GINodeEquiv<Instruction i, SDNode node> {
// depending on the predicates on the node.
Instruction IfSignExtend = ?;
Instruction IfZeroExtend = ?;
+ // In contrast to SelectionDAG we would like not to overload an anyext load
+ // for floating point truncation and extending stores and loads. Instead we
+ // assign separate opcodes for it.
+ Instruction IfFPExtend = ?;
+ Instruction IfFPTrunc = ?;
// SelectionDAG has one setcc for all compares. This differentiates
// for G_ICMP and G_FCMP.
@@ -235,6 +240,7 @@ def : GINodeEquiv<G_LOAD, ld> {
let CheckMMOIsNonAtomic = true;
let IfSignExtend = G_SEXTLOAD;
let IfZeroExtend = G_ZEXTLOAD;
+ let IfFPExtend = G_FPEXTLOAD;
}
def : GINodeEquiv<G_ICMP, setcc> {
@@ -248,7 +254,11 @@ def : GINodeEquiv<G_ICMP, setcc> {
// G_STORE handles both atomic and non-atomic stores where as SelectionDAG had
// separate nodes for them. This GINodeEquiv maps the non-atomic stores to
// G_STORE with a non-atomic MachineMemOperand.
-def : GINodeEquiv<G_STORE, st> { let CheckMMOIsNonAtomic = true; }
+def : GINodeEquiv<G_STORE, st> {
+ let CheckMMOIsNonAtomic = true;
+ let IfFPTrunc = G_FPTRUNCSTORE;
+}
+
def : GINodeEquiv<G_STORE, atomic_store> {
let CheckMMOIsNonAtomic = false;
let CheckMMOIsAtomic = true;
diff --git a/llvm/lib/CodeGen/GlobalISel/LegalizerHelper.cpp b/llvm/lib/CodeGen/GlobalISel/LegalizerHelper.cpp
index 42ae035758930..dd48ba80a7e8f 100644
--- a/llvm/lib/CodeGen/GlobalISel/LegalizerHelper.cpp
+++ b/llvm/lib/CodeGen/GlobalISel/LegalizerHelper.cpp
@@ -1687,7 +1687,8 @@ LegalizerHelper::LegalizeResult LegalizerHelper::narrowScalar(MachineInstr &MI,
return reduceLoadStoreWidth(LoadMI, TypeIdx, NarrowTy);
}
case TargetOpcode::G_ZEXTLOAD:
- case TargetOpcode::G_SEXTLOAD: {
+ case TargetOpcode::G_SEXTLOAD:
+ case TargetOpcode::G_FPEXTLOAD: {
auto &LoadMI = cast<GExtLoad>(MI);
Register DstReg = LoadMI.getDstReg();
Register PtrReg = LoadMI.getPointerReg();
@@ -1707,8 +1708,10 @@ LegalizerHelper::LegalizeResult LegalizerHelper::narrowScalar(MachineInstr &MI,
if (isa<GZExtLoad>(LoadMI))
MIRBuilder.buildZExt(DstReg, TmpReg);
- else
+ else if (isa<GSExtLoad>(LoadMI))
MIRBuilder.buildSExt(DstReg, TmpReg);
+ else
+ MIRBuilder.buildFPExt(DstReg, TmpReg);
LoadMI.eraseFromParent();
return Legalized;
@@ -1737,6 +1740,30 @@ LegalizerHelper::LegalizeResult LegalizerHelper::narrowScalar(MachineInstr &MI,
return reduceLoadStoreWidth(StoreMI, 0, NarrowTy);
}
+ case TargetOpcode::G_FPTRUNCSTORE: {
+ auto &StoreMI = cast<GFPTruncStore>(MI);
+ Register SrcReg = StoreMI.getValueReg();
+ Register PtrReg = StoreMI.getPointerReg();
+
+ auto &MMO = StoreMI.getMMO();
+ unsigned MemSize = MMO.getSizeInBits().getValue();
+ if (MemSize > NarrowSize) {
+ return UnableToLegalize;
+ }
+
+ auto TmpReg = MIRBuilder.buildFPTrunc(NarrowTy, SrcReg).getReg(0);
+ if (MemSize == NarrowSize) {
+ MIRBuilder.buildStore(TmpReg, PtrReg, MMO);
+ } else if (MemSize < NarrowSize) {
+ MIRBuilder.buildInstr(TargetOpcode::G_FPTRUNCSTORE)
+ .addUse(TmpReg)
+ .addUse(PtrReg)
+ .addMemOperand(&MMO);
+ }
+
+ StoreMI.eraseFromParent();
+ return Legalized;
+ }
case TargetOpcode::G_SELECT:
return narrowScalarSelect(MI, TypeIdx, NarrowTy);
case TargetOpcode::G_AND:
@@ -3147,6 +3174,7 @@ LegalizerHelper::widenScalar(MachineInstr &MI, unsigned TypeIdx, LLT WideTy) {
case TargetOpcode::G_LOAD:
case TargetOpcode::G_SEXTLOAD:
case TargetOpcode::G_ZEXTLOAD:
+ case TargetOpcode::G_FPEXTLOAD:
Observer.changingInstr(MI);
widenScalarDst(MI, WideTy);
Observer.changedInstr(MI);
@@ -3180,6 +3208,13 @@ LegalizerHelper::widenScalar(MachineInstr &MI, unsigned TypeIdx, LLT WideTy) {
Observer.changedInstr(MI);
return Legalized;
}
+ case TargetOpcode::G_FPTRUNCSTORE:
+ if (TypeIdx != 0)
+ return UnableToLegalize;
+ Observer.changingInstr(MI);
+ widenScalarSrc(MI, WideTy, 0, TargetOpcode::G_FPEXT);
+ Observer.changedInstr(MI);
+ return Legalized;
case TargetOpcode::G_CONSTANT: {
MachineOperand &SrcMO = MI.getOperand(1);
LLVMContext &Ctx = MIRBuilder.getMF().getFunction().getContext();
@@ -8517,7 +8552,19 @@ LegalizerHelper::lowerFPExtAndTruncMem(MachineInstr &MI) {
auto [DstReg, DstTy, SrcReg, SrcTy] = MI.getFirst2RegLLTs();
MachinePointerInfo PtrInfo;
- LLT StackTy = MI.getOpcode() == TargetOpcode::G_FPEXT ? SrcTy : DstTy;
+ unsigned StoreOpc;
+ unsigned LoadOpc;
+ LLT StackTy;
+ if (MI.getOpcode() == TargetOpcode::G_FPEXT) {
+ StackTy = SrcTy;
+ StoreOpc = TargetOpcode::G_STORE;
+ LoadOpc = TargetOpcode::G_FPEXTLOAD;
+ } else {
+ StackTy = DstTy;
+ StoreOpc = TargetOpcode::G_FPTRUNCSTORE;
+ LoadOpc = TargetOpcode::G_LOAD;
+ }
+
Align StackTyAlign = getStackTemporaryAlignment(StackTy);
auto StackTemp =
createStackTemporary(StackTy.getSizeInBytes(), StackTyAlign, PtrInfo);
@@ -8525,11 +8572,11 @@ LegalizerHelper::lowerFPExtAndTruncMem(MachineInstr &MI) {
MachineFunction &MF = MIRBuilder.getMF();
auto *StoreMMO = MF.getMachineMemOperand(PtrInfo, MachineMemOperand::MOStore,
StackTy, StackTyAlign);
- MIRBuilder.buildStore(SrcReg, StackTemp, *StoreMMO);
+ MIRBuilder.buildStoreInstr(StoreOpc, SrcReg, StackTemp, *StoreMMO);
auto *LoadMMO = MF.getMachineMemOperand(PtrInfo, MachineMemOperand::MOLoad,
StackTy, StackTyAlign);
- MIRBuilder.buildLoad(DstReg, StackTemp, *LoadMMO);
+ MIRBuilder.buildLoadInstr(LoadOpc, DstReg, StackTemp, *LoadMMO);
MI.eraseFromParent();
return Legalized;
diff --git a/llvm/lib/CodeGen/GlobalISel/MachineIRBuilder.cpp b/llvm/lib/CodeGen/GlobalISel/MachineIRBuilder.cpp
index 3906b311addf0..7e2f582779f5f 100644
--- a/llvm/lib/CodeGen/GlobalISel/MachineIRBuilder.cpp
+++ b/llvm/lib/CodeGen/GlobalISel/MachineIRBuilder.cpp
@@ -500,6 +500,20 @@ MachineInstrBuilder MachineIRBuilder::buildStore(const SrcOp &Val,
return MIB;
}
+MachineInstrBuilder MachineIRBuilder::buildStoreInstr(unsigned Opcode,
+ const SrcOp &Val,
+ const SrcOp &Addr,
+ MachineMemOperand &MMO) {
+ assert(Val.getLLTTy(*getMRI()).isValid() && "invalid operand type");
+ assert(Addr.getLLTTy(*getMRI()).isPointer() && "invalid operand type");
+
+ auto MIB = buildInstr(Opcode);
+ Val.addSrcToMIB(MIB);
+ Addr.addSrcToMIB(MIB);
+ MIB.addMemOperand(&MMO);
+ return MIB;
+}
+
MachineInstrBuilder
MachineIRBuilder::buildStore(const SrcOp &Val, const SrcOp &Addr,
MachinePointerInfo PtrInfo, Align Alignment,
diff --git a/llvm/lib/CodeGen/GlobalISel/Utils.cpp b/llvm/lib/CodeGen/GlobalISel/Utils.cpp
index 35e89cae9e929..c9c30b0601f3a 100644
--- a/llvm/lib/CodeGen/GlobalISel/Utils.cpp
+++ b/llvm/lib/CodeGen/GlobalISel/Utils.cpp
@@ -1777,8 +1777,10 @@ bool llvm::isPreISelGenericFloatingPointOpcode(unsigned Opc) {
case TargetOpcode::G_FNEARBYINT:
case TargetOpcode::G_FNEG:
case TargetOpcode::G_FPEXT:
+ case TargetOpcode::G_FPEXTLOAD:
case TargetOpcode::G_FPOW:
case TargetOpcode::G_FPTRUNC:
+ case TargetOpcode::G_FPTRUNCSTORE:
case TargetOpcode::G_FREM:
case TargetOpcode::G_FRINT:
case TargetOpcode::G_FSIN:
diff --git a/llvm/lib/CodeGen/MachineVerifier.cpp b/llvm/lib/CodeGen/MachineVerifier.cpp
index 5ce7606b051a5..d1d402ae042af 100644
--- a/llvm/lib/CodeGen/MachineVerifier.cpp
+++ b/llvm/lib/CodeGen/MachineVerifier.cpp
@@ -1254,7 +1254,9 @@ void MachineVerifier::verifyPreISelGenericInstruction(const MachineInstr *MI) {
case TargetOpcode::G_LOAD:
case TargetOpcode::G_STORE:
case TargetOpcode::G_ZEXTLOAD:
- case TargetOpcode::G_SEXTLOAD: {
+ case TargetOpcode::G_SEXTLOAD:
+ case TargetOpcode::G_FPEXTLOAD:
+ case TargetOpcode::G_FPTRUNCSTORE: {
LLT ValTy = MRI->getType(MI->getOperand(0).getReg());
LLT PtrTy = MRI->getType(MI->getOperand(1).getReg());
if (!PtrTy.isPointer())
@@ -1267,11 +1269,14 @@ void MachineVerifier::verifyPreISelGenericInstruction(const MachineInstr *MI) {
MI);
} else {
const MachineMemOperand &MMO = **MI->memoperands_begin();
- if (MI->getOpcode() == TargetOpcode::G_ZEXTLOAD ||
- MI->getOpcode() == TargetOpcode::G_SEXTLOAD) {
+ if (isa<GExtLoad>(*MI)) {
if (TypeSize::isKnownGE(MMO.getSizeInBits().getValue(),
ValTy.getSizeInBits()))
report("Generic extload must have a narrower memory type", MI);
+ } else if (isa<GFPTruncStore>(*MI)) {
+ if (TypeSize::isKnownGE(MMO.getSizeInBits().getValue(),
+ ValTy.getSizeInBits()))
+ report("Generic truncstore must have a narrower memory type", MI);
} else if (MI->getOpcode() == TargetOpcode::G_LOAD) {
if (TypeSize::isKnownGT(MMO.getSize().getValue(),
ValTy.getSizeInBytes()))
@@ -1296,7 +1301,7 @@ void MachineVerifier::verifyPreISelGenericInstruction(const MachineInstr *MI) {
}
const AtomicOrdering Order = MMO.getSuccessOrdering();
- if (Opc == TargetOpcode::G_STORE) {
+ if (isa<GAnyStore>(*MI)) {
if (Order == AtomicOrdering::Acquire ||
Order == AtomicOrdering::AcquireRelease)
report("atomic store cannot use acquire ordering", MI);
diff --git a/llvm/lib/Target/X86/GISel/X86LegalizerInfo.cpp b/llvm/lib/Target/X86/GISel/X86LegalizerInfo.cpp
index 8890952fac2c6..845341ec26e47 100644
--- a/llvm/lib/Target/X86/GISel/X86LegalizerInfo.cpp
+++ b/llvm/lib/Target/X86/GISel/X86LegalizerInfo.cpp
@@ -339,15 +339,9 @@ X86LegalizerInfo::X86LegalizerInfo(const X86Subtarget &STI,
Action.legalForTypesWithMemDesc({{s8, p0, s8, 1},
{s16, p0, s16, 1},
{s32, p0, s32, 1},
+ {s80, p0, s80, 1},
{p0, p0, p0, 1},
{v4s8, p0, v4s8, 1}});
-
- if (UseX87)
- Action.legalForTypesWithMemDesc({{s80, p0, s32, 1},
- {s80, p0, s64, 1},
- {s32, p0, s80, 1},
- {s64, p0, s80, 1},
- {s80, p0, s80, 1}});
if (Is64Bit)
Action.legalForTypesWithMemDesc(
{{s64, p0, s64, 1}, {v2s32, p0, v2s32, 1}});
@@ -400,6 +394,12 @@ X86LegalizerInfo::X86LegalizerInfo(const X86Subtarget &STI,
// TODO - SSE41/AVX2/AVX512F/AVX512BW vector extensions
}
+ for (unsigned Op : {G_FPEXTLOAD, G_FPTRUNCSTORE}) {
+ auto &Action = getActionDefinitionsBuilder(Op);
+ Action.legalForTypesWithMemDesc(
+ UseX87, {{s80, p0, s32, 1}, {s80, p0, s64, 1}, {s64, p0, s32, 1}});
+ }
+
// sext, zext, and anyext
getActionDefinitionsBuilder(G_ANYEXT)
.legalFor({s8, s16, s32, s128})
diff --git a/llvm/lib/Target/X86/GISel/X86RegisterBankInfo.cpp b/llvm/lib/Target/X86/GISel/X86RegisterBankInfo.cpp
index b23d791501729..f6b64fdc7269c 100644
--- a/llvm/lib/Target/X86/GISel/X86RegisterBankInfo.cpp
+++ b/llvm/lib/Target/X86/GISel/X86RegisterBankInfo.cpp
@@ -294,6 +294,8 @@ X86RegisterBankInfo::getInstrMapping(const MachineInstr &MI) const {
case TargetOpcode::G_FPEXT:
case TargetOpcode::G_FPTRUNC:
case TargetOpcode::G_FCONSTANT:
+ case TargetOpcode::G_FPEXTLOAD:
+ case TargetOpcode::G_FPTRUNCSTORE:
// Instruction having only floating-point operands (all scalars in
// VECRReg)
getInstrPartialMappingIdxs(MI, MRI, /* isFP= */ true, OpRegBankIdx);
diff --git a/llvm/test/CodeGen/AArch64/GlobalISel/legalizer-info-validation.mir b/llvm/test/CodeGen/AArch64/GlobalISel/legalizer-info-validation.mir
index 8a0071c9ea5c1..1cfdc70aa80e5 100644
--- a/llvm/test/CodeGen/AArch64/GlobalISel/legalizer-info-validation.mir
+++ b/llvm/test/CodeGen/AArch64/GlobalISel/legalizer-info-validation.mir
@@ -1,4 +1,3 @@
-# NOTE: Assertions have been autogenerated by utils/update_mir_test_checks.py UTC_ARGS: --version 5
# RUN: llc -mtriple=aarch64-- -run-pass=legalizer %s \
# RUN: -mcpu=cortex-a75 -o - 2>&1 | FileCheck %s --check-prefixes=CHECK
@@ -214,6 +213,9 @@
# DEBUG-NEXT: G_ZEXTLOAD (opcode {{[0-9]+}}): 2 type indices, 0 imm indices
# DEBUG-NEXT: .. type index coverage check SKIPPED: user-defined predicate detected
# DEBUG-NEXT: .. imm index coverage check SKIPPED: user-defined predicate detected
+# DEBUG-NEXT: G_FPEXTLOAD (opcode {{[0-9]+}}): 2 type indices, 0 imm indices
+# DEBUG-NEXT: .. type index coverage check SKIPPED: no rules defined
+# DEBUG-NEXT: .. imm index coverage check SKIPPED: no rules defined
# DEBUG-NEXT: G_INDEXED_LOAD (opcode {{[0-9]+}}): 3 type indices, 0 imm indices
# DEBUG-NEXT: .. type index coverage check SKIPPED: user-defined predicate detected
# DEBUG-NEXT: .. imm index coverage check SKIPPED: user-defined predicate detected
@@ -227,6 +229,9 @@
# DEBUG-NEXT: G_STORE (opcode {{[0-9]+}}): 2 type indices, 0 imm indices
# DEBUG-NEXT: .. type index coverage check SKIPPED: user-defined predicate detected
# DEBUG-NEXT: .. imm index coverage check SKIPPED: user-defined predicate detected
+# DEBUG-NEXT: G_FPTRUNCSTORE (opcode {{[0-9]+}}): 2 type indices, 0 imm indices
+# DEBUG-NEXT: .. type index coverage check SKIPPED: no rules defined
+# DEBUG-NEXT: .. imm index coverage check SKIPPED: no rules defined
# DEBUG-NEXT: G_INDEXED_STORE (opcode {{[0-9]+}}): 3 type indices, 0 imm indices
# DEBUG-NEXT: .. type index coverage check SKIPPED: user-defined predicate detected
# DEBUG-NEXT: .. imm index coverage check SKIPPED: user-defined predicate detected
diff --git a/llvm/test/CodeGen/MIR2Vec/Inputs/reference_x86_vocab_print.txt b/llvm/test/CodeGen/MIR2Vec/Inputs/reference_x86_vocab_print.txt
index 62e07445ad12e..cbceaeb5fc5f6 100644
--- a/llvm/test/CodeGen/MIR2Vec/Inputs/reference_x86_vocab_print.txt
+++ b/llvm/test/CodeGen/MIR2Vec/Inputs/reference_x86_vocab_print.txt
@@ -417,6 +417,7 @@ Key: G_FNEARBYINT: [ 0.00 0.00 ]
Key: G_FNEG: [ 0.00 0.00 ]
Key: G_FNSTCW: [ 0.00 0.00 ]
Key: G_FPEXT: [ 0.00 0.00 ]
+Key: G_FPEXTLOAD: [ 0.00 0.00 ]
Key: G_FPOW: [ 0.00 0.00 ]
Key: G_FPOWI: [ 0.00 0.00 ]
Key: G_FPTOSI: [ 0.00 0.00 ]
@@ -424,6 +425,7 @@ Key: G_FPTOSI_SAT: [ 0.00 0.00 ]
Key: G_FPTOUI: [ 0.00 0.00 ]
Key: G_FPTOUI_SAT: [ 0.00 0.00 ]
Key: G_FPTRUNC: [ 0.00 0.00 ]
+Key: G_FPTRUNCSTORE: [ 0.00 0.00 ]
Key: G_FRAME_INDEX: [ 0.00 0.00 ]
Key: G_FREEZE: [ 0.00 0.00 ]
Key: G_FREM: [ 0.00 0.00 ]
diff --git a/llvm/test/CodeGen/MIR2Vec/Inputs/reference_x86_vocab_wo=0.5_print.txt b/llvm/test/CodeGen/MIR2Vec/Inputs/reference_x86_vocab_wo=0.5_print.txt
index 03a3fafc6b801..aa7561a31bf4a 100644
--- a/llvm/test/CodeGen/MIR2Vec/Inputs/reference_x86_vocab_wo=0.5_print.txt
+++ b/llvm/test/CodeGen/MIR2Vec/Inputs/reference_x86_vocab_wo=0.5_print.txt
@@ -417,6 +417,7 @@ Key: G_FNEARBYINT: [ 0.00 0.00 ]
Key: G_FNEG: [ 0.00 0.00 ]
Key: G_FNSTCW: [ 0.00 0.00 ]
Key: G_FPEXT: [ 0.00 0.00 ]
+Key: G_FPEXTLOAD: [ 0.00 0.00 ]
Key: G_FPOW: [ 0.00 0.00 ]
Key: G_FPOWI: [ 0.00 0.00 ]
Key: G_FPTOSI: [ 0.00 0.00 ]
@@ -424,6 +425,7 @@ Key: G_FPTOSI_SAT: [ 0.00 0.00 ]
Key: G_FPTOUI: [ 0.00 0.00 ]
Key: G_FPTOUI_SAT: [ 0.00 0.00 ]
Key: G_FPTRUNC: [ 0.00 0.00 ]
+Key: G_FPTRUNCSTORE: [ 0.00 0.00 ]
Key: G_FRAME_INDEX: [ 0.00 0.00 ]
Key: G_FREEZE: [ 0.00 0.00 ]
Key: G_FREM: [ 0.00 0.00 ]
diff --git a/llvm/test/CodeGen/RISCV/GlobalISel/legalizer-info-validation.mir b/llvm/test/CodeGen/RISCV/GlobalISel/legalizer-info-validation.mir
index ff8b8faee5c15..8953fb237f94c 100644
--- a/llvm/test/CodeGen/RISCV/GlobalISel/legalizer-info-validation.mir
+++ b/llvm/test/CodeGen/RISCV/GlobalISel/legalizer-info-validation.mir
@@ -1,4 +1,3 @@
-# NOTE: Assertions have been autogenerated by utils/update_mir_test_checks.py UTC_ARGS: --version 5
# RUN: llc -mtriple=riscv32-- -run-pass=legalizer %s \
# RUN: -mattr=+m,+zbb,+zfh,+v -o - 2>&1 | FileCheck %s --check-prefixes=CHECK
# RUN: llc -mtriple=riscv64-- -run-pass=legalizer %s \
@@ -214,6 +213,9 @@
# DEBUG-NEXT: .. opcode {{[0-9]+}} is aliased to {{[0-9]+}}
# DEBUG-NEXT: .. type index coverage check SKIPPED: user-defined predicate detected
# DEBUG-NEXT: .. imm index coverage check SKIPPED: user-defined predicate detected
+# DEBUG-NEXT: G_FPEXTLOAD (opcode {{[0-9]+}}): 2 type indices, 0 imm indices
+# DEBUG-NEXT: .. type index coverage check SKIPPED: no rules defined
+# DEBUG-NEXT: .. imm index coverage check SKIPPED: no rules defined
# DEBUG-NEXT: G_INDEXED_LOAD (opcode {{[0-9]+}}): 3 type indices, 0 imm indices
# DEBUG-NEXT: .. type index coverage check SKIPPED: no rules defined
# DEBUG-NEXT: .. imm index coverage check SKIPPED: no rules defined
@@ -226,6 +228,9 @@
# DEBUG-NEXT: G_STORE (opcode {{[0-9]+}}): 2 type indices, 0 imm indices
# DEBUG-NEXT: .. type index coverage check SKIPPED: user-defined predicate detected
# DEBUG-NEXT: .. imm index coverage check SKIPPED: user-defined predicate detected
+# DEBUG-NEXT: G_FPTRUNCSTORE (opcode {{[0-9]+}}): 2 type indices, 0 imm indices
+# DEBUG-NEXT: .. type index coverage check SKIPPED: no rules defined
+# DEBUG-NEXT: .. imm index coverage check SKIPPED: no rules defined
# DEBUG-NEXT: G_INDEXED_STORE (opcode {{[0-9]+}}): 3 type indices, 0 imm indices
# DEBUG-NEXT: .. type index coverage check SKIPPED: no rules defined
# DEBUG-NEXT: .. imm index coverage check SKIPPED: no rules defined
diff --git a/llvm/test/CodeGen/X86/isel-fptrunc-fpext.ll b/llvm/test/CodeGen/X86/isel-fptrunc-fpext.ll
index 0ad9b90806ce9..c1ba7495e7e2d 100644
--- a/llvm/test/CodeGen/X86/isel-fptrunc-fpext.ll
+++ b/llvm/test/CodeGen/X86/isel-fptrunc-fpext.ll
@@ -15,10 +15,10 @@
; RUN: llc < %s -mtriple=x86_64-unknown-unknown -mattr=+avx512f -fast-isel=0 -global-isel=1 -global-isel-abort=1 | FileCheck %s --check-prefixes AVX,GLOBAL-AVX
define double @fpext_float_to_double(float %f) {
-; X86-LABEL: fpext_float_to_double:
-; X86: # %bb.0:
-; X86-NEXT: flds {{[0-9]+}}(%esp)
-; X86-NEXT: retl
+; FASTSDAG-X86-LABEL: fpext_float_to_double:
+; FASTSDAG-X86: # %bb.0:
+; FASTSDAG-X86-NEXT: flds {{[0-9]+}}(%esp)
+; FASTSDAG-X86-NEXT: retl
;
; SSE-LABEL: fpext_float_to_double:
; SSE: # %bb.0:
@@ -29,6 +29,17 @@ define double @fpext_float_to_double(float %f) {
; AVX: # %bb.0:
; AVX-NEXT: vcvtss2sd %xmm0, %xmm0, %xmm0
; AVX-NEXT: retq
+;
+; GLOBAL-X86-LABEL: fpext_float_to_double:
+; GLOBAL-X86: # %bb.0:
+; GLOBAL-X86-NEXT: pushl %eax
+; GLOBAL-X86-NEXT: .cfi_def_cfa_offset 8
+; GLOBAL-X86-NEXT: movl {{[0-9]+}}(%esp), %eax
+; GLOBAL-X86-NEXT: movl %eax, (%esp)
+; GLOBAL-X86-NEXT: flds (%esp)
+; GLOBAL-X86-NEXT: popl %eax
+; GLOBAL-X86-NEXT: .cfi_def_cfa_offset 4
+; GLOBAL-X86-NEXT: retl
%1 = fpext float %f to double
ret double %1
}
@@ -136,16 +147,16 @@ define x86_fp80 @fpext_double_to_x86_fp80(double %d) {
}
define float @fptrunc_double_to_float(double %d) {
-; FASTSDAG-X86-LABEL: fptrunc_double_to_float:
-; FASTSDAG-X86: # %bb.0:
-; FASTSDAG-X86-NEXT: pushl %eax
-; FASTSDAG-X86-NEXT: .cfi_def_cfa_offset 8
-; FASTSDAG-X86-NEXT: fldl {{[0-9]+}}(%esp)
-; FASTSDAG-X86-NEXT: fstps (%esp)
-; FASTSDAG-X86-NEXT: flds (%esp)
-; FASTSDAG-X86-NEXT: popl %eax
-; FASTSDAG-X86-NEXT: .cfi_def_cfa_offset 4
-; FASTSDAG-X86-NEXT: retl
+; X86-LABEL: fptrunc_double_to_float:
+; X86: # %bb.0:
+; X86-NEXT: pushl %eax
+; X86-NEXT: .cfi_def_cfa_offset 8
+; X86-NEXT: fldl {{[0-9]+}}(%esp)
+; X86-NEXT: fstps (%esp)
+; X86-NEXT: flds (%esp)
+; X86-NEXT: popl %eax
+; X86-NEXT: .cfi_def_cfa_offset 4
+; X86-NEXT: retl
;
; SSE-LABEL: fptrunc_double_to_float:
; SSE: # %bb.0:
@@ -156,21 +167,6 @@ define float @fptrunc_double_to_float(double %d) {
; AVX: # %bb.0:
; AVX-NEXT: vcvtsd2ss %xmm0, %xmm0, %xmm0
; AVX-NEXT: retq
-;
-; GLOBAL-X86-LABEL: fptrunc_double_to_float:
-; GLOBAL-X86: # %bb.0:
-; GLOBAL-X86-NEXT: pushl %eax
-; GLOBAL-X86-NEXT: .cfi_def_cfa_offset 8
-; GLOBAL-X86-NEXT: leal {{[0-9]+}}(%esp), %eax
-; GLOBAL-X86-NEXT: movl {{[0-9]+}}(%esp), %ecx
-; GLOBAL-X86-NEXT: movl 4(%eax), %eax
-; GLOBAL-X86-NEXT: movl %esp, %edx
-; GLOBAL-X86-NEXT: movl %ecx, (%esp)
-; GLOBAL-X86-NEXT: movl %eax, 4(%edx)
-; GLOBAL-X86-NEXT: flds (%esp)
-; GLOBAL-X86-NEXT: popl %eax
-; GLOBAL-X86-NEXT: .cfi_def_cfa_offset 4
-; GLOBAL-X86-NEXT: retl
%1 = fptrunc double %d to float
ret float %1
}
diff --git a/llvm/test/MachineVerifier/test_g_fpextload.mir b/llvm/test/MachineVerifier/test_g_fpextload.mir
new file mode 100644
index 0000000000000..e0e6f08684405
--- /dev/null
+++ b/llvm/test/MachineVerifier/test_g_fpextload.mir
@@ -0,0 +1,28 @@
+# RUN: not --crash llc -o - -mtriple=x86_64-linux-gnu -global-isel -run-pass=none -verify-machineinstrs %s 2>&1 | FileCheck %s
+# REQUIRES: x86-registered-target
+
+---
+name: test_fpextload
+legalized: true
+regBankSelected: false
+selected: false
+tracksRegLiveness: true
+liveins:
+body: |
+ bb.0:
+
+ ; CHECK: Bad machine code: Generic memory instruction must access a pointer
+ %0:_(s64) = G_CONSTANT i64 0
+ %1:_(s32) = G_FPEXTLOAD %0 :: (load (s16))
+
+ ; CHECK: *** Bad machine code: Generic instruction accessing memory must have one mem operand ***
+ %2:_(p0) = G_IMPLICIT_DEF
+ %3:_(s64) = G_FPEXTLOAD %2
+
+ ; CHECK: Bad machine code: Generic extload must have a narrower memory type
+ %4:_(s64) = G_FPEXTLOAD %2 :: (load (s64))
+
+ ; CHECK: Bad machine code: Generic extload must have a narrower memory type
+ %5:_(s64) = G_FPEXTLOAD %2 :: (load (s128))
+
+...
diff --git a/llvm/test/MachineVerifier/test_g_fptruncstore.mir b/llvm/test/MachineVerifier/test_g_fptruncstore.mir
new file mode 100644
index 0000000000000..0c10c20dc4386
--- /dev/null
+++ b/llvm/test/MachineVerifier/test_g_fptruncstore.mir
@@ -0,0 +1,32 @@
+# RUN: not --crash llc -o - -mtriple=x86_64-linux-gnu -global-isel -run-pass=none -verify-machineinstrs %s 2>&1 | FileCheck %s
+# REQUIRES: x86-registered-target
+
+---
+name: test_fptruncstore
+legalized: true
+regBankSelected: false
+selected: false
+tracksRegLiveness: true
+liveins:
+body: |
+ bb.0:
+
+ ; CHECK: Bad machine code: Generic memory instruction must access a pointer
+ %0:_(s64) = G_CONSTANT i64 0
+ %1:_(s32) = G_IMPLICIT_DEF
+ G_FPTRUNCSTORE %1, %0 :: (store (s16))
+
+ ; CHECK: *** Bad machine code: Generic instruction accessing memory must have one mem operand ***
+ %2:_(p0) = G_IMPLICIT_DEF
+ %3:_(s64) = G_IMPLICIT_DEF
+ G_FPTRUNCSTORE %3, %2
+
+ ; CHECK: Bad machine code: Generic truncstore must have a narrower memory type
+ %4:_(s32) = G_IMPLICIT_DEF
+ G_FPTRUNCSTORE %4, %2 :: (store (s32))
+
+ ; CHECK: Bad machine code: Generic truncstore must have a narrower memory type
+ %5:_(s32) = G_IMPLICIT_DEF
+ G_FPTRUNCSTORE %5, %2 :: (store (s64))
+
+...
diff --git a/llvm/test/TableGen/GlobalISelCombinerEmitter/match-table-cxx.td b/llvm/test/TableGen/GlobalISelCombinerEmitter/match-table-cxx.td
index 28017700a0448..ccd13a86f8ed6 100644
--- a/llvm/test/TableGen/GlobalISelCombinerEmitter/match-table-cxx.td
+++ b/llvm/test/TableGen/GlobalISelCombinerEmitter/match-table-cxx.td
@@ -96,71 +96,71 @@ def MyCombiner: GICombiner<"GenMyCombiner", [
// CHECK: const uint8_t *GenMyCombiner::getMatchTable() const {
// CHECK-NEXT: constexpr static uint8_t MatchTable0[] = {
-// CHECK-NEXT: /* 0 */ GIM_SwitchOpcode, /*MI*/0, /*[*/GIMT_Encode2(105), GIMT_Encode2(217), /*)*//*default:*//*Label 5*/ GIMT_Encode4(524),
-// CHECK-NEXT: /* 10 */ /*TargetOpcode::G_STORE*//*Label 0*/ GIMT_Encode4(458), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0),
-// CHECK-NEXT: /* 182 */ /*TargetOpcode::G_SEXT*//*Label 1*/ GIMT_Encode4(476), GIMT_Encode4(0),
-// CHECK-NEXT: /* 190 */ /*TargetOpcode::G_ZEXT*//*Label 2*/ GIMT_Encode4(488), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0),
-// CHECK-NEXT: /* 418 */ /*TargetOpcode::G_FNEG*//*Label 3*/ GIMT_Encode4(500), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0),
-// CHECK-NEXT: /* 454 */ /*TargetOpcode::G_FABS*//*Label 4*/ GIMT_Encode4(512),
-// CHECK-NEXT: /* 458 */ // Label 0: @458
-// CHECK-NEXT: /* 458 */ GIM_Try, /*On fail goto*//*Label 6*/ GIMT_Encode4(475), // Rule ID 2 //
-// CHECK-NEXT: /* 463 */ GIM_CheckSimplePredicate, GIMT_Encode2(GICXXPred_Simple_IsRule2Enabled),
-// CHECK-NEXT: /* 466 */ // MIs[0] x
-// CHECK-NEXT: /* 466 */ // No operand predicates
-// CHECK-NEXT: /* 466 */ // MIs[0] y
-// CHECK-NEXT: /* 466 */ // No operand predicates
-// CHECK-NEXT: /* 466 */ GIM_CheckCxxInsnPredicate, /*MI*/0, /*FnId*/GIMT_Encode2(GICXXPred_MI_Predicate_GICombiner0),
-// CHECK-NEXT: /* 470 */ GIM_CheckCxxInsnPredicate, /*MI*/0, /*FnId*/GIMT_Encode2(GICXXPred_MI_Predicate_GICombiner1),
-// CHECK-NEXT: /* 474 */ // Combiner Rule #2: TwoMatchNoApply
-// CHECK-NEXT: /* 474 */ GIR_EraseRootFromParent_Done,
-// CHECK-NEXT: /* 475 */ // Label 6: @475
-// CHECK-NEXT: /* 475 */ GIM_Reject,
-// CHECK-NEXT: /* 476 */ // Label 1: @476
-// CHECK-NEXT: /* 476 */ GIM_Try, /*On fail goto*//*Label 7*/ GIMT_Encode4(487), // Rule ID 3 //
-// CHECK-NEXT: /* 481 */ GIM_CheckSimplePredicate, GIMT_Encode2(GICXXPred_Simple_IsRule3Enabled),
-// CHECK-NEXT: /* 484 */ // MIs[0] a
-// CHECK-NEXT: /* 484 */ // No operand predicates
-// CHECK-NEXT: /* 484 */ // MIs[0] y
-// CHECK-NEXT: /* 484 */ // No operand predicates
-// CHECK-NEXT: /* 484 */ // Combiner Rule #3: NoMatchTwoApply
-// CHECK-NEXT: /* 484 */ GIR_DoneWithCustomAction, /*Fn*/GIMT_Encode2(GICXXCustomAction_GICombiner2),
-// CHECK-NEXT: /* 487 */ // Label 7: @487
-// CHECK-NEXT: /* 487 */ GIM_Reject,
-// CHECK-NEXT: /* 488 */ // Label 2: @488
-// CHECK-NEXT: /* 488 */ GIM_Try, /*On fail goto*//*Label 8*/ GIMT_Encode4(499), // Rule ID 4 //
-// CHECK-NEXT: /* 493 */ GIM_CheckSimplePredicate, GIMT_Encode2(GICXXPred_Simple_IsRule4Enabled),
-// CHECK-NEXT: /* 496 */ // MIs[0] a
-// CHECK-NEXT: /* 496 */ // No operand predicates
-// CHECK-NEXT: /* 496 */ // MIs[0] y
-// CHECK-NEXT: /* 496 */ // No operand predicates
-// CHECK-NEXT: /* 496 */ // Combiner Rule #4: CombineCXXOrder
-// CHECK-NEXT: /* 496 */ GIR_DoneWithCustomAction, /*Fn*/GIMT_Encode2(GICXXCustomAction_GICombiner3),
-// CHECK-NEXT: /* 499 */ // Label 8: @499
-// CHECK-NEXT: /* 499 */ GIM_Reject,
-// CHECK-NEXT: /* 500 */ // Label 3: @500
-// CHECK-NEXT: /* 500 */ GIM_Try, /*On fail goto*//*Label 9*/ GIMT_Encode4(511), // Rule ID 1 //
-// CHECK-NEXT: /* 505 */ GIM_CheckSimplePredicate, GIMT_Encode2(GICXXPred_Simple_IsRule1Enabled),
-// CHECK-NEXT: /* 508 */ // MIs[0] a
-// CHECK-NEXT: /* 508 */ // No operand predicates
-// CHECK-NEXT: /* 508 */ // MIs[0] b
-// CHECK-NEXT: /* 508 */ // No operand predicates
-// CHECK-NEXT: /* 508 */ // Combiner Rule #1: TwoMatchTwoApply
-// CHECK-NEXT: /* 508 */ GIR_DoneWithCustomAction, /*Fn*/GIMT_Encode2(GICXXCustomAction_GICombiner1),
-// CHECK-NEXT: /* 511 */ // Label 9: @511
-// CHECK-NEXT: /* 511 */ GIM_Reject,
-// CHECK-NEXT: /* 512 */ // Label 4: @512
-// CHECK-NEXT: /* 512 */ GIM_Try, /*On fail goto*//*Label 10*/ GIMT_Encode4(523), // Rule ID 0 //
-// CHECK-NEXT: /* 517 */ GIM_CheckSimplePredicate, GIMT_Encode2(GICXXPred_Simple_IsRule0Enabled),
-// CHECK-NEXT: /* 520 */ // MIs[0] a
-// CHECK-NEXT: /* 520 */ // No operand predicates
-// CHECK-NEXT: /* 520 */ // MIs[0] b
-// CHECK-NEXT: /* 520 */ // No operand predicates
-// CHECK-NEXT: /* 520 */ // Combiner Rule #0: OneMatchOneApply
-// CHECK-NEXT: /* 520 */ GIR_DoneWithCustomAction, /*Fn*/GIMT_Encode2(GICXXCustomAction_GICombiner0),
-// CHECK-NEXT: /* 523 */ // Label 10: @523
-// CHECK-NEXT: /* 523 */ GIM_Reject,
-// CHECK-NEXT: /* 524 */ // Label 5: @524
-// CHECK-NEXT: /* 524 */ GIM_Reject,
-// CHECK-NEXT: /* 525 */ }; // Size: 525 bytes
+// CHECK-NEXT: GIM_SwitchOpcode, /*MI*/0, /*[*/GIMT_Encode2({{[0-9]+}}), GIMT_Encode2({{[0-9]+}}), /*)*//*default:*//*Label 5*/ GIMT_Encode4({{[0-9]+}}),
+// CHECK-NEXT: /*TargetOpcode::G_STORE*//*Label 0*/ GIMT_Encode4({{[0-9]+}}), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0),
+// CHECK-NEXT: /*TargetOpcode::G_SEXT*//*Label 1*/ GIMT_Encode4({{[0-9]+}}), GIMT_Encode4(0),
+// CHECK-NEXT: /*TargetOpcode::G_ZEXT*//*Label 2*/ GIMT_Encode4({{[0-9]+}}), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0),
+// CHECK-NEXT: /*TargetOpcode::G_FNEG*//*Label 3*/ GIMT_Encode4({{[0-9]+}}), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0),
+// CHECK-NEXT: /*TargetOpcode::G_FABS*//*Label 4*/ GIMT_Encode4({{[0-9]+}}),
+// CHECK-NEXT: // Label 0: @{{[0-9]+}}
+// CHECK-NEXT: GIM_Try, /*On fail goto*//*Label 6*/ GIMT_Encode4({{[0-9]+}}), // Rule ID 2 //
+// CHECK-NEXT: GIM_CheckSimplePredicate, GIMT_Encode2(GICXXPred_Simple_IsRule2Enabled),
+// CHECK-NEXT: // MIs[0] x
+// CHECK-NEXT: // No operand predicates
+// CHECK-NEXT: // MIs[0] y
+// CHECK-NEXT: // No operand predicates
+// CHECK-NEXT: GIM_CheckCxxInsnPredicate, /*MI*/0, /*FnId*/GIMT_Encode2(GICXXPred_MI_Predicate_GICombiner0),
+// CHECK-NEXT: GIM_CheckCxxInsnPredicate, /*MI*/0, /*FnId*/GIMT_Encode2(GICXXPred_MI_Predicate_GICombiner1),
+// CHECK-NEXT: // Combiner Rule #2: TwoMatchNoApply
+// CHECK-NEXT: GIR_EraseRootFromParent_Done,
+// CHECK-NEXT: // Label 6: @{{[0-9]+}}
+// CHECK-NEXT: GIM_Reject,
+// CHECK-NEXT: // Label 1: @{{[0-9]+}}
+// CHECK-NEXT: GIM_Try, /*On fail goto*//*Label 7*/ GIMT_Encode4({{[0-9]+}}), // Rule ID 3 //
+// CHECK-NEXT: GIM_CheckSimplePredicate, GIMT_Encode2(GICXXPred_Simple_IsRule3Enabled),
+// CHECK-NEXT: // MIs[0] a
+// CHECK-NEXT: // No operand predicates
+// CHECK-NEXT: // MIs[0] y
+// CHECK-NEXT: // No operand predicates
+// CHECK-NEXT: // Combiner Rule #3: NoMatchTwoApply
+// CHECK-NEXT: GIR_DoneWithCustomAction, /*Fn*/GIMT_Encode2(GICXXCustomAction_GICombiner2),
+// CHECK-NEXT: // Label 7: @{{[0-9]+}}
+// CHECK-NEXT: GIM_Reject,
+// CHECK-NEXT: // Label 2: @{{[0-9]+}}
+// CHECK-NEXT: GIM_Try, /*On fail goto*//*Label 8*/ GIMT_Encode4({{[0-9]+}}), // Rule ID 4 //
+// CHECK-NEXT: GIM_CheckSimplePredicate, GIMT_Encode2(GICXXPred_Simple_IsRule4Enabled),
+// CHECK-NEXT: // MIs[0] a
+// CHECK-NEXT: // No operand predicates
+// CHECK-NEXT: // MIs[0] y
+// CHECK-NEXT: // No operand predicates
+// CHECK-NEXT: // Combiner Rule #4: CombineCXXOrder
+// CHECK-NEXT: GIR_DoneWithCustomAction, /*Fn*/GIMT_Encode2(GICXXCustomAction_GICombiner3),
+// CHECK-NEXT: // Label 8: @{{[0-9]+}}
+// CHECK-NEXT: GIM_Reject,
+// CHECK-NEXT: // Label 3: @{{[0-9]+}}
+// CHECK-NEXT: GIM_Try, /*On fail goto*//*Label 9*/ GIMT_Encode4({{[0-9]+}}), // Rule ID 1 //
+// CHECK-NEXT: GIM_CheckSimplePredicate, GIMT_Encode2(GICXXPred_Simple_IsRule1Enabled),
+// CHECK-NEXT: // MIs[0] a
+// CHECK-NEXT: // No operand predicates
+// CHECK-NEXT: // MIs[0] b
+// CHECK-NEXT: // No operand predicates
+// CHECK-NEXT: // Combiner Rule #1: TwoMatchTwoApply
+// CHECK-NEXT: GIR_DoneWithCustomAction, /*Fn*/GIMT_Encode2(GICXXCustomAction_GICombiner1),
+// CHECK-NEXT: // Label 9: @{{[0-9]+}}
+// CHECK-NEXT: GIM_Reject,
+// CHECK-NEXT: // Label 4: @{{[0-9]+}}
+// CHECK-NEXT: GIM_Try, /*On fail goto*//*Label 10*/ GIMT_Encode4({{[0-9]+}}), // Rule ID 0 //
+// CHECK-NEXT: GIM_CheckSimplePredicate, GIMT_Encode2(GICXXPred_Simple_IsRule0Enabled),
+// CHECK-NEXT: // MIs[0] a
+// CHECK-NEXT: // No operand predicates
+// CHECK-NEXT: // MIs[0] b
+// CHECK-NEXT: // No operand predicates
+// CHECK-NEXT: // Combiner Rule #0: OneMatchOneApply
+// CHECK-NEXT: GIR_DoneWithCustomAction, /*Fn*/GIMT_Encode2(GICXXCustomAction_GICombiner0),
+// CHECK-NEXT: // Label 10: @{{[0-9]+}}
+// CHECK-NEXT: GIM_Reject,
+// CHECK-NEXT: // Label 5: @{{[0-9]+}}
+// CHECK-NEXT: GIM_Reject,
+// CHECK-NEXT: }; // Size: 529 bytes
// CHECK-NEXT: return MatchTable0;
// CHECK-NEXT: }
diff --git a/llvm/test/TableGen/GlobalISelEmitter/GlobalISelEmitter.td b/llvm/test/TableGen/GlobalISelEmitter/GlobalISelEmitter.td
index 64ca63da3b6f0..c686e0d1519b0 100644
--- a/llvm/test/TableGen/GlobalISelEmitter/GlobalISelEmitter.td
+++ b/llvm/test/TableGen/GlobalISelEmitter/GlobalISelEmitter.td
@@ -535,7 +535,7 @@ def : Pat<(frag GPR32:$src1, complex:$src2, complex:$src3),
// R00O-NEXT: GIM_Reject,
// R00O: // Label [[DEFAULT_NUM]]: @[[DEFAULT]]
// R00O-NEXT: GIM_Reject,
-// R00O-NEXT: }; // Size: 1918 bytes
+// R00O-NEXT: }; // Size: 1926 bytes
def INSNBOB : I<(outs GPR32:$dst), (ins GPR32:$src1, GPR32:$src2, GPR32:$src3, GPR32:$src4),
[(set GPR32:$dst,
diff --git a/llvm/test/TableGen/RegClassByHwMode.td b/llvm/test/TableGen/RegClassByHwMode.td
index 0be22be560bea..7022c75fe8b24 100644
--- a/llvm/test/TableGen/RegClassByHwMode.td
+++ b/llvm/test/TableGen/RegClassByHwMode.td
@@ -234,36 +234,36 @@ include "Common/RegClassByHwModeCommon.td"
-// ISEL-GISEL: GIM_Try, /*On fail goto*//*Label 3*/ GIMT_Encode4(148),
+// ISEL-GISEL: GIM_Try, /*On fail goto*//*Label 3*/ GIMT_Encode4(152),
// ISEL-GISEL-NEXT: GIM_RootCheckType, /*Op*/0, /*Type*/GILLT_s64,
// ISEL-GISEL-NEXT: GIM_CheckAtomicOrdering, /*MI*/0, /*Order*/(uint8_t)AtomicOrdering::NotAtomic,
// ISEL-GISEL-NEXT: GIM_CheckMemorySizeEqualToLLT, /*MI*/0, /*MMO*/0, /*OpIdx*/0,
// ISEL-GISEL-NEXT: GIM_RootCheckRegBankForClass, /*Op*/0, /*RC*/GIMT_Encode2(MyTarget::XRegsRegClassID),
-// ISEL-GISEL-NEXT: GIM_Try, /*On fail goto*//*Label 4*/ GIMT_Encode4(101),
+// ISEL-GISEL-NEXT: GIM_Try, /*On fail goto*//*Label 4*/ GIMT_Encode4(105),
// ISEL-GISEL-NEXT: GIM_CheckPointerToAny, /*MI*/0, /*Op*/1, /*SizeInBits*/32,
// FIXME: This should be a direct check for regbank, not have an incorrect class
// ISEL-GISEL-NEXT: GIM_RootCheckRegBankForClass, /*Op*/1, /*RC*/GIMT_Encode2(MyTarget::PtrRegs32RegClassID),
-// ISEL-GISEL-NEXT: GIM_Try, /*On fail goto*//*Label 5*/ GIMT_Encode4(85), // Rule ID 1 //
+// ISEL-GISEL-NEXT: GIM_Try, /*On fail goto*//*Label 5*/ GIMT_Encode4(89), // Rule ID 1 //
// ISEL-GISEL-NEXT: GIM_CheckFeatures, GIMT_Encode2(GIFBS_HwMode1),
// ISEL-GISEL-NEXT: // (ld:{ *:[i64] } PtrRegOperand:{ *:[i32] }:$src)<<P:Predicate_unindexedload>><<P:Predicate_load>> => (MY_LOAD:{ *:[i64] } ?:{ *:[i32] }:$src)
// ISEL-GISEL-NEXT: GIR_MutateOpcode, /*InsnID*/0, /*RecycleInsnID*/0, /*Opcode*/GIMT_Encode2(MyTarget::MY_LOAD),
// ISEL-GISEL-NEXT: GIR_RootConstrainSelectedInstOperands,
// ISEL-GISEL-NEXT: // GIR_Coverage, 1,
// ISEL-GISEL-NEXT: GIR_Done,
-// ISEL-GISEL-NEXT: // Label 5: @85
-// ISEL-GISEL-NEXT: GIM_Try, /*On fail goto*//*Label 6*/ GIMT_Encode4(100), // Rule ID 2 //
+// ISEL-GISEL-NEXT: // Label 5: @89
+// ISEL-GISEL-NEXT: GIM_Try, /*On fail goto*//*Label 6*/ GIMT_Encode4(104), // Rule ID 2 //
// ISEL-GISEL-NEXT: GIM_CheckFeatures, GIMT_Encode2(GIFBS_HwMode2),
// ISEL-GISEL-NEXT: // (ld:{ *:[i64] } PtrRegOperand:{ *:[i32] }:$src)<<P:Predicate_unindexedload>><<P:Predicate_load>> => (MY_LOAD:{ *:[i64] } ?:{ *:[i32] }:$src)
// ISEL-GISEL-NEXT: GIR_MutateOpcode, /*InsnID*/0, /*RecycleInsnID*/0, /*Opcode*/GIMT_Encode2(MyTarget::MY_LOAD),
// ISEL-GISEL-NEXT: GIR_RootConstrainSelectedInstOperands,
// ISEL-GISEL-NEXT: // GIR_Coverage, 2,
// ISEL-GISEL-NEXT: GIR_Done,
-// ISEL-GISEL-NEXT: // Label 6: @100
+// ISEL-GISEL-NEXT: // Label 6: @104
// ISEL-GISEL-NEXT: GIM_Reject,
-// ISEL-GISEL-NEXT: // Label 4: @101
-// ISEL-GISEL-NEXT: GIM_Try, /*On fail goto*//*Label 7*/ GIMT_Encode4(124), // Rule ID 3 //
+// ISEL-GISEL-NEXT: // Label 4: @105
+// ISEL-GISEL-NEXT: GIM_Try, /*On fail goto*//*Label 7*/ GIMT_Encode4(128), // Rule ID 3 //
// ISEL-GISEL-NEXT: GIM_CheckFeatures, GIMT_Encode2(GIFBS_HwMode0),
// ISEL-GISEL-NEXT: // MIs[0] src
// ISEL-GISEL-NEXT: GIM_CheckPointerToAny, /*MI*/0, /*Op*/1, /*SizeInBits*/64,
@@ -273,8 +273,8 @@ include "Common/RegClassByHwModeCommon.td"
// ISEL-GISEL-NEXT: GIR_RootConstrainSelectedInstOperands,
// ISEL-GISEL-NEXT: // GIR_Coverage, 3,
// ISEL-GISEL-NEXT: GIR_Done,
-// ISEL-GISEL-NEXT: // Label 7: @124
-// ISEL-GISEL-NEXT: GIM_Try, /*On fail goto*//*Label 8*/ GIMT_Encode4(147), // Rule ID 4 //
+// ISEL-GISEL-NEXT: // Label 7: @128
+// ISEL-GISEL-NEXT: GIM_Try, /*On fail goto*//*Label 8*/ GIMT_Encode4(151), // Rule ID 4 //
// ISEL-GISEL-NEXT: GIM_CheckFeatures, GIMT_Encode2(GIFBS_HwMode3),
// ISEL-GISEL-NEXT: // MIs[0] src
// ISEL-GISEL-NEXT: GIM_CheckPointerToAny, /*MI*/0, /*Op*/1, /*SizeInBits*/32,
@@ -284,12 +284,12 @@ include "Common/RegClassByHwModeCommon.td"
// ISEL-GISEL-NEXT: GIR_RootConstrainSelectedInstOperands,
// ISEL-GISEL-NEXT: // GIR_Coverage, 4,
// ISEL-GISEL-NEXT: GIR_Done,
-// ISEL-GISEL-NEXT: // Label 8: @147
+// ISEL-GISEL-NEXT: // Label 8: @151
// ISEL-GISEL-NEXT: GIM_Reject,
-// ISEL-GISEL-NEXT: // Label 3: @148
+// ISEL-GISEL-NEXT: // Label 3: @152
// ISEL-GISEL-NEXT: GIM_Reject,
-// ISEL-GISEL-NEXT: // Label 1: @149
-// ISEL-GISEL-NEXT: GIM_Try, /*On fail goto*//*Label 9*/ GIMT_Encode4(186), // Rule ID 0 //
+// ISEL-GISEL-NEXT: // Label 1: @153
+// ISEL-GISEL-NEXT: GIM_Try, /*On fail goto*//*Label 9*/ GIMT_Encode4(190), // Rule ID 0 //
// ISEL-GISEL-NEXT: GIM_CheckFeatures, GIMT_Encode2(GIFBS_HwMode0),
// ISEL-GISEL-NEXT: GIM_RootCheckType, /*Op*/0, /*Type*/GILLT_s64,
// ISEL-GISEL-NEXT: GIM_CheckAtomicOrdering, /*MI*/0, /*Order*/(uint8_t)AtomicOrdering::NotAtomic,
diff --git a/llvm/utils/TableGen/GlobalISelEmitter.cpp b/llvm/utils/TableGen/GlobalISelEmitter.cpp
index bd79c423a00e2..447bd4c4a0184 100644
--- a/llvm/utils/TableGen/GlobalISelEmitter.cpp
+++ b/llvm/utils/TableGen/GlobalISelEmitter.cpp
@@ -541,8 +541,12 @@ GlobalISelEmitter::getEquivNode(const Record &Equiv,
N.getIntrinsicInfo(CGP)->isConvergent)
return &Target.getInstruction(Equiv.getValueAsDef("IfConvergent"));
+ bool IsAnyExtLoad = false;
+ bool IsTruncStore = false;
for (const TreePredicateCall &Call : N.getPredicateCalls()) {
const TreePredicateFn &Predicate = Call.Fn;
+ IsAnyExtLoad |= Predicate.isAnyExtLoad();
+ IsTruncStore |= Predicate.isTruncStore();
if (!Equiv.isValueUnset("IfSignExtend") &&
(Predicate.isLoad() || Predicate.isAtomic()) &&
Predicate.isSignExtLoad())
@@ -551,6 +555,16 @@ GlobalISelEmitter::getEquivNode(const Record &Equiv,
(Predicate.isLoad() || Predicate.isAtomic()) &&
Predicate.isZeroExtLoad())
return &Target.getInstruction(Equiv.getValueAsDef("IfZeroExtend"));
+ if (!Equiv.isValueUnset("IfFPExtend") &&
+ (Predicate.isLoad() || Predicate.isAtomic()) && IsAnyExtLoad &&
+ Predicate.getMemoryVT() != nullptr &&
+ getValueType(Predicate.getMemoryVT()).isFloatingPoint())
+ return &Target.getInstruction(Equiv.getValueAsDef("IfFPExtend"));
+ if (!Equiv.isValueUnset("IfFPTrunc") &&
+ (Predicate.isStore() || Predicate.isAtomic()) && IsTruncStore &&
+ Predicate.getMemoryVT() != nullptr &&
+ getValueType(Predicate.getMemoryVT()).isFloatingPoint())
+ return &Target.getInstruction(Equiv.getValueAsDef("IfFPTrunc"));
}
return &Target.getInstruction(Equiv.getValueAsDef("I"));
>From d1ec2151d6dfb80dde4048f5fff49521c9f6bbc7 Mon Sep 17 00:00:00 2001
From: Evgenii Kudriashov <evgenii.kudriashov at intel.com>
Date: Sun, 11 Jan 2026 08:08:47 -0800
Subject: [PATCH 6/6] Fix RegClassByHwMode.td as well
---
llvm/test/TableGen/RegClassByHwMode.td | 56 +++++++++++++-------------
1 file changed, 28 insertions(+), 28 deletions(-)
diff --git a/llvm/test/TableGen/RegClassByHwMode.td b/llvm/test/TableGen/RegClassByHwMode.td
index 853efd6c8cd1e..d88b501910f6b 100644
--- a/llvm/test/TableGen/RegClassByHwMode.td
+++ b/llvm/test/TableGen/RegClassByHwMode.td
@@ -270,37 +270,37 @@ include "Common/RegClassByHwModeCommon.td"
-// ISEL-GISEL: GIM_Try, /*On fail goto*//*Label 3*/ GIMT_Encode4(152),
+// ISEL-GISEL: GIM_Try, /*On fail goto*//*Label 3*/ GIMT_Encode4({{[0-9]+}}),
// ISEL-GISEL-NEXT: GIM_RootCheckType, /*Op*/0, /*Type*/GILLT_s64,
// ISEL-GISEL-NEXT: GIM_CheckAtomicOrdering, /*MI*/0, /*Order*/(uint8_t)AtomicOrdering::NotAtomic,
// ISEL-GISEL-NEXT: GIM_CheckMemorySizeEqualToLLT, /*MI*/0, /*MMO*/0, /*OpIdx*/0,
// ISEL-GISEL-NEXT: GIM_RootCheckRegBankForClass, /*Op*/0, /*RC*/GIMT_Encode2(MyTarget::XRegsRegClassID),
-// ISEL-GISEL-NEXT: GIM_Try, /*On fail goto*//*Label 4*/ GIMT_Encode4(105),
+// ISEL-GISEL-NEXT: GIM_Try, /*On fail goto*//*Label 4*/ GIMT_Encode4({{[0-9]+}}),
// ISEL-GISEL-NEXT: GIM_CheckPointerToAny, /*MI*/0, /*Op*/1, /*SizeInBits*/32,
// FIXME: This should be a direct check for regbank, not have an incorrect class
// ISEL-GISEL-NEXT: GIM_RootCheckRegBankForClass, /*Op*/1, /*RC*/GIMT_Encode2(MyTarget::PtrRegs32RegClassID),
-// ISEL-GISEL-NEXT: GIM_Try, /*On fail goto*//*Label 5*/ GIMT_Encode4(89), // Rule ID 1 //
+// ISEL-GISEL-NEXT: GIM_Try, /*On fail goto*//*Label 5*/ GIMT_Encode4({{[0-9]+}}), // Rule ID 4 //
// ISEL-GISEL-NEXT: GIM_CheckFeatures, GIMT_Encode2(GIFBS_HwMode0),
// ISEL-GISEL-NEXT: // (ld:{ *:[i64] } PtrRegOperand:{ *:[i32] }:$src)<<P:Predicate_unindexedload>><<P:Predicate_load>> => (MY_LOAD:{ *:[i64] } ?:{ *:[i32] }:$src)
// ISEL-GISEL-NEXT: GIR_MutateOpcode, /*InsnID*/0, /*RecycleInsnID*/0, /*Opcode*/GIMT_Encode2(MyTarget::MY_LOAD),
// ISEL-GISEL-NEXT: GIR_RootConstrainSelectedInstOperands,
// ISEL-GISEL-NEXT: // GIR_Coverage, 4,
// ISEL-GISEL-NEXT: GIR_Done,
-// ISEL-GISEL-NEXT: // Label 5: @85
-// ISEL-GISEL-NEXT: GIM_Try, /*On fail goto*//*Label 6*/ GIMT_Encode4(100), // Rule ID 5 //
+// ISEL-GISEL-NEXT: // Label 5: @{{[0-9]+}}
+// ISEL-GISEL-NEXT: GIM_Try, /*On fail goto*//*Label 6*/ GIMT_Encode4({{[0-9]+}}), // Rule ID 5 //
// ISEL-GISEL-NEXT: GIM_CheckFeatures, GIMT_Encode2(GIFBS_HwMode1),
// ISEL-GISEL-NEXT: // (ld:{ *:[i64] } PtrRegOperand:{ *:[i32] }:$src)<<P:Predicate_unindexedload>><<P:Predicate_load>> => (MY_LOAD:{ *:[i64] } ?:{ *:[i32] }:$src)
// ISEL-GISEL-NEXT: GIR_MutateOpcode, /*InsnID*/0, /*RecycleInsnID*/0, /*Opcode*/GIMT_Encode2(MyTarget::MY_LOAD),
// ISEL-GISEL-NEXT: GIR_RootConstrainSelectedInstOperands,
// ISEL-GISEL-NEXT: // GIR_Coverage, 5,
// ISEL-GISEL-NEXT: GIR_Done,
-// ISEL-GISEL-NEXT: // Label 6: @104
+// ISEL-GISEL-NEXT: // Label 6: @{{[0-9]+}}
// ISEL-GISEL-NEXT: GIM_Reject,
-// ISEL-GISEL-NEXT: // Label 4: @105
-// ISEL-GISEL-NEXT: GIM_Try, /*On fail goto*//*Label 7*/ GIMT_Encode4(128), // Rule ID 3 //
-// ISEL-GISEL-NEXT: GIM_CheckFeatures, GIMT_Encode2(GIFBS_HwMode0),
+// ISEL-GISEL-NEXT: // Label 4: @{{[0-9]+}}
+// ISEL-GISEL-NEXT: GIM_Try, /*On fail goto*//*Label 7*/ GIMT_Encode4({{[0-9]+}}), // Rule ID 6 //
+// ISEL-GISEL-NEXT: GIM_CheckFeatures, GIMT_Encode2(GIFBS_HwMode2),
// ISEL-GISEL-NEXT: // MIs[0] src
// ISEL-GISEL-NEXT: GIM_CheckPointerToAny, /*MI*/0, /*Op*/1, /*SizeInBits*/64,
// ISEL-GISEL-NEXT: GIM_RootCheckRegBankForClass, /*Op*/1, /*RC*/GIMT_Encode2(MyTarget::PtrRegs32RegClassID),
@@ -309,8 +309,8 @@ include "Common/RegClassByHwModeCommon.td"
// ISEL-GISEL-NEXT: GIR_RootConstrainSelectedInstOperands,
// ISEL-GISEL-NEXT: // GIR_Coverage, 6,
// ISEL-GISEL-NEXT: GIR_Done,
-// ISEL-GISEL-NEXT: // Label 7: @128
-// ISEL-GISEL-NEXT: GIM_Try, /*On fail goto*//*Label 8*/ GIMT_Encode4(151), // Rule ID 4 //
+// ISEL-GISEL-NEXT: // Label 7: @{{[0-9]+}}
+// ISEL-GISEL-NEXT: GIM_Try, /*On fail goto*//*Label 8*/ GIMT_Encode4({{[0-9]+}}), // Rule ID 7 //
// ISEL-GISEL-NEXT: GIM_CheckFeatures, GIMT_Encode2(GIFBS_HwMode3),
// ISEL-GISEL-NEXT: // MIs[0] src
// ISEL-GISEL-NEXT: GIM_CheckPointerToAny, /*MI*/0, /*Op*/1, /*SizeInBits*/32,
@@ -320,38 +320,38 @@ include "Common/RegClassByHwModeCommon.td"
// ISEL-GISEL-NEXT: GIR_RootConstrainSelectedInstOperands,
// ISEL-GISEL-NEXT: // GIR_Coverage, 7,
// ISEL-GISEL-NEXT: GIR_Done,
-// ISEL-GISEL-NEXT: // Label 8: @151
+// ISEL-GISEL-NEXT: // Label 8: @{{[0-9]+}}
// ISEL-GISEL-NEXT: GIM_Reject,
-// ISEL-GISEL-NEXT: // Label 3: @152
+// ISEL-GISEL-NEXT: // Label 3: @{{[0-9]+}}
// ISEL-GISEL-NEXT: GIM_Reject,
-// ISEL-GISEL-NEXT: // Label 1: @153
-// ISEL-GISEL-NEXT: GIM_Try, /*On fail goto*//*Label 9*/ GIMT_Encode4(190),
+// ISEL-GISEL-NEXT: // Label 1: @{{[0-9]+}}
+// ISEL-GISEL-NEXT: GIM_Try, /*On fail goto*//*Label 9*/ GIMT_Encode4({{[0-9]+}}),
// ISEL-GISEL-NEXT: GIM_RootCheckType, /*Op*/0, /*Type*/GILLT_s64,
// ISEL-GISEL-NEXT: GIM_CheckAtomicOrdering, /*MI*/0, /*Order*/(uint8_t)AtomicOrdering::NotAtomic,
// ISEL-GISEL-NEXT: GIM_CheckMemorySizeEqualToLLT, /*MI*/0, /*MMO*/0, /*OpIdx*/0,
// ISEL-GISEL-NEXT: GIM_RootCheckRegBankForClass, /*Op*/0, /*RC*/GIMT_Encode2(MyTarget::XRegsRegClassID),
-// ISEL-GISEL-NEXT: GIM_Try, /*On fail goto*//*Label 10*/ GIMT_Encode4(212),
+// ISEL-GISEL-NEXT: GIM_Try, /*On fail goto*//*Label 10*/ GIMT_Encode4({{[0-9]+}}),
// ISEL-GISEL-NEXT: GIM_CheckPointerToAny, /*MI*/0, /*Op*/1, /*SizeInBits*/32,
// ISEL-GISEL-NEXT: GIM_RootCheckRegBankForClass, /*Op*/1, /*RC*/GIMT_Encode2(MyTarget::PtrRegs32RegClassID),
-// ISEL-GISEL-NEXT: GIM_Try, /*On fail goto*//*Label 11*/ GIMT_Encode4(196), // Rule ID 0 //
+// ISEL-GISEL-NEXT: GIM_Try, /*On fail goto*//*Label 11*/ GIMT_Encode4({{[0-9]+}}), // Rule ID 0 //
// ISEL-GISEL-NEXT: GIM_CheckFeatures, GIMT_Encode2(GIFBS_HwMode0),
// ISEL-GISEL-NEXT: // (st XRegs_EvenIfRequired:{ *:[i64] }:$val, MyPtrRC:{ *:[i32] }:$src)<<P:Predicate_unindexedstore>><<P:Predicate_store>> => (MY_STORE XRegs_EvenIfRequired:{ *:[i64] }:$val, ?:{ *:[i32] }:$src)
// ISEL-GISEL-NEXT: GIR_MutateOpcode, /*InsnID*/0, /*RecycleInsnID*/0, /*Opcode*/GIMT_Encode2(MyTarget::MY_STORE),
// ISEL-GISEL-NEXT: GIR_RootConstrainSelectedInstOperands,
// ISEL-GISEL-NEXT: // GIR_Coverage, 0,
// ISEL-GISEL-NEXT: GIR_Done,
-// ISEL-GISEL-NEXT: // Label 11: @196
-// ISEL-GISEL-NEXT: GIM_Try, /*On fail goto*//*Label 12*/ GIMT_Encode4(211), // Rule ID 1 //
+// ISEL-GISEL-NEXT: // Label 11: @{{[0-9]+}}
+// ISEL-GISEL-NEXT: GIM_Try, /*On fail goto*//*Label 12*/ GIMT_Encode4({{[0-9]+}}), // Rule ID 1 //
// ISEL-GISEL-NEXT: GIM_CheckFeatures, GIMT_Encode2(GIFBS_HwMode1),
// ISEL-GISEL-NEXT: // (st XRegs_EvenIfRequired:{ *:[i64] }:$val, MyPtrRC:{ *:[i32] }:$src)<<P:Predicate_unindexedstore>><<P:Predicate_store>> => (MY_STORE XRegs_EvenIfRequired:{ *:[i64] }:$val, ?:{ *:[i32] }:$src)
// ISEL-GISEL-NEXT: GIR_MutateOpcode, /*InsnID*/0, /*RecycleInsnID*/0, /*Opcode*/GIMT_Encode2(MyTarget::MY_STORE),
// ISEL-GISEL-NEXT: GIR_RootConstrainSelectedInstOperands,
// ISEL-GISEL-NEXT: // GIR_Coverage, 1,
// ISEL-GISEL-NEXT: GIR_Done,
-// ISEL-GISEL-NEXT: // Label 12: @211
+// ISEL-GISEL-NEXT: // Label 12: @{{[0-9]+}}
// ISEL-GISEL-NEXT: GIM_Reject,
-// ISEL-GISEL-NEXT: // Label 10: @212
-// ISEL-GISEL-NEXT: GIM_Try, /*On fail goto*//*Label 13*/ GIMT_Encode4(235), // Rule ID 2 //
+// ISEL-GISEL-NEXT: // Label 10: @{{[0-9]+}}
+// ISEL-GISEL-NEXT: GIM_Try, /*On fail goto*//*Label 13*/ GIMT_Encode4({{[0-9]+}}), // Rule ID 2 //
// ISEL-GISEL-NEXT: GIM_CheckFeatures, GIMT_Encode2(GIFBS_HwMode2),
// ISEL-GISEL-NEXT: // MIs[0] src
// ISEL-GISEL-NEXT: GIM_CheckPointerToAny, /*MI*/0, /*Op*/1, /*SizeInBits*/64,
@@ -361,8 +361,8 @@ include "Common/RegClassByHwModeCommon.td"
// ISEL-GISEL-NEXT: GIR_RootConstrainSelectedInstOperands,
// ISEL-GISEL-NEXT: // GIR_Coverage, 2,
// ISEL-GISEL-NEXT: GIR_Done,
-// ISEL-GISEL-NEXT: // Label 13: @235
-// ISEL-GISEL-NEXT: GIM_Try, /*On fail goto*//*Label 14*/ GIMT_Encode4(258), // Rule ID 3 //
+// ISEL-GISEL-NEXT: // Label 13: @{{[0-9]+}}
+// ISEL-GISEL-NEXT: GIM_Try, /*On fail goto*//*Label 14*/ GIMT_Encode4({{[0-9]+}}), // Rule ID 3 //
// ISEL-GISEL-NEXT: GIM_CheckFeatures, GIMT_Encode2(GIFBS_HwMode3),
// ISEL-GISEL-NEXT: // MIs[0] src
// ISEL-GISEL-NEXT: GIM_CheckPointerToAny, /*MI*/0, /*Op*/1, /*SizeInBits*/32,
@@ -372,13 +372,13 @@ include "Common/RegClassByHwModeCommon.td"
// ISEL-GISEL-NEXT: GIR_RootConstrainSelectedInstOperands,
// ISEL-GISEL-NEXT: // GIR_Coverage, 3,
// ISEL-GISEL-NEXT: GIR_Done,
-// ISEL-GISEL-NEXT: // Label 14: @258
+// ISEL-GISEL-NEXT: // Label 14: @{{[0-9]+}}
// ISEL-GISEL-NEXT: GIM_Reject,
-// ISEL-GISEL-NEXT: // Label 9: @259
+// ISEL-GISEL-NEXT: // Label 9: @{{[0-9]+}}
// ISEL-GISEL-NEXT: GIM_Reject,
-// ISEL-GISEL-NEXT: // Label 2: @260
+// ISEL-GISEL-NEXT: // Label 2: @{{[0-9]+}}
// ISEL-GISEL-NEXT: GIM_Reject,
-// ISEL-GISEL-NEXT: }; // Size: 261 bytes
+// ISEL-GISEL-NEXT: }; // Size: 265 bytes
def HasAlignedRegisters : Predicate<"Subtarget->hasAlignedRegisters()">;
def HasUnalignedRegisters : Predicate<"Subtarget->hasUnalignedRegisters()">;
More information about the llvm-commits
mailing list