https://github.com/llvmbot created https://github.com/llvm/llvm-project/pull/223447
Backport 09be00c800cf9ae03a2c8fbdc215c259ac39f30f Requested by: @davemgreen >From 1ef5a1258d32ef1d23db7ece481d3a4ea88e941c Mon Sep 17 00:00:00 2001 From: David Green <[email protected]> Date: Mon, 14 Sep 2026 16:20:13 +0100 Subject: [PATCH] [GlobalISel][AArch64] Do not remove dst type predicates from pattern children nodes. (#221576) Given an instruction with a non-concrete type (G_CONCAT_VECTOR), with a child pattern instruction with a concrete type (G_FPTRUNC), the concrete type check for the child would incorrectly be removed. This patch makes sure they remain. This makes the match table a little larger, but many should be able to be optimized away (providing that the two operands with the same type can be matched up). Fixes #221458 (cherry picked from commit 09be00c800cf9ae03a2c8fbdc215c259ac39f30f) --- llvm/test/CodeGen/AArch64/fptrunc.ll | 1 + .../MatchTableOptimizerTypes.td | 63 +++++++++++++++++++ .../Common/GlobalISel/MatchTable/Matchers.cpp | 10 ++- 3 files changed, 73 insertions(+), 1 deletion(-) create mode 100644 llvm/test/TableGen/GlobalISelEmitter/MatchTableOptimizerTypes.td diff --git a/llvm/test/CodeGen/AArch64/fptrunc.ll b/llvm/test/CodeGen/AArch64/fptrunc.ll index 56b20eaac1c80..1e968eeea3d31 100644 --- a/llvm/test/CodeGen/AArch64/fptrunc.ll +++ b/llvm/test/CodeGen/AArch64/fptrunc.ll @@ -2,6 +2,7 @@ ; RUN: llc -mtriple=aarch64 -global-isel=0 -verify-machineinstrs %s -o - | FileCheck %s --check-prefixes=CHECK,CHECK-SD ; RUN: llc -mtriple=aarch64 -global-isel=1 -verify-machineinstrs %s -o - | FileCheck %s --check-prefixes=CHECK,CHECK-GI ; RUN: llc -mtriple=aarch64 -global-isel=1 -mattr=+fullfp16,+bf16 -verify-machineinstrs %s -o - | FileCheck %s --check-prefixes=CHECK,CHECK-GI +; RUN: llc -mtriple=aarch64 -global-isel=1 -mattr=+bf16 -verify-machineinstrs %s -o - | FileCheck %s --check-prefixes=CHECK,CHECK-GI define float @fptrunc_f64_f32(double %a) { ; CHECK-LABEL: fptrunc_f64_f32: diff --git a/llvm/test/TableGen/GlobalISelEmitter/MatchTableOptimizerTypes.td b/llvm/test/TableGen/GlobalISelEmitter/MatchTableOptimizerTypes.td new file mode 100644 index 0000000000000..ed264b02be1df --- /dev/null +++ b/llvm/test/TableGen/GlobalISelEmitter/MatchTableOptimizerTypes.td @@ -0,0 +1,63 @@ +// RUN: llvm-tblgen %s -gen-global-isel -gisel-extended-llt -optimize-match-table=true -I %p/../../../include -I %p/../Common | FileCheck %s + +include "llvm/Target/Target.td" +include "GlobalISelEmitterCommon.td" + +// Check the MatchTable does not remove necessary type checks + +def V1 : Register<"v1"> { let Namespace = "MyTarget"; } +def FPR64 : RegisterClass<"MyTarget", [v4f16, v4bf16], 64, (add V1)>; +def FPR128 : RegisterClass<"MyTarget", [v4f32, v8f16, v8bf16], 128, (add V1)>; +def BF16I : I<(outs FPR128:$dst), (ins FPR64:$Rn, FPR128:$Rm), []>; +def F16I : I<(outs FPR128:$dst), (ins FPR64:$Rn, FPR128:$Rm), []>; + +def : Pat<(v8bf16 (concat_vectors (v4bf16 FPR64:$Rn), (v4bf16 (fpround (v4f32 FPR128:$Rm))))), + (BF16I $Rn, $Rm)>; +def : Pat<(v8f16 (concat_vectors (v4f16 FPR64:$Rn), (v4f16 (fpround (v4f32 FPR128:$Rm))))), + (F16I $Rn, $Rm)>; + +// CHECK: constexpr static uint8_t MatchTable0[] = { +// CHECK-NEXT: /* 0 */ GIM_Try, /*On fail goto*//*Label 0*/ GIMT_Encode4(112), +// CHECK-NEXT: /* 5 */ GIM_CheckOpcode, /*MI*/0, GIMT_Encode2(TargetOpcode::G_CONCAT_VECTORS), +// CHECK-NEXT: /* 9 */ GIM_CheckNumOperands, /*MI*/0, /*Expected*/3, +// CHECK-NEXT: /* 12 */ GIM_RootCheckType, /*Op*/0, /*Type*/GILLT_v8s16, +// CHECK-NEXT: /* 15 */ GIM_RootCheckType, /*Op*/1, /*Type*/GILLT_v4s16, +// CHECK-NEXT: /* 18 */ GIM_RootCheckType, /*Op*/2, /*Type*/GILLT_v4s16, +// CHECK-NEXT: /* 21 */ GIM_RootCheckRegBankForClass, /*Op*/0, /*RC*/GIMT_Encode2(MyTarget::FPR128RegClassID), +// CHECK-NEXT: /* 25 */ GIM_RootCheckRegBankForClass, /*Op*/1, /*RC*/GIMT_Encode2(MyTarget::FPR64RegClassID), +// CHECK-NEXT: /* 29 */ GIM_Try, /*On fail goto*//*Label 1*/ GIMT_Encode4(70), // Rule ID 0 // +// CHECK-NEXT: /* 34 */ GIM_RecordInsn, /*DefineMI*/1, /*MI*/0, /*OpIdx*/2, // MIs[1] +// CHECK-NEXT: /* 38 */ GIM_CheckOpcode, /*MI*/1, GIMT_Encode2(TargetOpcode::G_FPTRUNC), +// CHECK-NEXT: /* 42 */ GIM_CheckType, /*MI*/1, /*Op*/0, /*Type*/GILLT_v4bf16, +// CHECK-NEXT: /* 46 */ GIM_CheckType, /*MI*/1, /*Op*/1, /*Type*/GILLT_v4f32, +// CHECK-NEXT: /* 50 */ GIM_CheckRegBankForClass, /*MI*/1, /*Op*/1, /*RC*/GIMT_Encode2(MyTarget::FPR128RegClassID), +// CHECK-NEXT: /* 55 */ GIM_CheckIsSafeToFold, /*NumInsns*/1, +// CHECK-NEXT: /* 57 */ // (concat_vectors:{ *:[v8bf16] } FPR64:{ *:[v4bf16] }:$Rn, (fpround:{ *:[v4bf16] } FPR128:{ *:[v4f32] }:$Rm)) => (BF16I:{ *:[v8bf16] } ?:{ *:[v4bf16] }:$Rn, ?:{ *:[v4f32] }:$Rm) +// CHECK-NEXT: /* 57 */ GIR_BuildRootMI, /*Opcode*/GIMT_Encode2(MyTarget::BF16I), +// CHECK-NEXT: /* 60 */ GIR_RootToRootCopy, /*OpIdx*/0, // DstI[dst] +// CHECK-NEXT: /* 62 */ GIR_RootToRootCopy, /*OpIdx*/1, // Rn +// CHECK-NEXT: /* 64 */ GIR_Copy, /*NewInsnID*/0, /*OldInsnID*/1, /*OpIdx*/1, // Rm +// CHECK-NEXT: /* 68 */ GIR_RootConstrainSelectedInstOperands, +// CHECK-NEXT: /* 69 */ // GIR_Coverage, 0, +// CHECK-NEXT: /* 69 */ GIR_EraseRootFromParent_Done, +// CHECK-NEXT: /* 70 */ // Label 1: @70 +// CHECK-NEXT: /* 70 */ GIM_Try, /*On fail goto*//*Label 2*/ GIMT_Encode4(111), // Rule ID 1 // +// CHECK-NEXT: /* 75 */ GIM_RecordInsn, /*DefineMI*/1, /*MI*/0, /*OpIdx*/2, // MIs[1] +// CHECK-NEXT: /* 79 */ GIM_CheckOpcode, /*MI*/1, GIMT_Encode2(TargetOpcode::G_FPTRUNC), +// CHECK-NEXT: /* 83 */ GIM_CheckType, /*MI*/1, /*Op*/0, /*Type*/GILLT_v4f16, +// CHECK-NEXT: /* 87 */ GIM_CheckType, /*MI*/1, /*Op*/1, /*Type*/GILLT_v4f32, +// CHECK-NEXT: /* 91 */ GIM_CheckRegBankForClass, /*MI*/1, /*Op*/1, /*RC*/GIMT_Encode2(MyTarget::FPR128RegClassID), +// CHECK-NEXT: /* 96 */ GIM_CheckIsSafeToFold, /*NumInsns*/1, +// CHECK-NEXT: /* 98 */ // (concat_vectors:{ *:[v8f16] } FPR64:{ *:[v4f16] }:$Rn, (fpround:{ *:[v4f16] } FPR128:{ *:[v4f32] }:$Rm)) => (F16I:{ *:[v8f16] } ?:{ *:[v4f16] }:$Rn, ?:{ *:[v4f32] }:$Rm) +// CHECK-NEXT: /* 98 */ GIR_BuildRootMI, /*Opcode*/GIMT_Encode2(MyTarget::F16I), +// CHECK-NEXT: /* 101 */ GIR_RootToRootCopy, /*OpIdx*/0, // DstI[dst] +// CHECK-NEXT: /* 103 */ GIR_RootToRootCopy, /*OpIdx*/1, // Rn +// CHECK-NEXT: /* 105 */ GIR_Copy, /*NewInsnID*/0, /*OldInsnID*/1, /*OpIdx*/1, // Rm +// CHECK-NEXT: /* 109 */ GIR_RootConstrainSelectedInstOperands, +// CHECK-NEXT: /* 110 */ // GIR_Coverage, 1, +// CHECK-NEXT: /* 110 */ GIR_EraseRootFromParent_Done, +// CHECK-NEXT: /* 111 */ // Label 2: @111 +// CHECK-NEXT: /* 111 */ GIM_Reject, +// CHECK-NEXT: /* 112 */ // Label 0: @112 +// CHECK-NEXT: /* 112 */ GIM_Reject, +// CHECK-NEXT: /* 113 */ }; // Size: 113 bytes diff --git a/llvm/utils/TableGen/Common/GlobalISel/MatchTable/Matchers.cpp b/llvm/utils/TableGen/Common/GlobalISel/MatchTable/Matchers.cpp index 7f22cbfc7f58d..531f9c2703bfa 100644 --- a/llvm/utils/TableGen/Common/GlobalISel/MatchTable/Matchers.cpp +++ b/llvm/utils/TableGen/Common/GlobalISel/MatchTable/Matchers.cpp @@ -1621,8 +1621,16 @@ void InstructionMatcher::optimize() { if (InsnVarID > 0) { assert(!Operands.empty() && "Nested instruction is expected to def a vreg"); - for (auto &OP : Operands[0]->predicates()) + for (auto &OP : Operands[0]->predicates()) { + // LLTOperandMatcher need to be kept as they may have a more specific type + // than the parent instruction type. + if (const auto *LLTPred = dyn_cast<LLTOperandMatcher>(&*OP)) { + if (!LLTPred->getTy().get().isAnyScalar() && + !LLTPred->getTy().get().isAnyVector()) + continue; + } OP.reset(); + } Operands[0]->eraseNullPredicates(); } for (auto &OM : Operands) { _______________________________________________ llvm-branch-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits
