From e27928282c0f0c8da451ccf5fd8492c2656cc1f1 Mon Sep 17 00:00:00 2001 From: XChy Date: Wed, 3 Sep 2025 14:45:41 +0800 Subject: [PATCH 1/6] [InstCombine][VectorCombine] Unify uses of lossless inverse cast --- llvm/include/llvm/Analysis/ConstantFolding.h | 12 +++++ llvm/lib/Analysis/ConstantFolding.cpp | 40 ++++++++++++++++ .../InstCombine/InstCombineAndOrXor.cpp | 7 ++- .../InstCombine/InstCombineCalls.cpp | 6 ++- .../InstCombine/InstCombineMulDivRem.cpp | 7 ++- .../Transforms/InstCombine/InstCombinePHI.cpp | 3 +- .../InstCombine/InstCombineSelect.cpp | 2 +- .../InstCombine/InstructionCombining.cpp | 2 +- .../Transforms/Vectorize/VectorCombine.cpp | 47 +------------------ 9 files changed, 71 insertions(+), 55 deletions(-) diff --git a/llvm/include/llvm/Analysis/ConstantFolding.h b/llvm/include/llvm/Analysis/ConstantFolding.h index dcbac8a301025..e5938e42fe723 100644 --- a/llvm/include/llvm/Analysis/ConstantFolding.h +++ b/llvm/include/llvm/Analysis/ConstantFolding.h @@ -226,6 +226,18 @@ LLVM_ABI bool isMathLibCallNoop(const CallBase *Call, LLVM_ABI Constant *ReadByteArrayFromGlobal(const GlobalVariable *GV, uint64_t Offset); + +struct PreservedCastFlags { + bool NNeg = false; + bool NUW = false; + bool NSW = false; +}; + +/// Try to cast C to InvC losslessly, satisfying CastOp(InvC) == C. +/// Will try best to preserve the flags. +LLVM_ABI Constant *getLosslessInvCast(Constant *C, Type *InvCastTo, + unsigned CastOp, const DataLayout &DL, + PreservedCastFlags *Flags = nullptr); } #endif diff --git a/llvm/lib/Analysis/ConstantFolding.cpp b/llvm/lib/Analysis/ConstantFolding.cpp index 2148431c1acce..4f618e31d943f 100644 --- a/llvm/lib/Analysis/ConstantFolding.cpp +++ b/llvm/lib/Analysis/ConstantFolding.cpp @@ -4608,4 +4608,44 @@ bool llvm::isMathLibCallNoop(const CallBase *Call, return false; } +LLVM_ABI Constant *llvm::getLosslessInvCast(Constant *C, Type *InvCastTo, + unsigned CastOp, + const DataLayout &DL, + PreservedCastFlags *Flags) { + switch (CastOp) { + case Instruction::BitCast: + // Bitcast is always lossless. + return ConstantFoldCastOperand(Instruction::BitCast, C, InvCastTo, DL); + case Instruction::Trunc: { + auto *ZExtC = ConstantFoldCastOperand(Instruction::ZExt, C, InvCastTo, DL); + if (Flags) { + // Truncation back on ZExt value is always NUW. + Flags->NUW = true; + // Test positivity of C. + auto *SExtC = + ConstantFoldCastOperand(Instruction::SExt, C, InvCastTo, DL); + Flags->NSW = ZExtC == SExtC; + } + return ZExtC; + } + case Instruction::SExt: + case Instruction::ZExt: { + auto *InvC = ConstantExpr::getTrunc(C, InvCastTo); + auto *CastInvC = ConstantFoldCastOperand(CastOp, InvC, C->getType(), DL); + // Must satisfy CastOp(InvC) == C. + if (!CastInvC || CastInvC != C) + return nullptr; + if (Flags && CastOp == Instruction::ZExt) { + auto *SExtInvC = + ConstantFoldCastOperand(Instruction::SExt, InvC, C->getType(), DL); + // Test positivity of InvC. + Flags->NNeg = CastInvC == SExtInvC; + } + return InvC; + } + default: + return nullptr; + } +} + void TargetFolder::anchor() {} diff --git a/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp b/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp index a13d3ceb61320..e60e1787688d8 100644 --- a/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp +++ b/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp @@ -1799,8 +1799,10 @@ static Instruction *foldLogicCastConstant(BinaryOperator &Logic, CastInst *Cast, // type may provide more information to later folds, and the smaller logic // instruction may be cheaper (particularly in the case of vectors). Value *X; + auto& DL = IC.getDataLayout(); if (match(Cast, m_OneUse(m_ZExt(m_Value(X))))) { - if (Constant *TruncC = IC.getLosslessUnsignedTrunc(C, SrcTy)) { + if (Constant *TruncC = + getLosslessInvCast(C, SrcTy, Instruction::ZExt, DL)) { // LogicOpc (zext X), C --> zext (LogicOpc X, C) Value *NewOp = IC.Builder.CreateBinOp(LogicOpc, X, TruncC); return new ZExtInst(NewOp, DestTy); @@ -1808,7 +1810,8 @@ static Instruction *foldLogicCastConstant(BinaryOperator &Logic, CastInst *Cast, } if (match(Cast, m_OneUse(m_SExtLike(m_Value(X))))) { - if (Constant *TruncC = IC.getLosslessSignedTrunc(C, SrcTy)) { + if (Constant *TruncC = + getLosslessInvCast(C, SrcTy, Instruction::SExt, DL)) { // LogicOpc (sext X), C --> sext (LogicOpc X, C) Value *NewOp = IC.Builder.CreateBinOp(LogicOpc, X, TruncC); return new SExtInst(NewOp, DestTy); diff --git a/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp b/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp index 42b65dde67255..e03d76629f33a 100644 --- a/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp +++ b/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp @@ -1956,7 +1956,8 @@ Instruction *InstCombinerImpl::visitCallInst(CallInst &CI) { Constant *C; if (match(I0, m_ZExt(m_Value(X))) && match(I1, m_Constant(C)) && I0->hasOneUse()) { - if (Constant *NarrowC = getLosslessUnsignedTrunc(C, X->getType())) { + if (Constant *NarrowC = + getLosslessInvCast(C, X->getType(), Instruction::ZExt, DL)) { Value *NarrowMaxMin = Builder.CreateBinaryIntrinsic(IID, X, NarrowC); return CastInst::Create(Instruction::ZExt, NarrowMaxMin, II->getType()); } @@ -2006,7 +2007,8 @@ Instruction *InstCombinerImpl::visitCallInst(CallInst &CI) { Constant *C; if (match(I0, m_SExt(m_Value(X))) && match(I1, m_Constant(C)) && I0->hasOneUse()) { - if (Constant *NarrowC = getLosslessSignedTrunc(C, X->getType())) { + if (Constant *NarrowC = + getLosslessInvCast(C, X->getType(), Instruction::SExt, DL)) { Value *NarrowMaxMin = Builder.CreateBinaryIntrinsic(IID, X, NarrowC); return CastInst::Create(Instruction::SExt, NarrowMaxMin, II->getType()); } diff --git a/llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp b/llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp index d7310b1c741c0..252021be72799 100644 --- a/llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp +++ b/llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp @@ -1642,10 +1642,12 @@ static Instruction *narrowUDivURem(BinaryOperator &I, } Constant *C; + auto &DL = IC.getDataLayout(); if (isa(N) && match(N, m_OneUse(m_ZExt(m_Value(X)))) && match(D, m_Constant(C))) { // If the constant is the same in the smaller type, use the narrow version. - Constant *TruncC = IC.getLosslessUnsignedTrunc(C, X->getType()); + Constant *TruncC = + getLosslessInvCast(C, X->getType(), Instruction::ZExt, DL); if (!TruncC) return nullptr; @@ -1656,7 +1658,8 @@ static Instruction *narrowUDivURem(BinaryOperator &I, if (isa(D) && match(D, m_OneUse(m_ZExt(m_Value(X)))) && match(N, m_Constant(C))) { // If the constant is the same in the smaller type, use the narrow version. - Constant *TruncC = IC.getLosslessUnsignedTrunc(C, X->getType()); + Constant *TruncC = + getLosslessInvCast(C, X->getType(), Instruction::ZExt, DL); if (!TruncC) return nullptr; diff --git a/llvm/lib/Transforms/InstCombine/InstCombinePHI.cpp b/llvm/lib/Transforms/InstCombine/InstCombinePHI.cpp index 6477141ab095f..86751bda27e66 100644 --- a/llvm/lib/Transforms/InstCombine/InstCombinePHI.cpp +++ b/llvm/lib/Transforms/InstCombine/InstCombinePHI.cpp @@ -841,7 +841,8 @@ Instruction *InstCombinerImpl::foldPHIArgZextsIntoPHI(PHINode &Phi) { NumZexts++; } else if (auto *C = dyn_cast(V)) { // Make sure that constants can fit in the new type. - Constant *Trunc = getLosslessUnsignedTrunc(C, NarrowType); + Constant *Trunc = + getLosslessInvCast(C, NarrowType, Instruction::ZExt, DL); if (!Trunc) return nullptr; NewIncoming.push_back(Trunc); diff --git a/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp b/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp index ba8b4c47e8f88..9467463d39c0e 100644 --- a/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp +++ b/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp @@ -2375,7 +2375,7 @@ Instruction *InstCombinerImpl::foldSelectExtConst(SelectInst &Sel) { // If the constant is the same after truncation to the smaller type and // extension to the original type, we can narrow the select. Type *SelType = Sel.getType(); - Constant *TruncC = getLosslessTrunc(C, SmallType, ExtOpcode); + Constant *TruncC = getLosslessInvCast(C, SmallType, ExtOpcode, DL); if (TruncC && ExtInst->hasOneUse()) { Value *TruncCVal = cast(TruncC); if (ExtInst == Sel.getFalseValue()) diff --git a/llvm/lib/Transforms/InstCombine/InstructionCombining.cpp b/llvm/lib/Transforms/InstCombine/InstructionCombining.cpp index 1a9b54bc009bc..4960a50bbede8 100644 --- a/llvm/lib/Transforms/InstCombine/InstructionCombining.cpp +++ b/llvm/lib/Transforms/InstCombine/InstructionCombining.cpp @@ -2568,7 +2568,7 @@ Instruction *InstCombinerImpl::narrowMathIfNoOverflow(BinaryOperator &BO) { Constant *WideC; if (!Op0->hasOneUse() || !match(Op1, m_Constant(WideC))) return nullptr; - Constant *NarrowC = getLosslessTrunc(WideC, X->getType(), CastOpc); + Constant *NarrowC = getLosslessInvCast(WideC, X->getType(), CastOpc, DL); if (!NarrowC) return nullptr; Y = NarrowC; diff --git a/llvm/lib/Transforms/Vectorize/VectorCombine.cpp b/llvm/lib/Transforms/Vectorize/VectorCombine.cpp index 6e46547b15b2b..93b3a0eeb0305 100644 --- a/llvm/lib/Transforms/Vectorize/VectorCombine.cpp +++ b/llvm/lib/Transforms/Vectorize/VectorCombine.cpp @@ -938,51 +938,6 @@ bool VectorCombine::foldBitOpOfCastops(Instruction &I) { return true; } -struct PreservedCastFlags { - bool NNeg = false; - bool NUW = false; - bool NSW = false; -}; - -// Try to cast C to InvC losslessly, satisfying CastOp(InvC) == C. -// Will try best to preserve the flags. -static Constant *getLosslessInvCast(Constant *C, Type *InvCastTo, - Instruction::CastOps CastOp, - const DataLayout &DL, - PreservedCastFlags &Flags) { - switch (CastOp) { - case Instruction::BitCast: - // Bitcast is always lossless. - return ConstantFoldCastOperand(Instruction::BitCast, C, InvCastTo, DL); - case Instruction::Trunc: { - auto *ZExtC = ConstantFoldCastOperand(Instruction::ZExt, C, InvCastTo, DL); - auto *SExtC = ConstantFoldCastOperand(Instruction::SExt, C, InvCastTo, DL); - // Truncation back on ZExt value is always NUW. - Flags.NUW = true; - // Test positivity of C. - Flags.NSW = ZExtC == SExtC; - return ZExtC; - } - case Instruction::SExt: - case Instruction::ZExt: { - auto *InvC = ConstantExpr::getTrunc(C, InvCastTo); - auto *CastInvC = ConstantFoldCastOperand(CastOp, InvC, C->getType(), DL); - // Must satisfy CastOp(InvC) == C. - if (!CastInvC || CastInvC != C) - return nullptr; - if (CastOp == Instruction::ZExt) { - auto *SExtInvC = - ConstantFoldCastOperand(Instruction::SExt, InvC, C->getType(), DL); - // Test positivity of InvC. - Flags.NNeg = CastInvC == SExtInvC; - } - return InvC; - } - default: - return nullptr; - } -} - /// Match: // bitop(castop(x), C) -> // bitop(castop(x), castop(InvC)) -> @@ -1025,7 +980,7 @@ bool VectorCombine::foldBitOpOfCastConstant(Instruction &I) { // Find the constant InvC, such that castop(InvC) equals to C. PreservedCastFlags RHSFlags; - Constant *InvC = getLosslessInvCast(C, SrcVecTy, CastOpcode, *DL, RHSFlags); + Constant *InvC = getLosslessInvCast(C, SrcVecTy, CastOpcode, *DL, &RHSFlags); if (!InvC) return false; From 3bc3ce29eef47c8def9ffaa359c7eeaeb1a81f05 Mon Sep 17 00:00:00 2001 From: XChy Date: Wed, 3 Sep 2025 15:03:03 +0800 Subject: [PATCH 2/6] format --- llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp b/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp index e60e1787688d8..76b761bd0969d 100644 --- a/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp +++ b/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp @@ -1799,7 +1799,7 @@ static Instruction *foldLogicCastConstant(BinaryOperator &Logic, CastInst *Cast, // type may provide more information to later folds, and the smaller logic // instruction may be cheaper (particularly in the case of vectors). Value *X; - auto& DL = IC.getDataLayout(); + auto &DL = IC.getDataLayout(); if (match(Cast, m_OneUse(m_ZExt(m_Value(X))))) { if (Constant *TruncC = getLosslessInvCast(C, SrcTy, Instruction::ZExt, DL)) { From 1b9aa50062981e55e611a12d80cb58ba889e9d95 Mon Sep 17 00:00:00 2001 From: XChy Date: Wed, 3 Sep 2025 17:53:08 +0800 Subject: [PATCH 3/6] Remove old helper functions --- .../InstCombine/InstCombineCompares.cpp | 2 +- .../InstCombine/InstCombineInternal.h | 17 ----------------- 2 files changed, 1 insertion(+), 18 deletions(-) diff --git a/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp b/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp index 90feddf6dcfe1..861630680752f 100644 --- a/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp +++ b/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp @@ -6375,7 +6375,7 @@ Instruction *InstCombinerImpl::foldICmpWithZextOrSext(ICmpInst &ICmp) { // If a lossless truncate is possible... Type *SrcTy = CastOp0->getSrcTy(); - Constant *Res = getLosslessTrunc(C, SrcTy, CastOp0->getOpcode()); + Constant *Res = getLosslessInvCast(C, SrcTy, CastOp0->getOpcode(), DL); if (Res) { if (ICmp.isEquality()) return new ICmpInst(ICmp.getPredicate(), X, Res); diff --git a/llvm/lib/Transforms/InstCombine/InstCombineInternal.h b/llvm/lib/Transforms/InstCombine/InstCombineInternal.h index 2340028ce93dc..d3d23130b6fc4 100644 --- a/llvm/lib/Transforms/InstCombine/InstCombineInternal.h +++ b/llvm/lib/Transforms/InstCombine/InstCombineInternal.h @@ -222,23 +222,6 @@ class LLVM_LIBRARY_VISIBILITY InstCombinerImpl final bool fmulByZeroIsZero(Value *MulVal, FastMathFlags FMF, const Instruction *CtxI) const; - Constant *getLosslessTrunc(Constant *C, Type *TruncTy, unsigned ExtOp) { - Constant *TruncC = ConstantExpr::getTrunc(C, TruncTy); - Constant *ExtTruncC = - ConstantFoldCastOperand(ExtOp, TruncC, C->getType(), DL); - if (ExtTruncC && ExtTruncC == C) - return TruncC; - return nullptr; - } - - Constant *getLosslessUnsignedTrunc(Constant *C, Type *TruncTy) { - return getLosslessTrunc(C, TruncTy, Instruction::ZExt); - } - - Constant *getLosslessSignedTrunc(Constant *C, Type *TruncTy) { - return getLosslessTrunc(C, TruncTy, Instruction::SExt); - } - std::optional>> convertOrOfShiftsToFunnelShift(Instruction &Or); From fe59e8b778f38bd323b486cf940d9170d5418bc6 Mon Sep 17 00:00:00 2001 From: XChy Date: Wed, 3 Sep 2025 19:23:19 +0800 Subject: [PATCH 4/6] Add signed/unsigned trunc wrapper --- llvm/include/llvm/Analysis/ConstantFolding.h | 10 +++++++++- llvm/lib/Analysis/ConstantFolding.cpp | 19 +++++++++++++++---- .../InstCombine/InstCombineAndOrXor.cpp | 6 ++---- .../InstCombine/InstCombineCalls.cpp | 6 ++---- .../InstCombine/InstCombineMulDivRem.cpp | 6 ++---- .../Transforms/InstCombine/InstCombinePHI.cpp | 3 +-- 6 files changed, 31 insertions(+), 19 deletions(-) diff --git a/llvm/include/llvm/Analysis/ConstantFolding.h b/llvm/include/llvm/Analysis/ConstantFolding.h index e5938e42fe723..7fef605e05ba8 100644 --- a/llvm/include/llvm/Analysis/ConstantFolding.h +++ b/llvm/include/llvm/Analysis/ConstantFolding.h @@ -238,6 +238,14 @@ struct PreservedCastFlags { LLVM_ABI Constant *getLosslessInvCast(Constant *C, Type *InvCastTo, unsigned CastOp, const DataLayout &DL, PreservedCastFlags *Flags = nullptr); -} + +LLVM_ABI Constant * +getLosslessUnsignedTrunc(Constant *C, Type *DestTy, const DataLayout &DL, + PreservedCastFlags *Flags = nullptr); + +LLVM_ABI Constant *getLosslessSignedTrunc(Constant *C, Type *DestTy, + const DataLayout &DL, + PreservedCastFlags *Flags = nullptr); +} // namespace llvm #endif diff --git a/llvm/lib/Analysis/ConstantFolding.cpp b/llvm/lib/Analysis/ConstantFolding.cpp index 4f618e31d943f..40e176c2ab5ce 100644 --- a/llvm/lib/Analysis/ConstantFolding.cpp +++ b/llvm/lib/Analysis/ConstantFolding.cpp @@ -4608,10 +4608,9 @@ bool llvm::isMathLibCallNoop(const CallBase *Call, return false; } -LLVM_ABI Constant *llvm::getLosslessInvCast(Constant *C, Type *InvCastTo, - unsigned CastOp, - const DataLayout &DL, - PreservedCastFlags *Flags) { +Constant *llvm::getLosslessInvCast(Constant *C, Type *InvCastTo, + unsigned CastOp, const DataLayout &DL, + PreservedCastFlags *Flags) { switch (CastOp) { case Instruction::BitCast: // Bitcast is always lossless. @@ -4648,4 +4647,16 @@ LLVM_ABI Constant *llvm::getLosslessInvCast(Constant *C, Type *InvCastTo, } } +Constant *llvm::getLosslessUnsignedTrunc(Constant *C, Type *DestTy, + const DataLayout &DL, + PreservedCastFlags *Flags) { + return getLosslessInvCast(C, DestTy, Instruction::ZExt, DL, Flags); +} + +Constant *llvm::getLosslessSignedTrunc(Constant *C, Type *DestTy, + const DataLayout &DL, + PreservedCastFlags *Flags) { + return getLosslessInvCast(C, DestTy, Instruction::SExt, DL, Flags); +} + void TargetFolder::anchor() {} diff --git a/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp b/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp index 76b761bd0969d..8b9df62d7c652 100644 --- a/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp +++ b/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp @@ -1801,8 +1801,7 @@ static Instruction *foldLogicCastConstant(BinaryOperator &Logic, CastInst *Cast, Value *X; auto &DL = IC.getDataLayout(); if (match(Cast, m_OneUse(m_ZExt(m_Value(X))))) { - if (Constant *TruncC = - getLosslessInvCast(C, SrcTy, Instruction::ZExt, DL)) { + if (Constant *TruncC = getLosslessUnsignedTrunc(C, SrcTy, DL)) { // LogicOpc (zext X), C --> zext (LogicOpc X, C) Value *NewOp = IC.Builder.CreateBinOp(LogicOpc, X, TruncC); return new ZExtInst(NewOp, DestTy); @@ -1810,8 +1809,7 @@ static Instruction *foldLogicCastConstant(BinaryOperator &Logic, CastInst *Cast, } if (match(Cast, m_OneUse(m_SExtLike(m_Value(X))))) { - if (Constant *TruncC = - getLosslessInvCast(C, SrcTy, Instruction::SExt, DL)) { + if (Constant *TruncC = getLosslessSignedTrunc(C, SrcTy, DL)) { // LogicOpc (sext X), C --> sext (LogicOpc X, C) Value *NewOp = IC.Builder.CreateBinOp(LogicOpc, X, TruncC); return new SExtInst(NewOp, DestTy); diff --git a/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp b/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp index e03d76629f33a..33b66aeaffe60 100644 --- a/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp +++ b/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp @@ -1956,8 +1956,7 @@ Instruction *InstCombinerImpl::visitCallInst(CallInst &CI) { Constant *C; if (match(I0, m_ZExt(m_Value(X))) && match(I1, m_Constant(C)) && I0->hasOneUse()) { - if (Constant *NarrowC = - getLosslessInvCast(C, X->getType(), Instruction::ZExt, DL)) { + if (Constant *NarrowC = getLosslessUnsignedTrunc(C, X->getType(), DL)) { Value *NarrowMaxMin = Builder.CreateBinaryIntrinsic(IID, X, NarrowC); return CastInst::Create(Instruction::ZExt, NarrowMaxMin, II->getType()); } @@ -2007,8 +2006,7 @@ Instruction *InstCombinerImpl::visitCallInst(CallInst &CI) { Constant *C; if (match(I0, m_SExt(m_Value(X))) && match(I1, m_Constant(C)) && I0->hasOneUse()) { - if (Constant *NarrowC = - getLosslessInvCast(C, X->getType(), Instruction::SExt, DL)) { + if (Constant *NarrowC = getLosslessSignedTrunc(C, X->getType(), DL)) { Value *NarrowMaxMin = Builder.CreateBinaryIntrinsic(IID, X, NarrowC); return CastInst::Create(Instruction::SExt, NarrowMaxMin, II->getType()); } diff --git a/llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp b/llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp index 252021be72799..a9aacc707cc20 100644 --- a/llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp +++ b/llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp @@ -1646,8 +1646,7 @@ static Instruction *narrowUDivURem(BinaryOperator &I, if (isa(N) && match(N, m_OneUse(m_ZExt(m_Value(X)))) && match(D, m_Constant(C))) { // If the constant is the same in the smaller type, use the narrow version. - Constant *TruncC = - getLosslessInvCast(C, X->getType(), Instruction::ZExt, DL); + Constant *TruncC = getLosslessUnsignedTrunc(C, X->getType(), DL); if (!TruncC) return nullptr; @@ -1658,8 +1657,7 @@ static Instruction *narrowUDivURem(BinaryOperator &I, if (isa(D) && match(D, m_OneUse(m_ZExt(m_Value(X)))) && match(N, m_Constant(C))) { // If the constant is the same in the smaller type, use the narrow version. - Constant *TruncC = - getLosslessInvCast(C, X->getType(), Instruction::ZExt, DL); + Constant *TruncC = getLosslessUnsignedTrunc(C, X->getType(), DL); if (!TruncC) return nullptr; diff --git a/llvm/lib/Transforms/InstCombine/InstCombinePHI.cpp b/llvm/lib/Transforms/InstCombine/InstCombinePHI.cpp index 86751bda27e66..ed9a0be6981fa 100644 --- a/llvm/lib/Transforms/InstCombine/InstCombinePHI.cpp +++ b/llvm/lib/Transforms/InstCombine/InstCombinePHI.cpp @@ -841,8 +841,7 @@ Instruction *InstCombinerImpl::foldPHIArgZextsIntoPHI(PHINode &Phi) { NumZexts++; } else if (auto *C = dyn_cast(V)) { // Make sure that constants can fit in the new type. - Constant *Trunc = - getLosslessInvCast(C, NarrowType, Instruction::ZExt, DL); + Constant *Trunc = getLosslessUnsignedTrunc(C, NarrowType, DL); if (!Trunc) return nullptr; NewIncoming.push_back(Trunc); From 14a4e420f85989a1bb50642e2192bd620904fc75 Mon Sep 17 00:00:00 2001 From: XChy Date: Sat, 6 Sep 2025 01:17:19 +0800 Subject: [PATCH 5/6] refine comment --- llvm/include/llvm/Analysis/ConstantFolding.h | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/llvm/include/llvm/Analysis/ConstantFolding.h b/llvm/include/llvm/Analysis/ConstantFolding.h index 7fef605e05ba8..5f91f9747bb97 100644 --- a/llvm/include/llvm/Analysis/ConstantFolding.h +++ b/llvm/include/llvm/Analysis/ConstantFolding.h @@ -233,8 +233,9 @@ struct PreservedCastFlags { bool NSW = false; }; -/// Try to cast C to InvC losslessly, satisfying CastOp(InvC) == C. -/// Will try best to preserve the flags. +/// Try to cast C to InvC losslessly, satisfying CastOp(InvC) equals C, or +/// CastOp(InvC) is a refined value of undefined C. Will try best to +/// preserve the flags. LLVM_ABI Constant *getLosslessInvCast(Constant *C, Type *InvCastTo, unsigned CastOp, const DataLayout &DL, PreservedCastFlags *Flags = nullptr); From 3b60666938bba17e7b86cda2e762fe9c15e4d542 Mon Sep 17 00:00:00 2001 From: XChy Date: Mon, 8 Sep 2025 20:52:35 +0800 Subject: [PATCH 6/6] resolve conflict --- llvm/lib/Transforms/Vectorize/VectorCombine.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/llvm/lib/Transforms/Vectorize/VectorCombine.cpp b/llvm/lib/Transforms/Vectorize/VectorCombine.cpp index 91cd8e40521fa..17cb18a22336a 100644 --- a/llvm/lib/Transforms/Vectorize/VectorCombine.cpp +++ b/llvm/lib/Transforms/Vectorize/VectorCombine.cpp @@ -984,7 +984,7 @@ bool VectorCombine::foldBitOpOfCastConstant(Instruction &I) { // Find the constant InvC, such that castop(InvC) equals to C. PreservedCastFlags RHSFlags; - Constant *InvC = getLosslessInvCast(C, SrcVecTy, CastOpcode, *DL, &RHSFlags); + Constant *InvC = getLosslessInvCast(C, SrcTy, CastOpcode, *DL, &RHSFlags); if (!InvC) return false;