https://github.com/lukel97 updated https://github.com/llvm/llvm-project/pull/227321
>From 822f165d50e900282a47556f771bba1f56c8c583 Mon Sep 17 00:00:00 2001 From: Luke Lau <[email protected]> Date: Tue, 29 Sep 2026 12:22:06 +0100 Subject: [PATCH 1/2] Precommit tests --- .../AArch64/lshr-trunc-sext-to-ashr-sext.ll | 34 +++++++++++++++++++ .../RISCV/lshr-trunc-sext-to-ashr-sext.ll | 34 +++++++++++++++++++ .../X86/lshr-trunc-sext-to-ashr-sext.ll | 34 +++++++++++++++++++ 3 files changed, 102 insertions(+) create mode 100644 llvm/test/Transforms/InstCombine/AArch64/lshr-trunc-sext-to-ashr-sext.ll create mode 100644 llvm/test/Transforms/InstCombine/RISCV/lshr-trunc-sext-to-ashr-sext.ll create mode 100644 llvm/test/Transforms/InstCombine/X86/lshr-trunc-sext-to-ashr-sext.ll diff --git a/llvm/test/Transforms/InstCombine/AArch64/lshr-trunc-sext-to-ashr-sext.ll b/llvm/test/Transforms/InstCombine/AArch64/lshr-trunc-sext-to-ashr-sext.ll new file mode 100644 index 00000000000000..b721dfa14db627 --- /dev/null +++ b/llvm/test/Transforms/InstCombine/AArch64/lshr-trunc-sext-to-ashr-sext.ll @@ -0,0 +1,34 @@ +; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 6 +; RUN: opt < %s -p instcombine -mtriple aarch64 -S | FileCheck %s + +define i64 @t0(i32 %x) { +; CHECK-LABEL: define i64 @t0( +; CHECK-SAME: i32 [[X:%.*]]) { +; CHECK-NEXT: [[A:%.*]] = lshr i32 [[X]], 16 +; CHECK-NEXT: [[B:%.*]] = zext nneg i32 [[A]] to i64 +; CHECK-NEXT: [[SEXT:%.*]] = shl nuw i64 [[B]], 48 +; CHECK-NEXT: [[C:%.*]] = ashr exact i64 [[SEXT]], 48 +; CHECK-NEXT: ret i64 [[C]] +; + %a = lshr i32 %x, 16 + %b = trunc i32 %a to i16 + %c = sext i16 %b to i64 + ret i64 %c +} + +define i32 @t1(i16 %x) { +; CHECK-LABEL: define i32 @t1( +; CHECK-SAME: i16 [[X:%.*]]) { +; CHECK-NEXT: [[S:%.*]] = sext i16 [[X]] to i32 +; CHECK-NEXT: [[Y:%.*]] = shl nsw i32 [[S]], 10 +; CHECK-NEXT: [[TMP1:%.*]] = add nsw i32 [[Y]], 32768 +; CHECK-NEXT: [[C:%.*]] = ashr i32 [[TMP1]], 16 +; CHECK-NEXT: ret i32 [[C]] +; + %s = sext i16 %x to i32 + %y = add i32 %s, 32 + %a = ashr i32 %y, 6 + %b = trunc i32 %a to i16 + %c = sext i16 %b to i32 + ret i32 %c +} diff --git a/llvm/test/Transforms/InstCombine/RISCV/lshr-trunc-sext-to-ashr-sext.ll b/llvm/test/Transforms/InstCombine/RISCV/lshr-trunc-sext-to-ashr-sext.ll new file mode 100644 index 00000000000000..4a95ddf26b4d70 --- /dev/null +++ b/llvm/test/Transforms/InstCombine/RISCV/lshr-trunc-sext-to-ashr-sext.ll @@ -0,0 +1,34 @@ +; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 6 +; RUN: opt < %s -p instcombine -mtriple riscv64 -S | FileCheck %s + +define i64 @t0(i32 %x) { +; CHECK-LABEL: define i64 @t0( +; CHECK-SAME: i32 [[X:%.*]]) { +; CHECK-NEXT: [[A:%.*]] = lshr i32 [[X]], 16 +; CHECK-NEXT: [[B:%.*]] = zext nneg i32 [[A]] to i64 +; CHECK-NEXT: [[SEXT:%.*]] = shl nuw i64 [[B]], 48 +; CHECK-NEXT: [[C:%.*]] = ashr exact i64 [[SEXT]], 48 +; CHECK-NEXT: ret i64 [[C]] +; + %a = lshr i32 %x, 16 + %b = trunc i32 %a to i16 + %c = sext i16 %b to i64 + ret i64 %c +} + +define i32 @t1(i16 %x) { +; CHECK-LABEL: define i32 @t1( +; CHECK-SAME: i16 [[X:%.*]]) { +; CHECK-NEXT: [[S:%.*]] = sext i16 [[X]] to i32 +; CHECK-NEXT: [[Y:%.*]] = shl nsw i32 [[S]], 10 +; CHECK-NEXT: [[TMP1:%.*]] = add nsw i32 [[Y]], 32768 +; CHECK-NEXT: [[C:%.*]] = ashr i32 [[TMP1]], 16 +; CHECK-NEXT: ret i32 [[C]] +; + %s = sext i16 %x to i32 + %y = add i32 %s, 32 + %a = ashr i32 %y, 6 + %b = trunc i32 %a to i16 + %c = sext i16 %b to i32 + ret i32 %c +} diff --git a/llvm/test/Transforms/InstCombine/X86/lshr-trunc-sext-to-ashr-sext.ll b/llvm/test/Transforms/InstCombine/X86/lshr-trunc-sext-to-ashr-sext.ll new file mode 100644 index 00000000000000..8a93a37ee3e400 --- /dev/null +++ b/llvm/test/Transforms/InstCombine/X86/lshr-trunc-sext-to-ashr-sext.ll @@ -0,0 +1,34 @@ +; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 6 +; RUN: opt < %s -p instcombine -mtriple x86_64 -S | FileCheck %s + +define i64 @t0(i32 %x) { +; CHECK-LABEL: define i64 @t0( +; CHECK-SAME: i32 [[X:%.*]]) { +; CHECK-NEXT: [[A:%.*]] = lshr i32 [[X]], 16 +; CHECK-NEXT: [[B:%.*]] = zext nneg i32 [[A]] to i64 +; CHECK-NEXT: [[SEXT:%.*]] = shl nuw i64 [[B]], 48 +; CHECK-NEXT: [[C:%.*]] = ashr exact i64 [[SEXT]], 48 +; CHECK-NEXT: ret i64 [[C]] +; + %a = lshr i32 %x, 16 + %b = trunc i32 %a to i16 + %c = sext i16 %b to i64 + ret i64 %c +} + +define i32 @t1(i16 %x) { +; CHECK-LABEL: define i32 @t1( +; CHECK-SAME: i16 [[X:%.*]]) { +; CHECK-NEXT: [[S:%.*]] = sext i16 [[X]] to i32 +; CHECK-NEXT: [[Y:%.*]] = shl nsw i32 [[S]], 10 +; CHECK-NEXT: [[TMP1:%.*]] = add nsw i32 [[Y]], 32768 +; CHECK-NEXT: [[C:%.*]] = ashr i32 [[TMP1]], 16 +; CHECK-NEXT: ret i32 [[C]] +; + %s = sext i16 %x to i32 + %y = add i32 %s, 32 + %a = ashr i32 %y, 6 + %b = trunc i32 %a to i16 + %c = sext i16 %b to i32 + ret i32 %c +} >From 31d2f8d80453e9c4f45c3c199957e77e296d2519 Mon Sep 17 00:00:00 2001 From: Luke Lau <[email protected]> Date: Tue, 29 Sep 2026 14:14:48 +0100 Subject: [PATCH 2/2] [InstCombine] Move sext(trunc(...)) combines before EvaluateInDifferentType --- .../InstCombine/InstCombineCasts.cpp | 62 +++++++++---------- .../AArch64/lshr-trunc-sext-to-ashr-sext.ll | 6 +- .../RISCV/lshr-trunc-sext-to-ashr-sext.ll | 6 +- .../X86/lshr-trunc-sext-to-ashr-sext.ll | 6 +- 4 files changed, 37 insertions(+), 43 deletions(-) diff --git a/llvm/lib/Transforms/InstCombine/InstCombineCasts.cpp b/llvm/lib/Transforms/InstCombine/InstCombineCasts.cpp index 0275bf52a13f25..f3741e9b16b94e 100644 --- a/llvm/lib/Transforms/InstCombine/InstCombineCasts.cpp +++ b/llvm/lib/Transforms/InstCombine/InstCombineCasts.cpp @@ -1945,37 +1945,8 @@ Instruction *InstCombinerImpl::visitSExt(SExtInst &Sext) { return CI; } - // Try to extend the entire expression tree to the wide destination type. - bool ShouldExtendExpression = true; - Value *TruncSrc = nullptr; - // It is not desirable to extend expression in the trunc + sext pattern when - // destination type is narrower than original (pre-trunc) type. - if (match(Src, m_Trunc(m_Value(TruncSrc)))) - if (TruncSrc->getType()->getScalarSizeInBits() > DestBitSize) - ShouldExtendExpression = false; - if (ShouldExtendExpression && shouldChangeType(SrcTy, DestTy) && - TypeEvaluationHelper::canEvaluateSExtd(Src, DestTy)) { - // Okay, we can transform this! Insert the new expression now. - LLVM_DEBUG( - dbgs() << "ICE: EvaluateInDifferentType converting expression type" - " to avoid sign extend: " - << Sext << '\n'); - Value *Res = EvaluateInDifferentType(Src, DestTy, true); - assert(Res->getType() == DestTy); - - // If the high bits are already filled with sign bit, just replace this - // cast with the result. - if (ComputeNumSignBits(Res, &Sext) > DestBitSize - SrcBitSize) - return replaceInstUsesWith(Sext, Res); - - // We need to emit a shl + ashr to do the sign extend. - Value *ShAmt = ConstantInt::get(DestTy, DestBitSize - SrcBitSize); - return BinaryOperator::CreateAShr(Builder.CreateShl(Res, ShAmt, "sext"), - ShAmt); - } - - Value *X = TruncSrc; - if (X) { + Value *X; + if (match(Src, m_Trunc(m_Value(X)))) { // If the input has more sign bits than bits truncated, then convert // directly to final type. unsigned XBitSize = X->getType()->getScalarSizeInBits(); @@ -2012,6 +1983,35 @@ Instruction *InstCombinerImpl::visitSExt(SExtInst &Sext) { } } + // Try to extend the entire expression tree to the wide destination type. + bool ShouldExtendExpression = true; + Value *TruncSrc = nullptr; + // It is not desirable to extend expression in the trunc + sext pattern when + // destination type is narrower than original (pre-trunc) type. + if (match(Src, m_Trunc(m_Value(TruncSrc)))) + if (TruncSrc->getType()->getScalarSizeInBits() > DestBitSize) + ShouldExtendExpression = false; + if (ShouldExtendExpression && shouldChangeType(SrcTy, DestTy) && + TypeEvaluationHelper::canEvaluateSExtd(Src, DestTy)) { + // Okay, we can transform this! Insert the new expression now. + LLVM_DEBUG( + dbgs() << "ICE: EvaluateInDifferentType converting expression type" + " to avoid sign extend: " + << Sext << '\n'); + Value *Res = EvaluateInDifferentType(Src, DestTy, true); + assert(Res->getType() == DestTy); + + // If the high bits are already filled with sign bit, just replace this + // cast with the result. + if (ComputeNumSignBits(Res, &Sext) > DestBitSize - SrcBitSize) + return replaceInstUsesWith(Sext, Res); + + // We need to emit a shl + ashr to do the sign extend. + Value *ShAmt = ConstantInt::get(DestTy, DestBitSize - SrcBitSize); + return BinaryOperator::CreateAShr(Builder.CreateShl(Res, ShAmt, "sext"), + ShAmt); + } + if (auto *Cmp = dyn_cast<ICmpInst>(Src)) return transformSExtICmp(Cmp, Sext); diff --git a/llvm/test/Transforms/InstCombine/AArch64/lshr-trunc-sext-to-ashr-sext.ll b/llvm/test/Transforms/InstCombine/AArch64/lshr-trunc-sext-to-ashr-sext.ll index b721dfa14db627..6451486688a123 100644 --- a/llvm/test/Transforms/InstCombine/AArch64/lshr-trunc-sext-to-ashr-sext.ll +++ b/llvm/test/Transforms/InstCombine/AArch64/lshr-trunc-sext-to-ashr-sext.ll @@ -4,10 +4,8 @@ define i64 @t0(i32 %x) { ; CHECK-LABEL: define i64 @t0( ; CHECK-SAME: i32 [[X:%.*]]) { -; CHECK-NEXT: [[A:%.*]] = lshr i32 [[X]], 16 -; CHECK-NEXT: [[B:%.*]] = zext nneg i32 [[A]] to i64 -; CHECK-NEXT: [[SEXT:%.*]] = shl nuw i64 [[B]], 48 -; CHECK-NEXT: [[C:%.*]] = ashr exact i64 [[SEXT]], 48 +; CHECK-NEXT: [[TMP1:%.*]] = ashr i32 [[X]], 16 +; CHECK-NEXT: [[C:%.*]] = sext i32 [[TMP1]] to i64 ; CHECK-NEXT: ret i64 [[C]] ; %a = lshr i32 %x, 16 diff --git a/llvm/test/Transforms/InstCombine/RISCV/lshr-trunc-sext-to-ashr-sext.ll b/llvm/test/Transforms/InstCombine/RISCV/lshr-trunc-sext-to-ashr-sext.ll index 4a95ddf26b4d70..09d35c2cfa2c3b 100644 --- a/llvm/test/Transforms/InstCombine/RISCV/lshr-trunc-sext-to-ashr-sext.ll +++ b/llvm/test/Transforms/InstCombine/RISCV/lshr-trunc-sext-to-ashr-sext.ll @@ -4,10 +4,8 @@ define i64 @t0(i32 %x) { ; CHECK-LABEL: define i64 @t0( ; CHECK-SAME: i32 [[X:%.*]]) { -; CHECK-NEXT: [[A:%.*]] = lshr i32 [[X]], 16 -; CHECK-NEXT: [[B:%.*]] = zext nneg i32 [[A]] to i64 -; CHECK-NEXT: [[SEXT:%.*]] = shl nuw i64 [[B]], 48 -; CHECK-NEXT: [[C:%.*]] = ashr exact i64 [[SEXT]], 48 +; CHECK-NEXT: [[TMP1:%.*]] = ashr i32 [[X]], 16 +; CHECK-NEXT: [[C:%.*]] = sext i32 [[TMP1]] to i64 ; CHECK-NEXT: ret i64 [[C]] ; %a = lshr i32 %x, 16 diff --git a/llvm/test/Transforms/InstCombine/X86/lshr-trunc-sext-to-ashr-sext.ll b/llvm/test/Transforms/InstCombine/X86/lshr-trunc-sext-to-ashr-sext.ll index 8a93a37ee3e400..852b6bc0daefea 100644 --- a/llvm/test/Transforms/InstCombine/X86/lshr-trunc-sext-to-ashr-sext.ll +++ b/llvm/test/Transforms/InstCombine/X86/lshr-trunc-sext-to-ashr-sext.ll @@ -4,10 +4,8 @@ define i64 @t0(i32 %x) { ; CHECK-LABEL: define i64 @t0( ; CHECK-SAME: i32 [[X:%.*]]) { -; CHECK-NEXT: [[A:%.*]] = lshr i32 [[X]], 16 -; CHECK-NEXT: [[B:%.*]] = zext nneg i32 [[A]] to i64 -; CHECK-NEXT: [[SEXT:%.*]] = shl nuw i64 [[B]], 48 -; CHECK-NEXT: [[C:%.*]] = ashr exact i64 [[SEXT]], 48 +; CHECK-NEXT: [[TMP1:%.*]] = ashr i32 [[X]], 16 +; CHECK-NEXT: [[C:%.*]] = sext i32 [[TMP1]] to i64 ; CHECK-NEXT: ret i64 [[C]] ; %a = lshr i32 %x, 16 _______________________________________________ llvm-branch-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits
