[llvm] [SeparateConstOffsetFromGEP] Stop distributing sext/zext over lossy trunc (PR #221381)
Fujun Han via llvm-commits
llvm-commits at lists.llvm.org
Fri Sep 25 20:06:31 PDT 2026
================
@@ -741,9 +741,22 @@ APInt ConstantOffsetExtractor::find(Value *V, GetElementPtrInst *GEP,
else if (BO->getOpcode() == Instruction::Xor)
ConstantOffset = extractDisjointBitsFromXor(BO);
} else if (isa<TruncInst>(V)) {
- ConstantOffset =
- find(U->getOperand(0), GEP, Idx, SignExtended, ZeroExtended)
- .trunc(BitWidth);
+ // With no pending extension, truncation distributes over add, sub and
+ // disjoint or in modular arithmetic, so any constant found in the wider
+ // operand stays valid after truncating it.
+ //
+ // With a pending sext/zext, distributing the extension into the operands
+ // of the truncated expression is unsound: the nuw/nsw flags checked by
+ // canTraceInto hold at the width of the add and say nothing about
+ // wrapping at the truncation width, e.g.
+ // zext i64 (trunc i8 (add nuw i32 (zext i8 251), (zext i8 5)))
+ // is 0 but would be rebuilt as 251 + 5 = 256. Only a fully constant
+ // truncated value remains exact, because then there is no remainder and
+ // the pending casts apply to the constant itself.
----------------
Peter9606 wrote:
Thanks! The constant exception is for when trunc's operand is already a Constant: there's no variable remainder to split, so tracing through is just folding ext(trunc C).
That shows up in @trunk_explicit (NVPTX/split-gep.ll): the index is trunc i64 1 to i32, and canonicalizeArrayIndicesToIndexSize then sign-extends it to the pointer index type, so find() sees sext(trunc C). The check stays that narrow so we keep this fold without reopening the known-bits approach.
https://github.com/llvm/llvm-project/pull/221381
More information about the llvm-commits
mailing list