Index: llvm/trunk/lib/Analysis/ScalarEvolution.cpp =================================================================== --- llvm/trunk/lib/Analysis/ScalarEvolution.cpp +++ llvm/trunk/lib/Analysis/ScalarEvolution.cpp @@ -1631,6 +1631,16 @@ } } } + + // sext((A + B + ...)) --> (sext(A) + sext(B) + ...) + if (SA->getNoWrapFlags(SCEV::FlagNSW)) { + // If the addition does not sign overflow then we can, by definition, + // commute the sign extension with the addition operation. + SmallVector Ops; + for (const auto *Op : SA->operands()) + Ops.push_back(getSignExtendExpr(Op, Ty)); + return getAddExpr(Ops, SCEV::FlagNSW); + } } // If the input value is a chrec scev, and we can prove that the value // did not overflow the old, smaller, value, we can sign extend all of the Index: llvm/trunk/test/Analysis/ScalarEvolution/no-wrap-add-exprs.ll =================================================================== --- llvm/trunk/test/Analysis/ScalarEvolution/no-wrap-add-exprs.ll +++ llvm/trunk/test/Analysis/ScalarEvolution/no-wrap-add-exprs.ll @@ -42,3 +42,44 @@ ret void } + +define void @f1(i8* %len_addr) { +; CHECK-LABEL: Classifying expressions for: @f1 + entry: + %len = load i8, i8* %len_addr, !range !0 + %len_norange = load i8, i8* %len_addr +; CHECK: %len = load i8, i8* %len_addr, !range !0 +; CHECK-NEXT: --> %len U: [0,127) S: [0,127) +; CHECK: %len_norange = load i8, i8* %len_addr +; CHECK-NEXT: --> %len_norange U: full-set S: full-set + + %t0 = add i8 %len, -1 + %t1 = add i8 %len, -2 +; CHECK: %t0 = add i8 %len, -1 +; CHECK-NEXT: --> (-1 + %len) U: [-1,126) S: [-1,126) +; CHECK: %t1 = add i8 %len, -2 +; CHECK-NEXT: --> (-2 + %len) U: [-2,125) S: [-2,125) + + %t0.sext = sext i8 %t0 to i16 + %t1.sext = sext i8 %t1 to i16 +; CHECK: %t0.sext = sext i8 %t0 to i16 +; CHECK-NEXT: --> (-1 + (zext i8 %len to i16)) U: [-1,126) S: [-1,126) +; CHECK: %t1.sext = sext i8 %t1 to i16 +; CHECK-NEXT: --> (-2 + (zext i8 %len to i16)) U: [-2,125) S: [-2,125) + + %q0 = add i8 %len_norange, 1 + %q1 = add i8 %len_norange, 2 +; CHECK: %q0 = add i8 %len_norange, 1 +; CHECK-NEXT: --> (1 + %len_norange) U: full-set S: full-set +; CHECK: %q1 = add i8 %len_norange, 2 +; CHECK-NEXT: --> (2 + %len_norange) U: full-set S: full-set + + %q0.sext = sext i8 %q0 to i16 + %q1.sext = sext i8 %q1 to i16 +; CHECK: %q0.sext = sext i8 %q0 to i16 +; CHECK-NEXT: --> (sext i8 (1 + %len_norange) to i16) U: [-128,128) S: [-128,128) +; CHECK: %q1.sext = sext i8 %q1 to i16 +; CHECK-NEXT: --> (sext i8 (2 + %len_norange) to i16) U: [-128,128) S: [-128,128) + + ret void +}