Skip to content

Commit a75f985

Browse files
ustachowigcbot
authored andcommitted
Fix endless loop in Legalization::visitBinaryOperator for optimized and/or sequences
Collected users of the instruction into a vector before updating them to prevent an endless loop when an instruction is used both in the condition and value of a select instruction.
1 parent fa4e175 commit a75f985

File tree

2 files changed

+50
-5
lines changed

2 files changed

+50
-5
lines changed

IGC/Compiler/LegalizationPass.cpp

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -280,7 +280,10 @@ void Legalization::visitBinaryOperator(llvm::BinaryOperator &I) {
280280
break;
281281
}
282282
// check select i1 with I not used as condition
283-
if (isa<SelectInst>(*U) && U->getOperand(0) != &I) {
283+
if (isa<SelectInst>(*U) &&
284+
(U->getOperand(0) != &I ||
285+
U->getOperand(1) == &I ||
286+
U->getOperand(2) == &I)) {
284287
flippable = false;
285288
break;
286289
}
@@ -297,20 +300,25 @@ void Legalization::visitBinaryOperator(llvm::BinaryOperator &I) {
297300
if (invert) {
298301
invert->setDebugLoc(I.getDebugLoc());
299302
}
300-
while (!I.user_empty()) {
301-
auto U = I.user_begin();
302-
if (SelectInst *s = dyn_cast<SelectInst>(*U)) {
303+
// Collect users before modifying them
304+
std::vector<User *> users(I.user_begin(), I.user_end());
305+
for (auto U : users) {
306+
if (SelectInst *s = dyn_cast<SelectInst>(U)) {
303307
Value *trueValue = s->getTrueValue();
304308
Value *falseValue = s->getFalseValue();
305309
s->setOperand(1, falseValue);
306310
s->setOperand(2, trueValue);
307311
s->setOperand(0, invert);
308-
} else if (BranchInst *br = dyn_cast<BranchInst>(*U)) {
312+
} else if (BranchInst *br = dyn_cast<BranchInst>(U)) {
309313
IGC_ASSERT(br->isConditional());
310314
br->swapSuccessors();
311315
br->setCondition(invert);
312316
}
313317
}
318+
IGC_ASSERT(
319+
I.user_empty() &&
320+
"Instruction should have no remaining uses after transformation"
321+
);
314322
I.eraseFromParent();
315323
cast<llvm::Instruction>(src0)->eraseFromParent();
316324
cast<llvm::Instruction>(src1)->eraseFromParent();
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
;=========================== begin_copyright_notice ============================
2+
;
3+
; Copyright (C) 2025 Intel Corporation
4+
;
5+
; SPDX-License-Identifier: MIT
6+
;
7+
;============================ end_copyright_notice =============================
8+
;
9+
; RUN: igc_opt -igc-legalization -verify -S %s -o - | FileCheck %s
10+
11+
; ------------------------------------------------
12+
; Legalization: handle optimized and/or sequence
13+
; ------------------------------------------------
14+
15+
define i1 @test_select(i1 %src1, i1 %src2, i1 %cc) {
16+
; CHECK-LABEL: define i1 @test_select(
17+
; CHECK-SAME: i1 [[SRC1:%.*]], i1 [[SRC2:%.*]], i1 [[CC:%.*]]) {
18+
; CHECK: [[XOR1:%.*]] = xor i1 [[SRC1]], true
19+
; CHECK-NEXT: [[XOR2:%.*]] = xor i1 [[SRC2]], true
20+
; CHECK-NEXT: [[AND1:%.*]] = and i1 [[XOR1]], [[XOR2]]
21+
; CHECK-NEXT: [[ZEXT1:%.*]] = zext i1 [[AND1]] to i32
22+
; CHECK-NEXT: [[ZEXT2:%.*]] = zext i1 [[CC]] to i32
23+
; CHECK-NEXT: [[SELECT1:%.*]] = select i1 [[AND1]], i32 [[ZEXT1]], i32 [[ZEXT2]]
24+
; CHECK-NEXT: [[TRUNC1:%.*]] = trunc i32 [[SELECT1]] to i1
25+
; CHECK-NEXT: ret i1 [[TRUNC1]]
26+
;
27+
%1 = xor i1 %src1, true
28+
%2 = xor i1 %src2, true
29+
%3 = and i1 %1, %2
30+
%4 = select i1 %3, i1 %3, i1 %cc
31+
ret i1 %4
32+
}
33+
34+
!igc.functions = !{!0}
35+
36+
!0 = !{i1 (i1, i1, i1)* @test_select, !1}
37+
!1 = !{}

0 commit comments

Comments
 (0)