return true;
};
+ auto InspectReturnInstForUB =
+ [&](Value &V, const SmallSetVector<ReturnInst *, 4> RetInsts) {
+ // Check if a return instruction always cause UB or not
+ // Note: It is guaranteed that the returned position of the anchor
+ // scope has noundef attribute when this is called.
+
+ // When the returned position has noundef attriubte, UB occur in the
+ // following cases.
+ // (1) Returned value is known to be undef.
+ // (2) The value is known to be a null pointer and the returned
+ // position has nonnull attribute (because the returned value is
+ // poison).
+ // Note: This callback is not called for a dead returned value because
+ // such values are ignored in
+ // checkForAllReturnedValuesAndReturnedInsts.
+ bool FoundUB = false;
+ if (isa<UndefValue>(V)) {
+ FoundUB = true;
+ } else {
+ auto &NonNullAA = A.getAAFor<AANonNull>(
+ *this, IRPosition::returned(*getAnchorScope()));
+ if (NonNullAA.isKnownNonNull() && isa<ConstantPointerNull>(V))
+ FoundUB = true;
+ }
+
+ if (FoundUB)
+ for (ReturnInst *RI : RetInsts)
+ KnownUBInsts.insert(RI);
+ return true;
+ };
+
A.checkForAllInstructions(InspectMemAccessInstForUB, *this,
{Instruction::Load, Instruction::Store,
Instruction::AtomicCmpXchg,
A.checkForAllInstructions(InspectBrInstForUB, *this, {Instruction::Br},
/* CheckBBLivenessOnly */ true);
A.checkForAllCallLikeInstructions(InspectCallSiteForUB, *this);
+
+ // If the returned position of the anchor scope has noundef attriubte, check
+ // all returned instructions.
+ // TODO: If AANoUndef is implemented, ask it here.
+ if (IRPosition::returned(*getAnchorScope()).hasAttr({Attribute::NoUndef}))
+ A.checkForAllReturnedValuesAndReturnInsts(InspectReturnInstForUB, *this);
+
if (NoUBPrevSize != AssumedNoUBInsts.size() ||
UBPrevSize != KnownUBInsts.size())
return ChangeStatus::CHANGED;
ret i32 %X
}
-; Tests for nonnull attribute violation.
+; Tests for nonnull noundef attribute violation.
+;
+; Tests for argument position
define void @arg_nonnull_1(i32* nonnull %a) {
; IS__TUNIT____: Function Attrs: argmemonly nofree nosync nounwind willreturn writeonly
ret:
ret void
}
+
+; Tests for returned position
+
+define nonnull i32* @returned_nonnnull(i32 %c) {
+; IS__TUNIT____: Function Attrs: nofree nosync nounwind readnone willreturn
+; IS__TUNIT____-LABEL: define {{[^@]+}}@returned_nonnnull
+; IS__TUNIT____-SAME: (i32 [[C:%.*]])
+; IS__TUNIT____-NEXT: switch i32 [[C]], label [[ONDEFAULT:%.*]] [
+; IS__TUNIT____-NEXT: i32 0, label [[ONZERO:%.*]]
+; IS__TUNIT____-NEXT: i32 1, label [[ONONE:%.*]]
+; IS__TUNIT____-NEXT: ]
+; IS__TUNIT____: onzero:
+; IS__TUNIT____-NEXT: [[PTR:%.*]] = alloca i32, align 4
+; IS__TUNIT____-NEXT: ret i32* [[PTR]]
+; IS__TUNIT____: onone:
+; IS__TUNIT____-NEXT: ret i32* null
+; IS__TUNIT____: ondefault:
+; IS__TUNIT____-NEXT: ret i32* undef
+;
+; IS__CGSCC____: Function Attrs: nofree norecurse nosync nounwind readnone willreturn
+; IS__CGSCC____-LABEL: define {{[^@]+}}@returned_nonnnull
+; IS__CGSCC____-SAME: (i32 [[C:%.*]])
+; IS__CGSCC____-NEXT: switch i32 [[C]], label [[ONDEFAULT:%.*]] [
+; IS__CGSCC____-NEXT: i32 0, label [[ONZERO:%.*]]
+; IS__CGSCC____-NEXT: i32 1, label [[ONONE:%.*]]
+; IS__CGSCC____-NEXT: ]
+; IS__CGSCC____: onzero:
+; IS__CGSCC____-NEXT: [[PTR:%.*]] = alloca i32, align 4
+; IS__CGSCC____-NEXT: ret i32* [[PTR]]
+; IS__CGSCC____: onone:
+; IS__CGSCC____-NEXT: ret i32* null
+; IS__CGSCC____: ondefault:
+; IS__CGSCC____-NEXT: ret i32* undef
+;
+ switch i32 %c, label %ondefault [ i32 0, label %onzero
+ i32 1, label %onone ]
+onzero:
+ %ptr = alloca i32
+ ret i32* %ptr
+onone:
+ ret i32* null
+ondefault:
+ ret i32* undef
+}
+
+define noundef i32* @returned_noundef(i32 %c) {
+; IS__TUNIT____: Function Attrs: nofree nosync nounwind readnone willreturn
+; IS__TUNIT____-LABEL: define {{[^@]+}}@returned_noundef
+; IS__TUNIT____-SAME: (i32 [[C:%.*]])
+; IS__TUNIT____-NEXT: switch i32 [[C]], label [[ONDEFAULT:%.*]] [
+; IS__TUNIT____-NEXT: i32 0, label [[ONZERO:%.*]]
+; IS__TUNIT____-NEXT: i32 1, label [[ONONE:%.*]]
+; IS__TUNIT____-NEXT: ]
+; IS__TUNIT____: onzero:
+; IS__TUNIT____-NEXT: [[PTR:%.*]] = alloca i32, align 4
+; IS__TUNIT____-NEXT: ret i32* [[PTR]]
+; IS__TUNIT____: onone:
+; IS__TUNIT____-NEXT: ret i32* null
+; IS__TUNIT____: ondefault:
+; IS__TUNIT____-NEXT: unreachable
+;
+; IS__CGSCC____: Function Attrs: nofree norecurse nosync nounwind readnone willreturn
+; IS__CGSCC____-LABEL: define {{[^@]+}}@returned_noundef
+; IS__CGSCC____-SAME: (i32 [[C:%.*]])
+; IS__CGSCC____-NEXT: switch i32 [[C]], label [[ONDEFAULT:%.*]] [
+; IS__CGSCC____-NEXT: i32 0, label [[ONZERO:%.*]]
+; IS__CGSCC____-NEXT: i32 1, label [[ONONE:%.*]]
+; IS__CGSCC____-NEXT: ]
+; IS__CGSCC____: onzero:
+; IS__CGSCC____-NEXT: [[PTR:%.*]] = alloca i32, align 4
+; IS__CGSCC____-NEXT: ret i32* [[PTR]]
+; IS__CGSCC____: onone:
+; IS__CGSCC____-NEXT: ret i32* null
+; IS__CGSCC____: ondefault:
+; IS__CGSCC____-NEXT: unreachable
+;
+ switch i32 %c, label %ondefault [ i32 0, label %onzero
+ i32 1, label %onone ]
+onzero:
+ %ptr = alloca i32
+ ret i32* %ptr
+onone:
+ ret i32* null
+ondefault:
+ ret i32* undef
+}
+
+define nonnull noundef i32* @returned_nonnnull_noundef(i32 %c) {
+; IS__TUNIT____: Function Attrs: nofree nosync nounwind readnone willreturn
+; IS__TUNIT____-LABEL: define {{[^@]+}}@returned_nonnnull_noundef
+; IS__TUNIT____-SAME: (i32 [[C:%.*]])
+; IS__TUNIT____-NEXT: switch i32 [[C]], label [[ONDEFAULT:%.*]] [
+; IS__TUNIT____-NEXT: i32 0, label [[ONZERO:%.*]]
+; IS__TUNIT____-NEXT: i32 1, label [[ONONE:%.*]]
+; IS__TUNIT____-NEXT: ]
+; IS__TUNIT____: onzero:
+; IS__TUNIT____-NEXT: [[PTR:%.*]] = alloca i32, align 4
+; IS__TUNIT____-NEXT: ret i32* [[PTR]]
+; IS__TUNIT____: onone:
+; IS__TUNIT____-NEXT: unreachable
+; IS__TUNIT____: ondefault:
+; IS__TUNIT____-NEXT: unreachable
+;
+; IS__CGSCC____: Function Attrs: nofree norecurse nosync nounwind readnone willreturn
+; IS__CGSCC____-LABEL: define {{[^@]+}}@returned_nonnnull_noundef
+; IS__CGSCC____-SAME: (i32 [[C:%.*]])
+; IS__CGSCC____-NEXT: switch i32 [[C]], label [[ONDEFAULT:%.*]] [
+; IS__CGSCC____-NEXT: i32 0, label [[ONZERO:%.*]]
+; IS__CGSCC____-NEXT: i32 1, label [[ONONE:%.*]]
+; IS__CGSCC____-NEXT: ]
+; IS__CGSCC____: onzero:
+; IS__CGSCC____-NEXT: [[PTR:%.*]] = alloca i32, align 4
+; IS__CGSCC____-NEXT: ret i32* [[PTR]]
+; IS__CGSCC____: onone:
+; IS__CGSCC____-NEXT: unreachable
+; IS__CGSCC____: ondefault:
+; IS__CGSCC____-NEXT: unreachable
+;
+ switch i32 %c, label %ondefault [ i32 0, label %onzero
+ i32 1, label %onone ]
+onzero:
+ %ptr = alloca i32
+ ret i32* %ptr
+onone:
+ ret i32* null
+ondefault:
+ ret i32* undef
+}