From 33cace05618391c7c427d66169186462aa37d75f Mon Sep 17 00:00:00 2001 From: Roman Lebedev Date: Mon, 21 Sep 2020 17:16:08 +0300 Subject: [PATCH] [SCEV] Recognize @llvm.abs as smax(x, -x) As per alive2 (ignoring undef): ---------------------------------------- define i32 @src(i32 %x, i1 %y) { %0: %r = abs i32 %x, 0 ret i32 %r } => define i32 @tgt(i32 %x, i1 %y) { %0: %neg_x = mul i32 %x, 4294967295 %r = smax i32 %x, %neg_x ret i32 %r } Transformation seems to be correct! ---------------------------------------- define i32 @src(i32 %x, i1 %y) { %0: %r = abs i32 %x, 1 ret i32 %r } => define i32 @tgt(i32 %x, i1 %y) { %0: %neg_x = mul nsw i32 %x, 4294967295 %r = smax i32 %x, %neg_x ret i32 %r } Transformation seems to be correct! --- lib/Analysis/ScalarEvolution.cpp | 8 ++++++++ test/Analysis/ScalarEvolution/abs-intrinsic.ll | 4 ++-- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/lib/Analysis/ScalarEvolution.cpp b/lib/Analysis/ScalarEvolution.cpp index 7f38731bf6a..11e8740d2f5 100644 --- a/lib/Analysis/ScalarEvolution.cpp +++ b/lib/Analysis/ScalarEvolution.cpp @@ -6339,6 +6339,14 @@ const SCEV *ScalarEvolution::createSCEV(Value *V) { if (auto *II = dyn_cast(U)) { switch (II->getIntrinsicID()) { + case Intrinsic::abs: { + const SCEV *Op = getSCEV(II->getArgOperand(0)); + SCEV::NoWrapFlags Flags = + cast(II->getArgOperand(1))->isOne() + ? SCEV::FlagNSW + : SCEV::FlagAnyWrap; + return getSMaxExpr(Op, getNegativeSCEV(Op, Flags)); + } case Intrinsic::umax: return getUMaxExpr(getSCEV(II->getArgOperand(0)), getSCEV(II->getArgOperand(1))); diff --git a/test/Analysis/ScalarEvolution/abs-intrinsic.ll b/test/Analysis/ScalarEvolution/abs-intrinsic.ll index daf8460ea60..ec8666613a7 100644 --- a/test/Analysis/ScalarEvolution/abs-intrinsic.ll +++ b/test/Analysis/ScalarEvolution/abs-intrinsic.ll @@ -8,7 +8,7 @@ define i32 @abs_nonsw(i32 %x) { ; CHECK-LABEL: 'abs_nonsw' ; CHECK-NEXT: Classifying expressions for: @abs_nonsw ; CHECK-NEXT: %r = call i32 @llvm.abs.i32(i32 %x, i1 false) -; CHECK-NEXT: --> %r U: full-set S: full-set +; CHECK-NEXT: --> ((-1 * %x) smax %x) U: full-set S: full-set ; CHECK-NEXT: Determining loop execution counts for: @abs_nonsw ; %r = call i32 @llvm.abs.i32(i32 %x, i1 0) @@ -19,7 +19,7 @@ define i32 @abs_nsw(i32 %x) { ; CHECK-LABEL: 'abs_nsw' ; CHECK-NEXT: Classifying expressions for: @abs_nsw ; CHECK-NEXT: %r = call i32 @llvm.abs.i32(i32 %x, i1 true) -; CHECK-NEXT: --> %r U: [0,-2147483648) S: full-set +; CHECK-NEXT: --> ((-1 * %x) smax %x) U: full-set S: full-set ; CHECK-NEXT: Determining loop execution counts for: @abs_nsw ; %r = call i32 @llvm.abs.i32(i32 %x, i1 1)