Skip to content

Commit 61c8cf9

Browse files
jdoerferttstellar
authored andcommitted
[Attributor][FIX] Do not use assumed information for UB detection
The helper `Attributor::checkForAllReturnedValuesAndReturnInsts` simplifies the returned value optimistically. In `AAUndefinedBehavior` we cannot use such optimistic values when deducing UB. As a result, we assumed UB for the return value of a function because we initially (=optimistically) thought the function return is `undef`. While we later adjusted this properly, the `AAUndefinedBehavior` was under the impression the return value is "known" (=fix) and could never change. To correct this we use `Attributor::checkForAllInstructions` and then manually to perform simplification of the return value, only allowing known values to be used. This actually matches the other UB deductions. Fixes #53647 (cherry picked from commit dd101c8)
1 parent 0ad6c09 commit 61c8cf9

File tree

2 files changed

+69
-37
lines changed

2 files changed

+69
-37
lines changed

llvm/lib/Transforms/IPO/AttributorAttributes.cpp

Lines changed: 34 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -2691,40 +2691,38 @@ struct AAUndefinedBehaviorImpl : public AAUndefinedBehavior {
26912691
return true;
26922692
};
26932693

2694-
auto InspectReturnInstForUB =
2695-
[&](Value &V, const SmallSetVector<ReturnInst *, 4> RetInsts) {
2696-
// Check if a return instruction always cause UB or not
2697-
// Note: It is guaranteed that the returned position of the anchor
2698-
// scope has noundef attribute when this is called.
2699-
// We also ensure the return position is not "assumed dead"
2700-
// because the returned value was then potentially simplified to
2701-
// `undef` in AAReturnedValues without removing the `noundef`
2702-
// attribute yet.
2703-
2704-
// When the returned position has noundef attriubte, UB occur in the
2705-
// following cases.
2706-
// (1) Returned value is known to be undef.
2707-
// (2) The value is known to be a null pointer and the returned
2708-
// position has nonnull attribute (because the returned value is
2709-
// poison).
2710-
bool FoundUB = false;
2711-
if (isa<UndefValue>(V)) {
2712-
FoundUB = true;
2713-
} else {
2714-
if (isa<ConstantPointerNull>(V)) {
2715-
auto &NonNullAA = A.getAAFor<AANonNull>(
2716-
*this, IRPosition::returned(*getAnchorScope()),
2717-
DepClassTy::NONE);
2718-
if (NonNullAA.isKnownNonNull())
2719-
FoundUB = true;
2720-
}
2721-
}
2694+
auto InspectReturnInstForUB = [&](Instruction &I) {
2695+
auto &RI = cast<ReturnInst>(I);
2696+
// Either we stopped and the appropriate action was taken,
2697+
// or we got back a simplified return value to continue.
2698+
Optional<Value *> SimplifiedRetValue =
2699+
stopOnUndefOrAssumed(A, RI.getReturnValue(), &I);
2700+
if (!SimplifiedRetValue.hasValue() || !SimplifiedRetValue.getValue())
2701+
return true;
27222702

2723-
if (FoundUB)
2724-
for (ReturnInst *RI : RetInsts)
2725-
KnownUBInsts.insert(RI);
2726-
return true;
2727-
};
2703+
// Check if a return instruction always cause UB or not
2704+
// Note: It is guaranteed that the returned position of the anchor
2705+
// scope has noundef attribute when this is called.
2706+
// We also ensure the return position is not "assumed dead"
2707+
// because the returned value was then potentially simplified to
2708+
// `undef` in AAReturnedValues without removing the `noundef`
2709+
// attribute yet.
2710+
2711+
// When the returned position has noundef attriubte, UB occurs in the
2712+
// following cases.
2713+
// (1) Returned value is known to be undef.
2714+
// (2) The value is known to be a null pointer and the returned
2715+
// position has nonnull attribute (because the returned value is
2716+
// poison).
2717+
if (isa<ConstantPointerNull>(*SimplifiedRetValue)) {
2718+
auto &NonNullAA = A.getAAFor<AANonNull>(
2719+
*this, IRPosition::returned(*getAnchorScope()), DepClassTy::NONE);
2720+
if (NonNullAA.isKnownNonNull())
2721+
KnownUBInsts.insert(&I);
2722+
}
2723+
2724+
return true;
2725+
};
27282726

27292727
bool UsedAssumedInformation = false;
27302728
A.checkForAllInstructions(InspectMemAccessInstForUB, *this,
@@ -2747,8 +2745,9 @@ struct AAUndefinedBehaviorImpl : public AAUndefinedBehavior {
27472745
auto &RetPosNoUndefAA =
27482746
A.getAAFor<AANoUndef>(*this, ReturnIRP, DepClassTy::NONE);
27492747
if (RetPosNoUndefAA.isKnownNoUndef())
2750-
A.checkForAllReturnedValuesAndReturnInsts(InspectReturnInstForUB,
2751-
*this);
2748+
A.checkForAllInstructions(InspectReturnInstForUB, *this,
2749+
{Instruction::Ret}, UsedAssumedInformation,
2750+
/* CheckBBLivenessOnly */ true);
27522751
}
27532752
}
27542753

llvm/test/Transforms/Attributor/undefined_behavior.ll

Lines changed: 35 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --function-signature --check-attributes --check-globals
2-
; RUN: opt -attributor -enable-new-pm=0 -attributor-manifest-internal -attributor-max-iterations-verify -attributor-annotate-decl-cs -attributor-max-iterations=2 -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_CGSCC_NPM,NOT_CGSCC_OPM,NOT_TUNIT_NPM,IS__TUNIT____,IS________OPM,IS__TUNIT_OPM
3-
; RUN: opt -aa-pipeline=basic-aa -passes=attributor -attributor-manifest-internal -attributor-max-iterations-verify -attributor-annotate-decl-cs -attributor-max-iterations=2 -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_CGSCC_OPM,NOT_CGSCC_NPM,NOT_TUNIT_OPM,IS__TUNIT____,IS________NPM,IS__TUNIT_NPM
2+
; RUN: opt -attributor -enable-new-pm=0 -attributor-manifest-internal -attributor-max-iterations-verify -attributor-annotate-decl-cs -attributor-max-iterations=6 -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_CGSCC_NPM,NOT_CGSCC_OPM,NOT_TUNIT_NPM,IS__TUNIT____,IS________OPM,IS__TUNIT_OPM
3+
; RUN: opt -aa-pipeline=basic-aa -passes=attributor -attributor-manifest-internal -attributor-max-iterations-verify -attributor-annotate-decl-cs -attributor-max-iterations=6 -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_CGSCC_OPM,NOT_CGSCC_NPM,NOT_TUNIT_OPM,IS__TUNIT____,IS________NPM,IS__TUNIT_NPM
44
; RUN: opt -attributor-cgscc -enable-new-pm=0 -attributor-manifest-internal -attributor-annotate-decl-cs -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_TUNIT_NPM,NOT_TUNIT_OPM,NOT_CGSCC_NPM,IS__CGSCC____,IS________OPM,IS__CGSCC_OPM
55
; RUN: opt -aa-pipeline=basic-aa -passes=attributor-cgscc -attributor-manifest-internal -attributor-annotate-decl-cs -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_TUNIT_NPM,NOT_TUNIT_OPM,NOT_CGSCC_OPM,IS__CGSCC____,IS________NPM,IS__CGSCC_NPM
66

@@ -793,6 +793,39 @@ define i32* @violate_noundef_pointer() {
793793
%ret = call i32* @argument_noundef2(i32* undef)
794794
ret i32* %ret
795795
}
796+
797+
define internal noundef i32 @assumed_undef_is_ok(i1 %c, i32 %arg) {
798+
; IS__CGSCC____: Function Attrs: nofree norecurse nosync nounwind readnone willreturn
799+
; IS__CGSCC____-LABEL: define {{[^@]+}}@assumed_undef_is_ok
800+
; IS__CGSCC____-SAME: (i1 [[C:%.*]]) #[[ATTR0]] {
801+
; IS__CGSCC____-NEXT: br i1 [[C]], label [[REC:%.*]], label [[RET:%.*]]
802+
; IS__CGSCC____: rec:
803+
; IS__CGSCC____-NEXT: br label [[RET]]
804+
; IS__CGSCC____: ret:
805+
; IS__CGSCC____-NEXT: ret i32 undef
806+
;
807+
%stack = alloca i32
808+
store i32 %arg, i32* %stack
809+
br i1 %c, label %rec, label %ret
810+
rec:
811+
%call = call i32 @assumed_undef_is_ok(i1 false, i32 0)
812+
store i32 %call, i32* %stack
813+
br label %ret
814+
ret:
815+
%l = load i32, i32* %stack
816+
ret i32 %l
817+
}
818+
819+
define noundef i32 @assumed_undef_is_ok_caller(i1 %c) {
820+
; CHECK: Function Attrs: nofree norecurse nosync nounwind readnone willreturn
821+
; CHECK-LABEL: define {{[^@]+}}@assumed_undef_is_ok_caller
822+
; CHECK-SAME: (i1 [[C:%.*]]) #[[ATTR0]] {
823+
; CHECK-NEXT: ret i32 0
824+
;
825+
%call = call i32 @assumed_undef_is_ok(i1 %c, i32 undef)
826+
ret i32 %call
827+
}
828+
796829
;.
797830
; IS__TUNIT____: attributes #[[ATTR0]] = { nofree norecurse nosync nounwind readnone willreturn }
798831
; IS__TUNIT____: attributes #[[ATTR1]] = { nofree norecurse nosync nounwind null_pointer_is_valid readnone willreturn }

0 commit comments

Comments
 (0)