From 7683b54ca4bd1248fbeee3735f1de59722e14e4e Mon Sep 17 00:00:00 2001 From: Nathan Corbyn Date: Thu, 20 Nov 2025 10:50:21 +0000 Subject: [PATCH 1/4] [AArch64][GlobalISel] Don't crash when legalising vector G_SHL --- .../AArch64/GISel/AArch64LegalizerInfo.cpp | 8 ++--- .../AArch64/GlobalISel/legalize-shl-crash.ll | 29 +++++++++++++++++++ 2 files changed, 33 insertions(+), 4 deletions(-) create mode 100644 llvm/test/CodeGen/AArch64/GlobalISel/legalize-shl-crash.ll diff --git a/llvm/lib/Target/AArch64/GISel/AArch64LegalizerInfo.cpp b/llvm/lib/Target/AArch64/GISel/AArch64LegalizerInfo.cpp index 089b0b2feb231..c0c8ceb0122b9 100644 --- a/llvm/lib/Target/AArch64/GISel/AArch64LegalizerInfo.cpp +++ b/llvm/lib/Target/AArch64/GISel/AArch64LegalizerInfo.cpp @@ -216,15 +216,15 @@ AArch64LegalizerInfo::AArch64LegalizerInfo(const AArch64Subtarget &ST) .widenScalarToNextPow2(0) .clampScalar(1, s32, s64) .clampScalar(0, s32, s64) + .minScalarSameAs(1, 0) + .minScalarEltSameAsIf(isVector(0), 1, 0) + .maxScalarEltSameAsIf(isVector(0), 1, 0) .clampNumElements(0, v8s8, v16s8) .clampNumElements(0, v4s16, v8s16) .clampNumElements(0, v2s32, v4s32) .clampNumElements(0, v2s64, v2s64) .moreElementsToNextPow2(0) - .minScalarSameAs(1, 0) - .scalarizeIf(scalarOrEltWiderThan(0, 64), 0) - .minScalarEltSameAsIf(isVector(0), 1, 0) - .maxScalarEltSameAsIf(isVector(0), 1, 0); + .scalarizeIf(scalarOrEltWiderThan(0, 64), 0); getActionDefinitionsBuilder(G_PTR_ADD) .legalFor({{p0, s64}, {v2p0, v2s64}}) diff --git a/llvm/test/CodeGen/AArch64/GlobalISel/legalize-shl-crash.ll b/llvm/test/CodeGen/AArch64/GlobalISel/legalize-shl-crash.ll new file mode 100644 index 0000000000000..b7a5cdc77aa35 --- /dev/null +++ b/llvm/test/CodeGen/AArch64/GlobalISel/legalize-shl-crash.ll @@ -0,0 +1,29 @@ +; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 6 +; RUN: llc -global-isel -o - %s | FileCheck %s + +target triple = "aarch64-unknown-unknown" + +; Check we don't crash here. + +define <2 x i8> @test() { +; CHECK-LABEL: test: +; CHECK: // %bb.0: // %entry +; CHECK-NEXT: mov w8, #1 // =0x1 +; CHECK-NEXT: mov w9, #0 // =0x0 +; CHECK-NEXT: fmov s0, w8 +; CHECK-NEXT: fmov s1, w9 +; CHECK-NEXT: mov v0.b[1], w8 +; CHECK-NEXT: mov v1.b[1], w9 +; CHECK-NEXT: ushl v0.8b, v0.8b, v1.8b +; CHECK-NEXT: umov w8, v0.b[0] +; CHECK-NEXT: umov w9, v0.b[1] +; CHECK-NEXT: fmov s0, w8 +; CHECK-NEXT: mov v0.s[1], w9 +; CHECK-NEXT: // kill: def $d0 killed $d0 killed $q0 +; CHECK-NEXT: ret +entry: + %zeroes = zext <2 x i1> zeroinitializer to <2 x i32> + %ones = shl <2 x i32> splat (i32 1), %zeroes + %ones.trunc = trunc <2 x i32> %ones to <2 x i8> + ret <2 x i8> %ones.trunc +} From 92db3f75ebe9413662f3c061a5eff823ee5abe29 Mon Sep 17 00:00:00 2001 From: Nathan Corbyn Date: Mon, 1 Dec 2025 15:43:34 +0000 Subject: [PATCH 2/4] Modify handling of `G_*SH*` opcodes in `LegalizerHelper::moreElementsVector()` --- .../CodeGen/GlobalISel/LegalizerHelper.cpp | 21 +++++++++++++------ .../AArch64/GISel/AArch64LegalizerInfo.cpp | 8 +++---- 2 files changed, 19 insertions(+), 10 deletions(-) diff --git a/llvm/lib/CodeGen/GlobalISel/LegalizerHelper.cpp b/llvm/lib/CodeGen/GlobalISel/LegalizerHelper.cpp index 120c38ab8404c..1aa1d465d8da6 100644 --- a/llvm/lib/CodeGen/GlobalISel/LegalizerHelper.cpp +++ b/llvm/lib/CodeGen/GlobalISel/LegalizerHelper.cpp @@ -6684,13 +6684,24 @@ LegalizerHelper::moreElementsVector(MachineInstr &MI, unsigned TypeIdx, case TargetOpcode::G_FMAXIMUMNUM: case TargetOpcode::G_STRICT_FADD: case TargetOpcode::G_STRICT_FSUB: - case TargetOpcode::G_STRICT_FMUL: + case TargetOpcode::G_STRICT_FMUL: { + Observer.changingInstr(MI); + moreElementsVectorSrc(MI, MoreTy, 1); + moreElementsVectorSrc(MI, MoreTy, 2); + moreElementsVectorDst(MI, MoreTy, 0); + Observer.changedInstr(MI); + return Legalized; + } case TargetOpcode::G_SHL: case TargetOpcode::G_ASHR: case TargetOpcode::G_LSHR: { Observer.changingInstr(MI); moreElementsVectorSrc(MI, MoreTy, 1); - moreElementsVectorSrc(MI, MoreTy, 2); + // The shift operand may have a different scalar type from the source and + // destination operands. + LLT ShiftMoreTy = MoreTy.changeElementType( + MRI.getType(MI.getOperand(2).getReg()).getElementType()); + moreElementsVectorSrc(MI, ShiftMoreTy, 2); moreElementsVectorDst(MI, MoreTy, 0); Observer.changedInstr(MI); return Legalized; @@ -6806,12 +6817,10 @@ LegalizerHelper::moreElementsVector(MachineInstr &MI, unsigned TypeIdx, LLT DstExtTy; if (TypeIdx == 0) { DstExtTy = MoreTy; - SrcExtTy = LLT::fixed_vector( - MoreTy.getNumElements(), + SrcExtTy = MoreTy.changeElementType( MRI.getType(MI.getOperand(1).getReg()).getElementType()); } else { - DstExtTy = LLT::fixed_vector( - MoreTy.getNumElements(), + DstExtTy = MoreTy.changeElementType( MRI.getType(MI.getOperand(0).getReg()).getElementType()); SrcExtTy = MoreTy; } diff --git a/llvm/lib/Target/AArch64/GISel/AArch64LegalizerInfo.cpp b/llvm/lib/Target/AArch64/GISel/AArch64LegalizerInfo.cpp index c0c8ceb0122b9..089b0b2feb231 100644 --- a/llvm/lib/Target/AArch64/GISel/AArch64LegalizerInfo.cpp +++ b/llvm/lib/Target/AArch64/GISel/AArch64LegalizerInfo.cpp @@ -216,15 +216,15 @@ AArch64LegalizerInfo::AArch64LegalizerInfo(const AArch64Subtarget &ST) .widenScalarToNextPow2(0) .clampScalar(1, s32, s64) .clampScalar(0, s32, s64) - .minScalarSameAs(1, 0) - .minScalarEltSameAsIf(isVector(0), 1, 0) - .maxScalarEltSameAsIf(isVector(0), 1, 0) .clampNumElements(0, v8s8, v16s8) .clampNumElements(0, v4s16, v8s16) .clampNumElements(0, v2s32, v4s32) .clampNumElements(0, v2s64, v2s64) .moreElementsToNextPow2(0) - .scalarizeIf(scalarOrEltWiderThan(0, 64), 0); + .minScalarSameAs(1, 0) + .scalarizeIf(scalarOrEltWiderThan(0, 64), 0) + .minScalarEltSameAsIf(isVector(0), 1, 0) + .maxScalarEltSameAsIf(isVector(0), 1, 0); getActionDefinitionsBuilder(G_PTR_ADD) .legalFor({{p0, s64}, {v2p0, v2s64}}) From 8e7ad6589016f38fe4a9aaeaae25b5c64a85a51a Mon Sep 17 00:00:00 2001 From: Nathan Corbyn Date: Mon, 1 Dec 2025 15:48:02 +0000 Subject: [PATCH 3/4] Relocate test case --- .../AArch64/GlobalISel/legalize-shl-crash.ll | 29 ------------------- llvm/test/CodeGen/AArch64/shift.ll | 28 ++++++++++++++++++ 2 files changed, 28 insertions(+), 29 deletions(-) delete mode 100644 llvm/test/CodeGen/AArch64/GlobalISel/legalize-shl-crash.ll diff --git a/llvm/test/CodeGen/AArch64/GlobalISel/legalize-shl-crash.ll b/llvm/test/CodeGen/AArch64/GlobalISel/legalize-shl-crash.ll deleted file mode 100644 index b7a5cdc77aa35..0000000000000 --- a/llvm/test/CodeGen/AArch64/GlobalISel/legalize-shl-crash.ll +++ /dev/null @@ -1,29 +0,0 @@ -; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 6 -; RUN: llc -global-isel -o - %s | FileCheck %s - -target triple = "aarch64-unknown-unknown" - -; Check we don't crash here. - -define <2 x i8> @test() { -; CHECK-LABEL: test: -; CHECK: // %bb.0: // %entry -; CHECK-NEXT: mov w8, #1 // =0x1 -; CHECK-NEXT: mov w9, #0 // =0x0 -; CHECK-NEXT: fmov s0, w8 -; CHECK-NEXT: fmov s1, w9 -; CHECK-NEXT: mov v0.b[1], w8 -; CHECK-NEXT: mov v1.b[1], w9 -; CHECK-NEXT: ushl v0.8b, v0.8b, v1.8b -; CHECK-NEXT: umov w8, v0.b[0] -; CHECK-NEXT: umov w9, v0.b[1] -; CHECK-NEXT: fmov s0, w8 -; CHECK-NEXT: mov v0.s[1], w9 -; CHECK-NEXT: // kill: def $d0 killed $d0 killed $q0 -; CHECK-NEXT: ret -entry: - %zeroes = zext <2 x i1> zeroinitializer to <2 x i32> - %ones = shl <2 x i32> splat (i32 1), %zeroes - %ones.trunc = trunc <2 x i32> %ones to <2 x i8> - ret <2 x i8> %ones.trunc -} diff --git a/llvm/test/CodeGen/AArch64/shift.ll b/llvm/test/CodeGen/AArch64/shift.ll index 9827cb3526f99..f67ccc0af9501 100644 --- a/llvm/test/CodeGen/AArch64/shift.ll +++ b/llvm/test/CodeGen/AArch64/shift.ll @@ -1033,6 +1033,34 @@ define <2 x i128> @lshr_v2i128(<2 x i128> %0, <2 x i128> %1){ ret <2 x i128> %3 } +define <2 x i8> @pr168848() { +; CHECK-SD-LABEL: pr168848: +; CHECK-SD: // %bb.0: // %entry +; CHECK-SD-NEXT: movi v0.2s, #1 +; CHECK-SD-NEXT: ret +; +; CHECK-GI-LABEL: pr168848: +; CHECK-GI: // %bb.0: // %entry +; CHECK-GI-NEXT: mov w8, #1 // =0x1 +; CHECK-GI-NEXT: mov w9, #0 // =0x0 +; CHECK-GI-NEXT: fmov s0, w8 +; CHECK-GI-NEXT: fmov s1, w9 +; CHECK-GI-NEXT: mov v0.b[1], w8 +; CHECK-GI-NEXT: mov v1.b[1], w9 +; CHECK-GI-NEXT: ushl v0.8b, v0.8b, v1.8b +; CHECK-GI-NEXT: umov w8, v0.b[0] +; CHECK-GI-NEXT: umov w9, v0.b[1] +; CHECK-GI-NEXT: fmov s0, w8 +; CHECK-GI-NEXT: mov v0.s[1], w9 +; CHECK-GI-NEXT: // kill: def $d0 killed $d0 killed $q0 +; CHECK-GI-NEXT: ret +entry: + %zeroes = zext <2 x i1> zeroinitializer to <2 x i32> + %ones = shl <2 x i32> splat (i32 1), %zeroes + %ones.trunc = trunc <2 x i32> %ones to <2 x i8> + ret <2 x i8> %ones.trunc +} + ; ===== Vector with Non-Pow 2 Width ===== define <3 x i8> @shl_v3i8(<3 x i8> %0, <3 x i8> %1){ From 0425039642d0d2804c90f15c97b4566dcf899d19 Mon Sep 17 00:00:00 2001 From: Nathan Corbyn Date: Mon, 1 Dec 2025 16:38:59 +0000 Subject: [PATCH 4/4] Make sure the test case won't be optimised out --- llvm/test/CodeGen/AArch64/shift.ll | 23 +++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/llvm/test/CodeGen/AArch64/shift.ll b/llvm/test/CodeGen/AArch64/shift.ll index f67ccc0af9501..98c7f673ecd01 100644 --- a/llvm/test/CodeGen/AArch64/shift.ll +++ b/llvm/test/CodeGen/AArch64/shift.ll @@ -1033,21 +1033,24 @@ define <2 x i128> @lshr_v2i128(<2 x i128> %0, <2 x i128> %1){ ret <2 x i128> %3 } -define <2 x i8> @pr168848() { +define <2 x i8> @pr168848(<2 x i1> %shift) { ; CHECK-SD-LABEL: pr168848: ; CHECK-SD: // %bb.0: // %entry -; CHECK-SD-NEXT: movi v0.2s, #1 +; CHECK-SD-NEXT: movi v1.2s, #1 +; CHECK-SD-NEXT: and v0.8b, v0.8b, v1.8b +; CHECK-SD-NEXT: ushl v0.2s, v1.2s, v0.2s ; CHECK-SD-NEXT: ret ; ; CHECK-GI-LABEL: pr168848: ; CHECK-GI: // %bb.0: // %entry +; CHECK-GI-NEXT: movi v1.2s, #1 ; CHECK-GI-NEXT: mov w8, #1 // =0x1 -; CHECK-GI-NEXT: mov w9, #0 // =0x0 -; CHECK-GI-NEXT: fmov s0, w8 -; CHECK-GI-NEXT: fmov s1, w9 -; CHECK-GI-NEXT: mov v0.b[1], w8 -; CHECK-GI-NEXT: mov v1.b[1], w9 -; CHECK-GI-NEXT: ushl v0.8b, v0.8b, v1.8b +; CHECK-GI-NEXT: and v0.8b, v0.8b, v1.8b +; CHECK-GI-NEXT: fmov s1, w8 +; CHECK-GI-NEXT: uzp1 v0.4h, v0.4h, v0.4h +; CHECK-GI-NEXT: mov v1.b[1], w8 +; CHECK-GI-NEXT: uzp1 v0.8b, v0.8b, v0.8b +; CHECK-GI-NEXT: ushl v0.8b, v1.8b, v0.8b ; CHECK-GI-NEXT: umov w8, v0.b[0] ; CHECK-GI-NEXT: umov w9, v0.b[1] ; CHECK-GI-NEXT: fmov s0, w8 @@ -1055,8 +1058,8 @@ define <2 x i8> @pr168848() { ; CHECK-GI-NEXT: // kill: def $d0 killed $d0 killed $q0 ; CHECK-GI-NEXT: ret entry: - %zeroes = zext <2 x i1> zeroinitializer to <2 x i32> - %ones = shl <2 x i32> splat (i32 1), %zeroes + %shift.zext = zext <2 x i1> %shift to <2 x i32> + %ones = shl <2 x i32> splat (i32 1), %shift.zext %ones.trunc = trunc <2 x i32> %ones to <2 x i8> ret <2 x i8> %ones.trunc }