[Attributor] Introduce a helper do deal with constant type mismatches

If we simplify values we sometimes end up with type mismatches. If the
value is a constant we can often cast it though to still allow
propagation. The logic is now put into a helper and it replaces some
ad hoc things we did before.

This also introduces the AA namespace for abstract attribute related
functions and types.
This commit is contained in:
Johannes Doerfert 2021-05-09 20:02:18 -05:00
parent 55e9c28212
commit 6caea8a7fa
10 changed files with 71 additions and 62 deletions

View File

@ -131,6 +131,15 @@ class AAManager;
class AAResults;
class Function;
/// Abstract Attribute helper functions.
namespace AA {
/// Try to convert \p V to type \p Ty without introducing new instructions. If
/// this is not possible return `nullptr`. Note: this function basically knows
/// how to cast various constants.
Value *getWithType(Value &V, Type &Ty);
} // namespace AA
/// The value passed to the line option that defines the maximal initialization
/// chain length.
extern unsigned MaxInitializationChainLength;

View File

@ -159,6 +159,24 @@ ChangeStatus llvm::operator&(ChangeStatus L, ChangeStatus R) {
}
///}
Value *AA::getWithType(Value &V, Type &Ty) {
if (V.getType() == &Ty)
return &V;
if (isa<UndefValue>(V))
return UndefValue::get(&Ty);
if (auto *C = dyn_cast<Constant>(&V)) {
if (C->isNullValue())
return Constant::getNullValue(&Ty);
if (C->getType()->isPointerTy() && Ty.isPointerTy())
return ConstantExpr::getPointerCast(C, &Ty);
if (C->getType()->isIntegerTy() && Ty.isIntegerTy())
return ConstantExpr::getTrunc(C, &Ty, /* OnlyIfReduced */ true);
if (C->getType()->isFloatingPointTy() && Ty.isFloatingPointTy())
return ConstantExpr::getFPTrunc(C, &Ty, /* OnlyIfReduced */ true);
}
return nullptr;
}
/// Return true if \p New is equal or worse than \p Old.
static bool isEqualOrWorse(const Attribute &New, const Attribute &Old) {
if (!Old.isIntAttribute())

View File

@ -4631,12 +4631,13 @@ struct AAValueSimplifyImpl : AAValueSimplify {
auto *C = SimplifiedAssociatedValue.hasValue()
? dyn_cast<Constant>(SimplifiedAssociatedValue.getValue())
: UndefValue::get(V.getType());
if (C) {
if (C && C != &V) {
Value *NewV = AA::getWithType(*C, *V.getType());
// We can replace the AssociatedValue with the constant.
if (!V.user_empty() && &V != C && V.getType() == C->getType()) {
LLVM_DEBUG(dbgs() << "[ValueSimplify] " << V << " -> " << *C
if (!V.user_empty() && &V != C && NewV) {
LLVM_DEBUG(dbgs() << "[ValueSimplify] " << V << " -> " << *NewV
<< " :: " << *this << "\n");
if (A.changeValueAfterManifest(V, *C))
if (A.changeValueAfterManifest(V, *NewV))
Changed = ChangeStatus::CHANGED;
}
}
@ -4778,23 +4779,23 @@ struct AAValueSimplifyReturned : AAValueSimplifyImpl {
auto *C = SimplifiedAssociatedValue.hasValue()
? dyn_cast<Constant>(SimplifiedAssociatedValue.getValue())
: UndefValue::get(V.getType());
if (C) {
if (C && C != &V) {
auto PredForReturned =
[&](Value &V, const SmallSetVector<ReturnInst *, 4> &RetInsts) {
// We can replace the AssociatedValue with the constant.
if (&V == C || V.getType() != C->getType() || isa<UndefValue>(V))
if (&V == C || isa<UndefValue>(V))
return true;
for (ReturnInst *RI : RetInsts) {
if (RI->getFunction() != getAnchorScope())
continue;
auto *RC = C;
if (RC->getType() != RI->getReturnValue()->getType())
RC = ConstantExpr::getPointerCast(
RC, RI->getReturnValue()->getType());
LLVM_DEBUG(dbgs() << "[ValueSimplify] " << V << " -> " << *RC
Value *NewV =
AA::getWithType(*C, *RI->getReturnValue()->getType());
if (!NewV)
continue;
LLVM_DEBUG(dbgs() << "[ValueSimplify] " << V << " -> " << *NewV
<< " in " << *RI << " :: " << *this << "\n");
if (A.changeUseAfterManifest(RI->getOperandUse(0), *RC))
if (A.changeUseAfterManifest(RI->getOperandUse(0), *NewV))
Changed = ChangeStatus::CHANGED;
}
return true;
@ -4994,9 +4995,10 @@ struct AAValueSimplifyCallSiteArgument : AAValueSimplifyFloating {
Use &U = cast<CallBase>(&getAnchorValue())
->getArgOperandUse(getCallSiteArgNo());
// We can replace the AssociatedValue with the constant.
if (&V != C && V.getType() == C->getType()) {
if (A.changeUseAfterManifest(U, *C))
Changed = ChangeStatus::CHANGED;
if (&V != C) {
if (Value *NewV = AA::getWithType(*C, *V.getType()))
if (A.changeUseAfterManifest(U, *NewV))
Changed = ChangeStatus::CHANGED;
}
}

View File

@ -43,9 +43,8 @@ define void @run() {
; IS__CGSCC____-LABEL: define {{[^@]+}}@run
; IS__CGSCC____-SAME: () #[[ATTR0:[0-9]+]] {
; IS__CGSCC____-NEXT: entry:
; IS__CGSCC____-NEXT: [[A_CAST:%.*]] = bitcast %struct.Foo* @a to i32*
; IS__CGSCC____-NEXT: [[TMP0:%.*]] = load i32, i32* [[A_CAST]], align 8
; IS__CGSCC____-NEXT: [[A_0_1:%.*]] = getelementptr [[STRUCT_FOO:%.*]], %struct.Foo* @a, i32 0, i32 1
; IS__CGSCC____-NEXT: [[TMP0:%.*]] = load i32, i32* getelementptr inbounds ([[STRUCT_FOO:%.*]], %struct.Foo* @a, i32 0, i32 0), align 8
; IS__CGSCC____-NEXT: [[A_0_1:%.*]] = getelementptr [[STRUCT_FOO]], %struct.Foo* @a, i32 0, i32 1
; IS__CGSCC____-NEXT: [[TMP1:%.*]] = load i64, i64* [[A_0_1]], align 8
; IS__CGSCC____-NEXT: unreachable
;

View File

@ -59,11 +59,10 @@ define internal i32 @vfu2(%struct.MYstr* byval(%struct.MYstr) align 4 %u) nounwi
; IS__TUNIT_OPM-NEXT: entry:
; IS__TUNIT_OPM-NEXT: [[TMP0:%.*]] = getelementptr [[STRUCT_MYSTR]], %struct.MYstr* @mystr, i32 0, i32 1
; IS__TUNIT_OPM-NEXT: [[TMP1:%.*]] = load i32, i32* [[TMP0]], align 4
; IS__TUNIT_OPM-NEXT: [[TMP2:%.*]] = getelementptr [[STRUCT_MYSTR]], %struct.MYstr* @mystr, i32 0, i32 0
; IS__TUNIT_OPM-NEXT: [[TMP3:%.*]] = load i8, i8* [[TMP2]], align 8
; IS__TUNIT_OPM-NEXT: [[TMP4:%.*]] = zext i8 [[TMP3]] to i32
; IS__TUNIT_OPM-NEXT: [[TMP5:%.*]] = add i32 [[TMP4]], [[TMP1]]
; IS__TUNIT_OPM-NEXT: ret i32 [[TMP5]]
; IS__TUNIT_OPM-NEXT: [[TMP2:%.*]] = load i8, i8* getelementptr inbounds ([[STRUCT_MYSTR]], %struct.MYstr* @mystr, i32 0, i32 0), align 8
; IS__TUNIT_OPM-NEXT: [[TMP3:%.*]] = zext i8 [[TMP2]] to i32
; IS__TUNIT_OPM-NEXT: [[TMP4:%.*]] = add i32 [[TMP3]], [[TMP1]]
; IS__TUNIT_OPM-NEXT: ret i32 [[TMP4]]
;
; IS__TUNIT_NPM: Function Attrs: nofree nosync nounwind readonly willreturn
; IS__TUNIT_NPM-LABEL: define {{[^@]+}}@vfu2
@ -76,11 +75,10 @@ define internal i32 @vfu2(%struct.MYstr* byval(%struct.MYstr) align 4 %u) nounwi
; IS__TUNIT_NPM-NEXT: store i32 [[TMP1]], i32* [[U_PRIV_0_1]], align 4
; IS__TUNIT_NPM-NEXT: [[TMP2:%.*]] = getelementptr [[STRUCT_MYSTR]], %struct.MYstr* @mystr, i32 0, i32 1
; IS__TUNIT_NPM-NEXT: [[TMP3:%.*]] = load i32, i32* [[TMP2]], align 4
; IS__TUNIT_NPM-NEXT: [[TMP4:%.*]] = getelementptr [[STRUCT_MYSTR]], %struct.MYstr* @mystr, i32 0, i32 0
; IS__TUNIT_NPM-NEXT: [[TMP5:%.*]] = load i8, i8* [[TMP4]], align 8
; IS__TUNIT_NPM-NEXT: [[TMP6:%.*]] = zext i8 [[TMP5]] to i32
; IS__TUNIT_NPM-NEXT: [[TMP7:%.*]] = add i32 [[TMP6]], [[TMP3]]
; IS__TUNIT_NPM-NEXT: ret i32 [[TMP7]]
; IS__TUNIT_NPM-NEXT: [[TMP4:%.*]] = load i8, i8* getelementptr inbounds ([[STRUCT_MYSTR]], %struct.MYstr* @mystr, i32 0, i32 0), align 8
; IS__TUNIT_NPM-NEXT: [[TMP5:%.*]] = zext i8 [[TMP4]] to i32
; IS__TUNIT_NPM-NEXT: [[TMP6:%.*]] = add i32 [[TMP5]], [[TMP3]]
; IS__TUNIT_NPM-NEXT: ret i32 [[TMP6]]
;
; IS__CGSCC____: Function Attrs: nofree norecurse nosync nounwind readonly willreturn
; IS__CGSCC____-LABEL: define {{[^@]+}}@vfu2
@ -88,11 +86,10 @@ define internal i32 @vfu2(%struct.MYstr* byval(%struct.MYstr) align 4 %u) nounwi
; IS__CGSCC____-NEXT: entry:
; IS__CGSCC____-NEXT: [[TMP0:%.*]] = getelementptr [[STRUCT_MYSTR:%.*]], %struct.MYstr* @mystr, i32 0, i32 1
; IS__CGSCC____-NEXT: [[TMP1:%.*]] = load i32, i32* [[TMP0]], align 4
; IS__CGSCC____-NEXT: [[TMP2:%.*]] = getelementptr [[STRUCT_MYSTR]], %struct.MYstr* @mystr, i32 0, i32 0
; IS__CGSCC____-NEXT: [[TMP3:%.*]] = load i8, i8* [[TMP2]], align 8
; IS__CGSCC____-NEXT: [[TMP4:%.*]] = zext i8 [[TMP3]] to i32
; IS__CGSCC____-NEXT: [[TMP5:%.*]] = add i32 [[TMP4]], [[TMP1]]
; IS__CGSCC____-NEXT: ret i32 [[TMP5]]
; IS__CGSCC____-NEXT: [[TMP2:%.*]] = load i8, i8* getelementptr inbounds ([[STRUCT_MYSTR]], %struct.MYstr* @mystr, i32 0, i32 0), align 8
; IS__CGSCC____-NEXT: [[TMP3:%.*]] = zext i8 [[TMP2]] to i32
; IS__CGSCC____-NEXT: [[TMP4:%.*]] = add i32 [[TMP3]], [[TMP1]]
; IS__CGSCC____-NEXT: ret i32 [[TMP4]]
;
entry:
%0 = getelementptr %struct.MYstr, %struct.MYstr* %u, i32 0, i32 1 ; <i32*> [#uses=1]
@ -245,9 +242,8 @@ define i32 @unions_v2() nounwind {
; IS__CGSCC_NPM-LABEL: define {{[^@]+}}@unions_v2
; IS__CGSCC_NPM-SAME: () #[[ATTR1]] {
; IS__CGSCC_NPM-NEXT: entry:
; IS__CGSCC_NPM-NEXT: [[MYSTR_CAST1:%.*]] = bitcast %struct.MYstr* @mystr to i8*
; IS__CGSCC_NPM-NEXT: [[TMP0:%.*]] = load i8, i8* [[MYSTR_CAST1]], align 8
; IS__CGSCC_NPM-NEXT: [[MYSTR_0_12:%.*]] = getelementptr [[STRUCT_MYSTR:%.*]], %struct.MYstr* @mystr, i32 0, i32 1
; IS__CGSCC_NPM-NEXT: [[TMP0:%.*]] = load i8, i8* getelementptr inbounds ([[STRUCT_MYSTR:%.*]], %struct.MYstr* @mystr, i32 0, i32 0), align 8
; IS__CGSCC_NPM-NEXT: [[MYSTR_0_12:%.*]] = getelementptr [[STRUCT_MYSTR]], %struct.MYstr* @mystr, i32 0, i32 1
; IS__CGSCC_NPM-NEXT: [[TMP1:%.*]] = load i32, i32* [[MYSTR_0_12]], align 8
; IS__CGSCC_NPM-NEXT: [[RESULT:%.*]] = call i32 @vfu2_v2(i8 [[TMP0]], i32 [[TMP1]]) #[[ATTR3:[0-9]+]]
; IS__CGSCC_NPM-NEXT: ret i32 [[RESULT]]

View File

@ -15,19 +15,11 @@ define i64 @fn2() {
; IS__TUNIT____-NEXT: [[CALL2:%.*]] = call i64 @fn1(i64 undef) #[[ATTR0]], !range [[RNG0:![0-9]+]]
; IS__TUNIT____-NEXT: ret i64 [[CALL2]]
;
; IS__CGSCC_OPM: Function Attrs: nofree norecurse nosync nounwind readnone willreturn
; IS__CGSCC_OPM-LABEL: define {{[^@]+}}@fn2
; IS__CGSCC_OPM-SAME: () #[[ATTR0:[0-9]+]] {
; IS__CGSCC_OPM-NEXT: entry:
; IS__CGSCC_OPM-NEXT: [[CALL2:%.*]] = call i64 @fn1(i64 undef) #[[ATTR1:[0-9]+]]
; IS__CGSCC_OPM-NEXT: ret i64 [[CALL2]]
;
; IS__CGSCC_NPM: Function Attrs: nofree norecurse nosync nounwind readnone willreturn
; IS__CGSCC_NPM-LABEL: define {{[^@]+}}@fn2
; IS__CGSCC_NPM-SAME: () #[[ATTR0:[0-9]+]] {
; IS__CGSCC_NPM-NEXT: entry:
; IS__CGSCC_NPM-NEXT: [[CALL2:%.*]] = call i64 @fn1(i64 undef) #[[ATTR1:[0-9]+]], !range [[RNG0:![0-9]+]]
; IS__CGSCC_NPM-NEXT: ret i64 [[CALL2]]
; IS__CGSCC____: Function Attrs: nofree norecurse nosync nounwind readnone willreturn
; IS__CGSCC____-LABEL: define {{[^@]+}}@fn2
; IS__CGSCC____-SAME: () #[[ATTR0:[0-9]+]] {
; IS__CGSCC____-NEXT: entry:
; IS__CGSCC____-NEXT: ret i64 undef
;
entry:
%conv = sext i32 undef to i64
@ -48,7 +40,7 @@ define i64 @fn2b(i32 %arg) {
;
; IS__CGSCC____: Function Attrs: nofree norecurse nosync nounwind readnone willreturn
; IS__CGSCC____-LABEL: define {{[^@]+}}@fn2b
; IS__CGSCC____-SAME: (i32 [[ARG:%.*]]) #[[ATTR0:[0-9]+]] {
; IS__CGSCC____-SAME: (i32 [[ARG:%.*]]) #[[ATTR0]] {
; IS__CGSCC____-NEXT: entry:
; IS__CGSCC____-NEXT: [[CONV:%.*]] = sext i32 [[ARG]] to i64
; IS__CGSCC____-NEXT: [[DIV:%.*]] = sdiv i64 8, [[CONV]]

View File

@ -26,21 +26,16 @@ define i32* @func1() {
; CHECK: Function Attrs: nofree nosync nounwind readnone willreturn
; CHECK-LABEL: define {{[^@]+}}@func1
; CHECK-SAME: () #[[ATTR0]] {
; CHECK-NEXT: [[PTR:%.*]] = call i32* @func1a() #[[ATTR0]]
; CHECK-NEXT: ret i32* [[PTR]]
; CHECK-NEXT: ret i32* getelementptr inbounds ([1 x i32], [1 x i32]* @var1, i32 0, i32 0)
;
%ptr = call i32* @func1a([1 x i32]* @var1)
ret i32* %ptr
}
; UTC_ARGS: --disable
; CHECK-LABEL: define internal noundef nonnull align 4 dereferenceable(4) i32* @func1a()
; CHECK-NEXT: ret i32* getelementptr inbounds ([1 x i32], [1 x i32]* @var1, i32 0, i32 0)
define internal i32* @func1a([1 x i32]* %arg) {
%ptr = getelementptr inbounds [1 x i32], [1 x i32]* %arg, i64 0, i64 0
ret i32* %ptr
}
; UTC_ARGS: --enable
define internal void @func2a(i32* %0) {
; CHECK: Function Attrs: nofree nosync nounwind willreturn writeonly

View File

@ -86,7 +86,7 @@ entry:
; CHECK-NOT: nounwind
; CHECK-NEXT: define
; CHECK-NEXT: entry:
; CHECK-NEXT: %call3 = call i32 (i8*, ...) @printf(i8* noundef nonnull dereferenceable(18) getelementptr inbounds ([18 x i8], [18 x i8]* @"??_C@_0BC@NKPAGFFJ@Exception?5caught?6?$AA@", i64 0, i64 0))
; CHECK-NEXT: %call3 = call i32 (i8*, ...) @printf(i8* noundef nonnull dereferenceable(18) getelementptr inbounds ([18 x i8], [18 x i8]* @"??_C@_0BC@NKPAGFFJ@Exception?5caught?6?$AA@", i32 0, i32 0))
; CHECK-NEXT: call void @"?overflow@@YAXXZ_may_throw"()
; CHECK-NEXT: unreachable
%call3 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([18 x i8], [18 x i8]* @"??_C@_0BC@NKPAGFFJ@Exception?5caught?6?$AA@", i64 0, i64 0))

View File

@ -82,7 +82,7 @@ entry:
; CHECK-NOT: nounwind
; CHECK-NEXT: define
; CHECK-NEXT: entry:
; CHECK-NEXT: %call3 = call i32 (i8*, ...) @printf(i8* noundef nonnull dereferenceable(18) getelementptr inbounds ([18 x i8], [18 x i8]* @"??_C@_0BC@NKPAGFFJ@Exception?5caught?6?$AA@", i64 0, i64 0))
; CHECK-NEXT: %call3 = call i32 (i8*, ...) @printf(i8* noundef nonnull dereferenceable(18) getelementptr inbounds ([18 x i8], [18 x i8]* @"??_C@_0BC@NKPAGFFJ@Exception?5caught?6?$AA@", i32 0, i32 0))
; CHECK-NEXT: call void @"?overflow@@YAXXZ_may_throw"()
; CHECK-NEXT: unreachable
%call3 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([18 x i8], [18 x i8]* @"??_C@_0BC@NKPAGFFJ@Exception?5caught?6?$AA@", i64 0, i64 0))

View File

@ -623,15 +623,13 @@ define internal i8*@test_byval2(%struct.X* byval(%struct.X) %a) {
; IS__TUNIT____: Function Attrs: nofree nosync nounwind readonly willreturn
; IS__TUNIT____-LABEL: define {{[^@]+}}@test_byval2
; IS__TUNIT____-SAME: () #[[ATTR4:[0-9]+]] {
; IS__TUNIT____-NEXT: [[G0:%.*]] = getelementptr [[STRUCT_X:%.*]], %struct.X* @S, i32 0, i32 0
; IS__TUNIT____-NEXT: [[L:%.*]] = load i8*, i8** [[G0]], align 8
; IS__TUNIT____-NEXT: [[L:%.*]] = load i8*, i8** getelementptr inbounds ([[STRUCT_X:%.*]], %struct.X* @S, i32 0, i32 0), align 8
; IS__TUNIT____-NEXT: ret i8* [[L]]
;
; IS__CGSCC____: Function Attrs: nofree norecurse nosync nounwind readonly willreturn
; IS__CGSCC____-LABEL: define {{[^@]+}}@test_byval2
; IS__CGSCC____-SAME: () #[[ATTR3:[0-9]+]] {
; IS__CGSCC____-NEXT: [[G0:%.*]] = getelementptr [[STRUCT_X:%.*]], %struct.X* @S, i32 0, i32 0
; IS__CGSCC____-NEXT: [[L:%.*]] = load i8*, i8** [[G0]], align 8
; IS__CGSCC____-NEXT: [[L:%.*]] = load i8*, i8** getelementptr inbounds ([[STRUCT_X:%.*]], %struct.X* @S, i32 0, i32 0), align 8
; IS__CGSCC____-NEXT: ret i8* [[L]]
;
%g0 = getelementptr %struct.X, %struct.X* %a, i32 0, i32 0