diff --git a/IGC/AdaptorOCL/preprocess_spvir/PromoteSubByte.cpp b/IGC/AdaptorOCL/preprocess_spvir/PromoteSubByte.cpp index d7325fa1303f..65f24a7adb90 100644 --- a/IGC/AdaptorOCL/preprocess_spvir/PromoteSubByte.cpp +++ b/IGC/AdaptorOCL/preprocess_spvir/PromoteSubByte.cpp @@ -97,7 +97,16 @@ bool PromoteSubByte::run(Module &module) { changed |= getOrCreatePromotedValue(&globalVariable) != &globalVariable; } - visit(module); + // Promoting an instruction can recursively promote instructions further down in its block + // (through PHI nodes) and insert their replacements there. Visit only the instructions that + // existed before promotion: visiting a replacement would promote it again and make cleanUp() + // erase it while it still has users. + SmallVector originalInstructions; + for (auto &F : module) + for (auto &I : llvm::instructions(F)) + originalInstructions.push_back(&I); + for (auto *I : originalInstructions) + visit(*I); while (!promotionQueue.empty()) { auto value = promotionQueue.front(); diff --git a/IGC/Compiler/tests/PromoteSubByte/i1/phinodes-loop-carried.ll b/IGC/Compiler/tests/PromoteSubByte/i1/phinodes-loop-carried.ll new file mode 100644 index 000000000000..f43fab2a29df --- /dev/null +++ b/IGC/Compiler/tests/PromoteSubByte/i1/phinodes-loop-carried.ll @@ -0,0 +1,49 @@ +;=========================== begin_copyright_notice ============================ +; +; Copyright (C) 2026 Intel Corporation +; +; SPDX-License-Identifier: MIT +; +;============================ end_copyright_notice ============================= + +; REQUIRES: llvm-16-plus +; RUN: igc_opt --opaque-pointers -igc-promote-sub-byte -S %s -o %t.ll +; RUN: FileCheck %s --input-file=%t.ll + +; Visiting %u promotes the PHI node %p, which promotes its back-edge value %v further down the +; block. The replacement of %v must not be promoted again when the visitor reaches it, or +; cleanUp() erases it and leaves its user %w with an undefined operand. + +; CHECK-LABEL: define void @loop_carried_i1( +; CHECK: loop: +; CHECK: [[P:%.*]] = phi i8 [ 1, %entry ], [ [[V8:%.*]], %loop ] +; CHECK: [[U:%.*]] = icmp ne i8 [[P]], 1 +; CHECK: [[U8:%.*]] = zext i1 [[U]] to i8 +; CHECK: [[V:%.*]] = icmp ne i8 %x, 0 +; CHECK: [[V8]] = zext i1 [[V]] to i8 +; CHECK: [[W:%.*]] = icmp ne i8 [[V8]], [[U8]] +; CHECK-NOT: undef +; CHECK-NOT: poison +; CHECK: ret void + +define void @loop_carried_i1(ptr %out, ptr %in, i64 %n) { +entry: + br label %loop + +loop: + %i = phi i64 [ 0, %entry ], [ %i.next, %loop ] + %p = phi i1 [ true, %entry ], [ %v, %loop ] + %u = icmp ne i1 %p, true + %ptr = getelementptr i8, ptr %in, i64 %i + %x = load i8, ptr %ptr + %v = icmp ne i8 %x, 0 + %w = icmp ne i1 %v, %u + %i.next = add i64 %i, 1 + %done = icmp eq i64 %i.next, %n + br i1 %done, label %exit, label %loop + +exit: + %r = zext i1 %w to i8 + store i8 %r, ptr %out + ret void +}