From ccd7732a1fbe6a6df525892171f62ff276bf7501 Mon Sep 17 00:00:00 2001 From: Dominik Steenken Date: Thu, 28 May 2026 10:44:52 +0200 Subject: [PATCH 1/2] [SystemZ] Fix off-by-one error in backend When combineCCMask is called on a TM node with two constant operands, and all of the bits in the mask are active, the existing APInt bit access goes off the overall length of the integer by one. This commit fixes that by using the index value of the leftmost active bit, rather than the number of active bits. --- llvm/lib/Target/SystemZ/SystemZISelLowering.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/llvm/lib/Target/SystemZ/SystemZISelLowering.cpp b/llvm/lib/Target/SystemZ/SystemZISelLowering.cpp index b597d6adbd01c..e0bf05823f99a 100644 --- a/llvm/lib/Target/SystemZ/SystemZISelLowering.cpp +++ b/llvm/lib/Target/SystemZ/SystemZISelLowering.cpp @@ -8887,7 +8887,7 @@ static bool combineCCMask(SDValue &CCReg, int &CCValid, int &CCMask, auto Result = Op0APVal & Op1APVal; bool AllOnes = Result == Op1APVal; bool AllZeros = Result == 0; - bool IsLeftMostBitSet = Result[Op1APVal.getActiveBits()] != 0; + bool IsLeftMostBitSet = Result[Op1APVal.getActiveBits() - 1] != 0; return AllZeros ? 0 : AllOnes ? 3 : IsLeftMostBitSet ? 2 : 1; }; SDValue Op0 = CCNode->getOperand(0); From edee83a61870dba2762068662fc27659217f17a5 Mon Sep 17 00:00:00 2001 From: Dominik Steenken Date: Fri, 29 May 2026 10:13:12 +0200 Subject: [PATCH 2/2] Add regression test --- .../CodeGen/SystemZ/combine-ccmask-tm-full.ll | 41 +++++++++++++++++++ 1 file changed, 41 insertions(+) create mode 100644 llvm/test/CodeGen/SystemZ/combine-ccmask-tm-full.ll diff --git a/llvm/test/CodeGen/SystemZ/combine-ccmask-tm-full.ll b/llvm/test/CodeGen/SystemZ/combine-ccmask-tm-full.ll new file mode 100644 index 0000000000000..85ab999d00bd7 --- /dev/null +++ b/llvm/test/CodeGen/SystemZ/combine-ccmask-tm-full.ll @@ -0,0 +1,41 @@ +; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 6 +; Test that DAGCombiner doesn't crash when combining CCMask with TM instruction +; where all bits in the mask are active (off-by-one error regression test). +; +; RUN: llc < %s -mtriple=s390x-linux-gnu -mcpu=z10 | FileCheck %s + +define void @test_tm_full_mask(ptr %ptr) { +; CHECK-LABEL: test_tm_full_mask: +; CHECK: # %bb.0: +; CHECK-NEXT: lb %r0, 0(%r2) +; CHECK-NEXT: tmll %r0, 1 +; CHECK-NEXT: lhi %r1, 1 +; CHECK-NEXT: jne .LBB0_2 +; CHECK-NEXT: # %bb.1: +; CHECK-NEXT: lr %r1, %r0 +; CHECK-NEXT: .LBB0_2: +; CHECK-NEXT: tmll %r1, 1 +; CHECK-NEXT: je .LBB0_4 +; CHECK-NEXT: # %bb.3: # %if.then +; CHECK-NEXT: mvi 0(%r2), 1 +; CHECK-NEXT: .LBB0_4: # %loop +; CHECK-NEXT: # =>This Inner Loop Header: Depth=1 +; CHECK-NEXT: j .LBB0_4 + %1 = load i1, ptr %ptr, align 4 + %2 = freeze i1 %1 + %3 = select i1 %2, i32 0, i32 -1973148440 + %4 = trunc i32 %3 to i16 + %5 = or disjoint i16 %4, 1 + %6 = icmp ult i16 %5, 3 + %7 = and i32 %3, -1973157888 + %8 = icmp eq i32 %7, 0 + %9 = select i1 %6, i1 %8, i1 %2 + br i1 %9, label %if.then, label %loop + +if.then: + store i1 true, ptr %ptr, align 4 + br label %loop + +loop: + br label %loop +}