From be13748efcc8fcfe37d49118ad6bbf742306b832 Mon Sep 17 00:00:00 2001 From: Erika Hunhoff Date: Thu, 11 Jun 2026 12:00:52 -0600 Subject: [PATCH] [AIE] Fix instruction-select crash on unpack of a non-load value selectG_AIE_LOAD_UNPACK assumes the def feeding an unpack intrinsic is a load, but it only checks mayLoad() before calling getLoadStoreSize(), which dereferences the instruction's first memory operand. The SRS narrowing intrinsic (the lowering of acc.to_vector()) reports mayLoad() yet carries no memory operand, so feeding its result directly into aie::unpack crashed instruction-select with a SIGSEGV. Guard the combine on memoperands_empty() in both the AIE2 and AIE2P selectors so a non-load producer falls back to normal VUNPACK selection. Co-Authored-By: Claude Opus 4 (1M context) --- .../Target/AIE/AIE2InstructionSelector.cpp | 6 ++- .../AIE/aie2p/AIE2PInstructionSelector.cpp | 6 ++- .../inst-select-unpack-non-load.mir | 49 +++++++++++++++++++ .../inst-select-unpack-non-load.mir | 48 ++++++++++++++++++ 4 files changed, 107 insertions(+), 2 deletions(-) create mode 100644 llvm/test/CodeGen/AIE/aie2/GlobalISel/inst-select-unpack-non-load.mir create mode 100644 llvm/test/CodeGen/AIE/aie2p/GlobalIsel/inst-select-unpack-non-load.mir diff --git a/llvm/lib/Target/AIE/AIE2InstructionSelector.cpp b/llvm/lib/Target/AIE/AIE2InstructionSelector.cpp index 8c269b5b74e5..4d2f54e4c6c8 100644 --- a/llvm/lib/Target/AIE/AIE2InstructionSelector.cpp +++ b/llvm/lib/Target/AIE/AIE2InstructionSelector.cpp @@ -640,7 +640,11 @@ AIE2InstructionSelector::getCombinedOpcodeUNPACKLoad( Intrinsic::aie2_unpack_I16_I8)) return {}; - if (!MemOp.mayLoad()) + // The unpack may be fed by an op that reports mayLoad() but is not an actual + // memory access (e.g. the SRS narrowing intrinsic that lowers + // acc.to_vector()). Such ops carry no memory operand, so bail out + // before getLoadStoreSize() dereferences a non-existent one. + if (!MemOp.mayLoad() || MemOp.memoperands_empty()) return {}; assert(getLoadStoreSize(MemOp) == 256 && "Unexpected VLDA.UNPACK size"); diff --git a/llvm/lib/Target/AIE/aie2p/AIE2PInstructionSelector.cpp b/llvm/lib/Target/AIE/aie2p/AIE2PInstructionSelector.cpp index 950b4b15258b..5997fc57a368 100644 --- a/llvm/lib/Target/AIE/aie2p/AIE2PInstructionSelector.cpp +++ b/llvm/lib/Target/AIE/aie2p/AIE2PInstructionSelector.cpp @@ -2747,7 +2747,11 @@ AIE2PInstructionSelector::getCombinedOpcodeUNPACKLoad( CombOpInstID != Intrinsic::aie2p_unpack_I1024_I8_I4)) return {}; - if (!MemOp.mayLoad()) + // The unpack may be fed by an op that reports mayLoad() but is not an actual + // memory access (e.g. the SRS narrowing intrinsic that lowers + // acc.to_vector()). Such ops carry no memory operand, so bail out + // before getLoadStoreSize() dereferences a non-existent one. + if (!MemOp.mayLoad() || MemOp.memoperands_empty()) return {}; assert(((getLoadStoreSize(MemOp) == 256 && diff --git a/llvm/test/CodeGen/AIE/aie2/GlobalISel/inst-select-unpack-non-load.mir b/llvm/test/CodeGen/AIE/aie2/GlobalISel/inst-select-unpack-non-load.mir new file mode 100644 index 000000000000..ce26a5756f77 --- /dev/null +++ b/llvm/test/CodeGen/AIE/aie2/GlobalISel/inst-select-unpack-non-load.mir @@ -0,0 +1,49 @@ +# NOTE: Assertions have been autogenerated by utils/update_mir_test_checks.py +# +# This file is licensed under the Apache License v2.0 with LLVM Exceptions. +# See https://llvm.org/LICENSE.txt for license information. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +# +# (c) Copyright 2026 Advanced Micro Devices, Inc. or its affiliates + +# RUN: llc -mtriple aie2 -run-pass=instruction-select %s -verify-machineinstrs -o - | FileCheck %s + +# The VLDB.UNPACK combine in selectG_AIE_LOAD_UNPACK must only fire when the +# def feeding the unpack is an actual load. Here the unpack consumes the result +# of an SRS narrowing intrinsic (the lowering of acc.to_vector()), which +# reports mayLoad() but carries no memory operand. Previously the combine path +# called getLoadStoreSize() on it and dereferenced a non-existent memoperand, +# crashing instruction-select. It must instead fall back to the normal VUNPACK +# selection. + +--- +name: unpack_of_srs_not_load +alignment: 16 +legalized: true +regBankSelected: true +body: | + bb.1.entry: + liveins: $p0 + ; CHECK-LABEL: name: unpack_of_srs_not_load + ; CHECK: liveins: $p0 + ; CHECK-NEXT: {{ $}} + ; CHECK-NEXT: [[COPY:%[0-9]+]]:ep = COPY $p0 + ; CHECK-NEXT: [[DEF:%[0-9]+]]:acc1024 = IMPLICIT_DEF + ; CHECK-NEXT: [[MOV_RLC_imm10_pseudo:%[0-9]+]]:er = MOV_RLC_imm10_pseudo 8 + ; CHECK-NEXT: [[COPY1:%[0-9]+]]:mss = COPY [[MOV_RLC_imm10_pseudo]] + ; CHECK-NEXT: [[VSRS_S8_S32_mv_w_srs:%[0-9]+]]:vec256 = VSRS_S8_S32_mv_w_srs [[DEF]], [[COPY1]], implicit-def dead $srsrs_of, implicit $crsat, implicit $crrnd + ; CHECK-NEXT: [[VUNPACK_S16_S8_:%[0-9]+]]:vec512 = VUNPACK_S16_S8 [[VSRS_S8_S32_mv_w_srs]] + ; CHECK-NEXT: [[COPY2:%[0-9]+]]:vec256 = COPY [[VUNPACK_S16_S8_]].sub_256_lo + ; CHECK-NEXT: [[COPY3:%[0-9]+]]:vec256 = COPY [[VUNPACK_S16_S8_]].sub_256_hi + ; CHECK-NEXT: VST_dmw_sts_w_ag_idx_imm [[COPY3]], [[COPY]], 32 :: (store (<16 x s16>) into unknown-address + 32) + ; CHECK-NEXT: VST_dmw_sts_w_ag_idx_imm [[COPY2]], [[COPY]], 0 :: (store (<16 x s16>), align 64) + ; CHECK-NEXT: PseudoRET implicit $lr + %0:ptrregbank(p0) = COPY $p0 + %1:accregbank(<16 x s64>) = G_IMPLICIT_DEF + %2:gprregbank(s32) = G_CONSTANT i32 8 + %3:gprregbank(s32) = G_CONSTANT i32 1 + %4:vregbank(<32 x s8>) = G_INTRINSIC_W_SIDE_EFFECTS intrinsic(@llvm.aie2.I256.v32.acc32.srs), %1(<16 x s64>), %2(s32), %3(s32) + %5:vregbank(<32 x s16>) = G_INTRINSIC intrinsic(@llvm.aie2.unpack.I16.I8), %4(<32 x s8>), %3(s32) + G_STORE %5(<32 x s16>), %0(p0) :: (store (<32 x s16>)) + PseudoRET implicit $lr +... diff --git a/llvm/test/CodeGen/AIE/aie2p/GlobalIsel/inst-select-unpack-non-load.mir b/llvm/test/CodeGen/AIE/aie2p/GlobalIsel/inst-select-unpack-non-load.mir new file mode 100644 index 000000000000..ca0ea2d78c30 --- /dev/null +++ b/llvm/test/CodeGen/AIE/aie2p/GlobalIsel/inst-select-unpack-non-load.mir @@ -0,0 +1,48 @@ +# NOTE: Assertions have been autogenerated by utils/update_mir_test_checks.py +# +# This file is licensed under the Apache License v2.0 with LLVM Exceptions. +# See https://llvm.org/LICENSE.txt for license information. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +# +# (c) Copyright 2026 Advanced Micro Devices, Inc. or its affiliates + +# RUN: llc -mtriple aie2p -run-pass=instruction-select %s -verify-machineinstrs -o - | FileCheck %s + +# The VLDB.UNPACK combine in selectG_AIE_LOAD_UNPACK must only fire when the +# def feeding the unpack is an actual load. Here the unpack consumes the result +# of an SRS narrowing intrinsic (the lowering of acc.to_vector()), which +# reports mayLoad() but carries no memory operand. Previously the combine path +# called getLoadStoreSize() on it and dereferenced a non-existent memoperand, +# crashing instruction-select. It must instead fall back to the normal VUNPACK +# selection. + +--- +name: unpack_of_srs_not_load +alignment: 16 +legalized: true +regBankSelected: true +body: | + bb.1.entry: + liveins: $p0 + ; CHECK-LABEL: name: unpack_of_srs_not_load + ; CHECK: liveins: $p0 + ; CHECK-NEXT: {{ $}} + ; CHECK-NEXT: [[COPY:%[0-9]+]]:ep = COPY $p0 + ; CHECK-NEXT: [[DEF:%[0-9]+]]:acc1024 = IMPLICIT_DEF + ; CHECK-NEXT: [[MOV_RLC_imm11_pseudo:%[0-9]+]]:er = MOV_RLC_imm11_pseudo 8 + ; CHECK-NEXT: $crsrsmode = MOV_scalar_imm11_pseudo 0 + ; CHECK-NEXT: [[COPY1:%[0-9]+]]:es = COPY [[MOV_RLC_imm11_pseudo]] + ; CHECK-NEXT: [[VSRS_4x_mv_w_srs_cm_srsSign1_:%[0-9]+]]:vec256 = VSRS_4x_mv_w_srs_cm_srsSign1 [[DEF]], [[COPY1]], implicit-def dead $srsrs_of, implicit $crrnd, implicit $crsrsmode, implicit $crsat, implicit $srssign1 + ; CHECK-NEXT: $crunpacksize = MOV_scalar_imm11_pseudo 1 + ; CHECK-NEXT: [[VUNPACK_mv_unpack_w_unpackSign1_:%[0-9]+]]:vec512 = VUNPACK_mv_unpack_w_unpackSign1 [[VSRS_4x_mv_w_srs_cm_srsSign1_]], implicit $crunpacksize, implicit $unpacksign1 + ; CHECK-NEXT: VST_dmx_sts_x_idx_imm [[VUNPACK_mv_unpack_w_unpackSign1_]], [[COPY]], 0 :: (store (<32 x s16>)) + ; CHECK-NEXT: PseudoRET implicit $lr + %0:ptrregbank(p0) = COPY $p0 + %1:accregbank(<32 x s32>) = G_IMPLICIT_DEF + %2:gprregbank(s32) = G_CONSTANT i32 8 + %3:gprregbank(s32) = G_CONSTANT i32 1 + %4:vregbank(<32 x s8>) = G_INTRINSIC_W_SIDE_EFFECTS intrinsic(@llvm.aie2p.I256.v32.acc32.srs), %1(<32 x s32>), %2(s32), %3(s32) + %5:vregbank(<32 x s16>) = G_INTRINSIC intrinsic(@llvm.aie2p.unpack.I512.I16.I8), %4(<32 x s8>), %3(s32) + G_STORE %5(<32 x s16>), %0(p0) :: (store (<32 x s16>)) + PseudoRET implicit $lr +...