Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ValueTracking: introduce llvm::isNotCrossLaneOperation #112011

Merged
merged 4 commits into from
Oct 14, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions llvm/include/llvm/Analysis/ValueTracking.h
Original file line number Diff line number Diff line change
Expand Up @@ -791,6 +791,9 @@ bool onlyUsedByLifetimeMarkers(const Value *V);
/// droppable instructions.
bool onlyUsedByLifetimeMarkersOrDroppableInsts(const Value *V);

/// Return true if the instruction doesn't potentially cross vector lanes.
bool isNotCrossLaneOperation(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
11 changes: 4 additions & 7 deletions llvm/lib/Analysis/InstructionSimplify.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4343,13 +4343,10 @@ static Value *simplifyWithOpReplaced(Value *V, Value *Op, Value *RepOp,
if (isa<PHINode>(I))
return nullptr;

if (Op->getType()->isVectorTy()) {
// 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;
}
// For vector types, the simplification must hold per-lane, so forbid
// potentially cross-lane operations like shufflevector.
if (Op->getType()->isVectorTy() && !isNotCrossLaneOperation(I))
return nullptr;

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

bool llvm::isNotCrossLaneOperation(const Instruction *I) {
if (auto *II = dyn_cast<IntrinsicInst>(I)) {
artagnon marked this conversation as resolved.
Show resolved Hide resolved
artagnon marked this conversation as resolved.
Show resolved Hide resolved
switch (II->getIntrinsicID()) {
// TODO: expand this list.
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:
artagnon marked this conversation as resolved.
Show resolved Hide resolved
return true;
default:
return false;
}
}
return !isa<CallBase, BitCastInst, ShuffleVectorInst, ExtractElementInst>(I);
}

bool llvm::isSafeToSpeculativelyExecute(const Instruction *Inst,
const Instruction *CtxI,
AssumptionCache *AC,
Expand Down
18 changes: 2 additions & 16 deletions llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3629,26 +3629,12 @@ 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 (isSafeToSpeculativelyExecuteWithVariableReplaced(&CI) &&
isNotCrossLaneOperation(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
Loading