Skip to content

Commit

Permalink
ValueTracking: introduce llvm::isLanewiseOperation
Browse files Browse the repository at this point in the history
Factor out and unify common code from InstSimplify and InstCombine that
partially guard against cross-lane vector operations into
llvm::isLanewiseOperation in ValueTracking.

Alive2 proofs for changed tests: https://alive2.llvm.org/ce/z/r9jCpP
  • Loading branch information
artagnon committed Oct 11, 2024
1 parent c04b640 commit b2a7446
Show file tree
Hide file tree
Showing 7 changed files with 37 additions and 39 deletions.
4 changes: 4 additions & 0 deletions llvm/include/llvm/Analysis/ValueTracking.h
Original file line number Diff line number Diff line change
Expand Up @@ -791,6 +791,10 @@ bool onlyUsedByLifetimeMarkers(const Value *V);
/// droppable instructions.
bool onlyUsedByLifetimeMarkersOrDroppableInsts(const Value *V);

/// Return true if the instruction is known to be a vector lane-wise operation
/// i.e. if it doesn't potentially cross vector lanes.
bool isLanewiseOperation(const Instruction *I);

/// Return true if the instruction does not have any effects besides
/// calculating the result and does not have undefined behavior.
///
Expand Down
8 changes: 3 additions & 5 deletions llvm/lib/Analysis/InstructionSimplify.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4343,13 +4343,11 @@ static Value *simplifyWithOpReplaced(Value *V, Value *Op, Value *RepOp,
if (isa<PHINode>(I))
return nullptr;

if (Op->getType()->isVectorTy()) {
if (Op->getType()->isVectorTy() &&
(!I->getType()->isVectorTy() || !isLanewiseOperation(I)))
// For vector types, the simplification must hold per-lane, so forbid
// potentially cross-lane operations like shufflevector.
if (!I->getType()->isVectorTy() || isa<ShuffleVectorInst>(I) ||
isa<CallBase>(I) || isa<BitCastInst>(I))
return nullptr;
}
return nullptr;

// Don't fold away llvm.is.constant checks based on assumptions.
if (match(I, m_Intrinsic<Intrinsic::is_constant>()))
Expand Down
24 changes: 24 additions & 0 deletions llvm/lib/Analysis/ValueTracking.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6947,6 +6947,30 @@ bool llvm::onlyUsedByLifetimeMarkersOrDroppableInsts(const Value *V) {
V, /* AllowLifetime */ true, /* AllowDroppable */ true);
}

bool llvm::isLanewiseOperation(const Instruction *I) {
if (auto *II = dyn_cast<IntrinsicInst>(I)) {
switch (II->getIntrinsicID()) {
case Intrinsic::ctlz:
case Intrinsic::cttz:
case Intrinsic::ctpop:
case Intrinsic::umin:
case Intrinsic::umax:
case Intrinsic::smin:
case Intrinsic::smax:
case Intrinsic::usub_sat:
case Intrinsic::uadd_sat:
case Intrinsic::ssub_sat:
case Intrinsic::sadd_sat:
return true;
default:
return false;
}
}
auto *Shuffle = dyn_cast<ShuffleVectorInst>(I);
return (!Shuffle || Shuffle->isIdentity() || Shuffle->isSelect()) &&
!isa<CallBase>(I) && !isa<BitCastInst>(I);
}

bool llvm::isSafeToSpeculativelyExecute(const Instruction *Inst,
const Instruction *CtxI,
AssumptionCache *AC,
Expand Down
17 changes: 1 addition & 16 deletions llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3629,26 +3629,11 @@ Instruction *InstCombinerImpl::visitCallInst(CallInst &CI) {
// * The intrinsic is speculatable.
// * The select condition is not a vector, or the intrinsic does not
// perform cross-lane operations.
switch (IID) {
case Intrinsic::ctlz:
case Intrinsic::cttz:
case Intrinsic::ctpop:
case Intrinsic::umin:
case Intrinsic::umax:
case Intrinsic::smin:
case Intrinsic::smax:
case Intrinsic::usub_sat:
case Intrinsic::uadd_sat:
case Intrinsic::ssub_sat:
case Intrinsic::sadd_sat:
if (isLanewiseOperation(II))
for (Value *Op : II->args())
if (auto *Sel = dyn_cast<SelectInst>(Op))
if (Instruction *R = FoldOpIntoSelect(*II, Sel))
return R;
[[fallthrough]];
default:
break;
}

if (Instruction *Shuf = foldShuffledIntrinsicOperands(II, Builder))
return Shuf;
Expand Down
12 changes: 2 additions & 10 deletions llvm/test/Transforms/InstCombine/ispow2.ll
Original file line number Diff line number Diff line change
Expand Up @@ -977,11 +977,7 @@ define i1 @is_pow2or0_ctpop_wrong_pred2_logical(i32 %x) {

define <2 x i1> @is_pow2or0_ctpop_commute_vec_wrong_pred3(<2 x i8> %x) {
; CHECK-LABEL: @is_pow2or0_ctpop_commute_vec_wrong_pred3(
; CHECK-NEXT: [[T0:%.*]] = tail call range(i8 0, 9) <2 x i8> @llvm.ctpop.v2i8(<2 x i8> [[X:%.*]])
; CHECK-NEXT: [[CMP:%.*]] = icmp eq <2 x i8> [[T0]], <i8 1, i8 1>
; CHECK-NEXT: [[ISZERO:%.*]] = icmp eq <2 x i8> [[X]], zeroinitializer
; CHECK-NEXT: [[R:%.*]] = and <2 x i1> [[CMP]], [[ISZERO]]
; CHECK-NEXT: ret <2 x i1> [[R]]
; CHECK-NEXT: ret <2 x i1> zeroinitializer
;
%t0 = tail call <2 x i8> @llvm.ctpop.v2i8(<2 x i8> %x)
%cmp = icmp eq <2 x i8> %t0, <i8 1, i8 1>
Expand Down Expand Up @@ -1174,11 +1170,7 @@ define i1 @isnot_pow2nor0_ctpop_wrong_pred2_logical(i32 %x) {

define <2 x i1> @isnot_pow2nor0_wrong_pred3_ctpop_commute_vec(<2 x i8> %x) {
; CHECK-LABEL: @isnot_pow2nor0_wrong_pred3_ctpop_commute_vec(
; CHECK-NEXT: [[T0:%.*]] = tail call range(i8 0, 9) <2 x i8> @llvm.ctpop.v2i8(<2 x i8> [[X:%.*]])
; CHECK-NEXT: [[CMP:%.*]] = icmp ne <2 x i8> [[T0]], <i8 1, i8 1>
; CHECK-NEXT: [[NOTZERO:%.*]] = icmp ne <2 x i8> [[X]], zeroinitializer
; CHECK-NEXT: [[R:%.*]] = or <2 x i1> [[CMP]], [[NOTZERO]]
; CHECK-NEXT: ret <2 x i1> [[R]]
; CHECK-NEXT: ret <2 x i1> <i1 true, i1 true>
;
%t0 = tail call <2 x i8> @llvm.ctpop.v2i8(<2 x i8> %x)
%cmp = icmp ne <2 x i8> %t0, <i8 1, i8 1>
Expand Down
4 changes: 1 addition & 3 deletions llvm/test/Transforms/InstCombine/select-ctlz-to-cttz.ll
Original file line number Diff line number Diff line change
Expand Up @@ -208,10 +208,8 @@ define <2 x i32> @select_clz_to_ctz_vec_with_undef(<2 x i32> %a) {
; CHECK-NEXT: [[SUB:%.*]] = sub <2 x i32> zeroinitializer, [[A:%.*]]
; CHECK-NEXT: [[AND:%.*]] = and <2 x i32> [[A]], [[SUB]]
; CHECK-NEXT: [[LZ:%.*]] = tail call range(i32 0, 33) <2 x i32> @llvm.ctlz.v2i32(<2 x i32> [[AND]], i1 true)
; CHECK-NEXT: [[TOBOOL:%.*]] = icmp eq <2 x i32> [[A]], zeroinitializer
; CHECK-NEXT: [[SUB1:%.*]] = xor <2 x i32> [[LZ]], <i32 31, i32 undef>
; CHECK-NEXT: [[COND:%.*]] = select <2 x i1> [[TOBOOL]], <2 x i32> [[LZ]], <2 x i32> [[SUB1]]
; CHECK-NEXT: ret <2 x i32> [[COND]]
; CHECK-NEXT: ret <2 x i32> [[SUB1]]
;
%sub = sub <2 x i32> zeroinitializer, %a
%and = and <2 x i32> %sub, %a
Expand Down
7 changes: 2 additions & 5 deletions llvm/test/Transforms/InstSimplify/select.ll
Original file line number Diff line number Diff line change
Expand Up @@ -1087,13 +1087,10 @@ define i32 @select_ctpop_zero(i32 %x) {
ret i32 %sel
}

; FIXME: This is safe to fold.
define <2 x i32> @select_ctpop_zero_vec(<2 x i32> %x) {
; CHECK-LABEL: @select_ctpop_zero_vec(
; CHECK-NEXT: [[T0:%.*]] = icmp eq <2 x i32> [[X:%.*]], zeroinitializer
; CHECK-NEXT: [[T1:%.*]] = call <2 x i32> @llvm.ctpop.v2i32(<2 x i32> [[X]])
; CHECK-NEXT: [[SEL:%.*]] = select <2 x i1> [[T0]], <2 x i32> zeroinitializer, <2 x i32> [[T1]]
; CHECK-NEXT: ret <2 x i32> [[SEL]]
; CHECK-NEXT: [[T1:%.*]] = call <2 x i32> @llvm.ctpop.v2i32(<2 x i32> [[X:%.*]])
; CHECK-NEXT: ret <2 x i32> [[T1]]
;
%t0 = icmp eq <2 x i32> %x, zeroinitializer
%t1 = call <2 x i32> @llvm.ctpop.v2i32(<2 x i32> %x)
Expand Down

0 comments on commit b2a7446

Please sign in to comment.