Skip to content

Commit

Permalink
[Attributor] Handle constant icmp expressions in AAPotentialValues
Browse files Browse the repository at this point in the history
A `ConstantExpr` ICmp is pretty much the same thing as an ICmpInst when
we want to simplify it. We just need to be less restrictive wrt. the
type and use the static helper functions directly.

Fixes: #59767
  • Loading branch information
jdoerfert committed Jan 22, 2023
1 parent 8e7c1b9 commit 82ba958
Show file tree
Hide file tree
Showing 2 changed files with 43 additions and 15 deletions.
38 changes: 23 additions & 15 deletions llvm/lib/Transforms/IPO/AttributorAttributes.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10347,7 +10347,9 @@ struct AAPotentialValuesImpl : AAPotentialValues {
return;
}
Value *Stripped = getAssociatedValue().stripPointerCasts();
if (isa<Constant>(Stripped)) {
auto *CE = dyn_cast<ConstantExpr>(Stripped);
if (isa<Constant>(Stripped) &&
(!CE || CE->getOpcode() != Instruction::ICmp)) {
addValue(A, getState(), *Stripped, getCtxI(), AA::AnyScope,
getAnchorScope());
indicateOptimisticFixpoint();
Expand Down Expand Up @@ -10549,10 +10551,9 @@ struct AAPotentialValuesFloating : AAPotentialValuesImpl {
/// We handle multiple cases, one in which at least one operand is an
/// (assumed) nullptr. If so, try to simplify it using AANonNull on the other
/// operand. Return true if successful, in that case Worklist will be updated.
bool handleCmp(Attributor &A, CmpInst &Cmp, ItemInfo II,
bool handleCmp(Attributor &A, Value &Cmp, Value *LHS, Value *RHS,
CmpInst::Predicate Pred, ItemInfo II,
SmallVectorImpl<ItemInfo> &Worklist) {
Value *LHS = Cmp.getOperand(0);
Value *RHS = Cmp.getOperand(1);

// Simplify the operands first.
bool UsedAssumedInformation = false;
Expand All @@ -10574,20 +10575,20 @@ struct AAPotentialValuesFloating : AAPotentialValuesImpl {
return false;
RHS = *SimplifiedRHS;

LLVMContext &Ctx = Cmp.getContext();
LLVMContext &Ctx = LHS->getContext();
// Handle the trivial case first in which we don't even need to think about
// null or non-null.
if (LHS == RHS && (Cmp.isTrueWhenEqual() || Cmp.isFalseWhenEqual())) {
Constant *NewV =
ConstantInt::get(Type::getInt1Ty(Ctx), Cmp.isTrueWhenEqual());
if (LHS == RHS &&
(CmpInst::isTrueWhenEqual(Pred) || CmpInst::isFalseWhenEqual(Pred))) {
Constant *NewV = ConstantInt::get(Type::getInt1Ty(Ctx),
CmpInst::isTrueWhenEqual(Pred));
addValue(A, getState(), *NewV, /* CtxI */ nullptr, II.S,
getAnchorScope());
return true;
}

// From now on we only handle equalities (==, !=).
ICmpInst *ICmp = dyn_cast<ICmpInst>(&Cmp);
if (!ICmp || !ICmp->isEquality())
if (!CmpInst::isEquality(Pred))
return false;

bool LHSIsNull = isa<ConstantPointerNull>(LHS);
Expand All @@ -10604,14 +10605,13 @@ struct AAPotentialValuesFloating : AAPotentialValuesImpl {
// The index is the operand that we assume is not null.
unsigned PtrIdx = LHSIsNull;
auto &PtrNonNullAA = A.getAAFor<AANonNull>(
*this, IRPosition::value(*ICmp->getOperand(PtrIdx)),
DepClassTy::REQUIRED);
*this, IRPosition::value(*(PtrIdx ? RHS : LHS)), DepClassTy::REQUIRED);
if (!PtrNonNullAA.isAssumedNonNull())
return false;

// The new value depends on the predicate, true for != and false for ==.
Constant *NewV = ConstantInt::get(Type::getInt1Ty(Ctx),
ICmp->getPredicate() == CmpInst::ICMP_NE);
Constant *NewV =
ConstantInt::get(Type::getInt1Ty(Ctx), Pred == CmpInst::ICMP_NE);
addValue(A, getState(), *NewV, /* CtxI */ nullptr, II.S, getAnchorScope());
return true;
}
Expand Down Expand Up @@ -10812,7 +10812,8 @@ struct AAPotentialValuesFloating : AAPotentialValuesImpl {
SmallVectorImpl<ItemInfo> &Worklist,
SmallMapVector<const Function *, LivenessInfo, 4> &LivenessAAs) {
if (auto *CI = dyn_cast<CmpInst>(&I))
if (handleCmp(A, *CI, II, Worklist))
if (handleCmp(A, *CI, CI->getOperand(0), CI->getOperand(1),
CI->getPredicate(), II, Worklist))
return true;

switch (I.getOpcode()) {
Expand Down Expand Up @@ -10877,6 +10878,13 @@ struct AAPotentialValuesFloating : AAPotentialValuesImpl {
continue;
}

if (auto *CE = dyn_cast<ConstantExpr>(V)) {
if (CE->getOpcode() == Instruction::ICmp)
if (handleCmp(A, *CE, CE->getOperand(0), CE->getOperand(1),
CmpInst::Predicate(CE->getPredicate()), II, Worklist))
continue;
}

if (auto *I = dyn_cast<Instruction>(V)) {
if (simplifyInstruction(A, *I, II, Worklist, LivenessAAs))
continue;
Expand Down
20 changes: 20 additions & 0 deletions llvm/test/Transforms/Attributor/value-simplify.ll
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,11 @@ declare void @f(i32)
declare token @llvm.call.preallocated.setup(i32)
declare ptr @llvm.call.preallocated.arg(token, i32)

@str = private unnamed_addr addrspace(4) constant [1 x i8] c"\00", align 1
@ConstAS3Ptr = addrspace(3) global i32 0, align 4

;.
; CHECK: @[[STR:[a-zA-Z0-9_$"\\.-]+]] = private unnamed_addr addrspace(4) constant [1 x i8] zeroinitializer, align 1
; CHECK: @[[CONSTAS3PTR:[a-zA-Z0-9_$"\\.-]+]] = addrspace(3) global i32 0, align 4
; CHECK: @[[S:[a-zA-Z0-9_$"\\.-]+]] = external global [[STRUCT_X:%.*]]
; CHECK: @[[G:[a-zA-Z0-9_$"\\.-]+]] = internal constant { [2 x ptr] } { [2 x ptr] [ptr @f1, ptr @f2] }
Expand Down Expand Up @@ -1407,6 +1409,24 @@ entry:
ret void
}

define i1 @constexpr_icmp1() {
; CHECK: Function Attrs: nofree norecurse nosync nounwind willreturn memory(none)
; CHECK-LABEL: define {{[^@]+}}@constexpr_icmp1
; CHECK-SAME: () #[[ATTR1]] {
; CHECK-NEXT: ret i1 true
;
ret i1 icmp ne (ptr addrspacecast (ptr addrspace(4) @str to ptr), ptr null)
}

define i1 @constexpr_icmp2() {
; CHECK: Function Attrs: nofree norecurse nosync nounwind willreturn memory(none)
; CHECK-LABEL: define {{[^@]+}}@constexpr_icmp2
; CHECK-SAME: () #[[ATTR1]] {
; CHECK-NEXT: ret i1 false
;
ret i1 icmp eq (ptr addrspacecast (ptr addrspace(4) @str to ptr), ptr null)
}

;.
; TUNIT: attributes #[[ATTR0:[0-9]+]] = { nocallback nofree nosync nounwind willreturn }
; TUNIT: attributes #[[ATTR1]] = { nofree norecurse nosync nounwind willreturn memory(none) }
Expand Down

0 comments on commit 82ba958

Please sign in to comment.