diff --git a/llvm/include/llvm/Transforms/IPO/Attributor.h b/llvm/include/llvm/Transforms/IPO/Attributor.h --- a/llvm/include/llvm/Transforms/IPO/Attributor.h +++ b/llvm/include/llvm/Transforms/IPO/Attributor.h @@ -131,6 +131,15 @@ 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; diff --git a/llvm/lib/Transforms/IPO/Attributor.cpp b/llvm/lib/Transforms/IPO/Attributor.cpp --- a/llvm/lib/Transforms/IPO/Attributor.cpp +++ b/llvm/lib/Transforms/IPO/Attributor.cpp @@ -159,6 +159,24 @@ } ///} +Value *AA::getWithType(Value &V, Type &Ty) { + if (V.getType() == &Ty) + return &V; + if (isa(V)) + return UndefValue::get(&Ty); + if (auto *C = dyn_cast(&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()) diff --git a/llvm/lib/Transforms/IPO/AttributorAttributes.cpp b/llvm/lib/Transforms/IPO/AttributorAttributes.cpp --- a/llvm/lib/Transforms/IPO/AttributorAttributes.cpp +++ b/llvm/lib/Transforms/IPO/AttributorAttributes.cpp @@ -4631,12 +4631,13 @@ auto *C = SimplifiedAssociatedValue.hasValue() ? dyn_cast(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 @@ auto *C = SimplifiedAssociatedValue.hasValue() ? dyn_cast(SimplifiedAssociatedValue.getValue()) : UndefValue::get(V.getType()); - if (C) { + if (C && C != &V) { auto PredForReturned = [&](Value &V, const SmallSetVector &RetInsts) { // We can replace the AssociatedValue with the constant. - if (&V == C || V.getType() != C->getType() || isa(V)) + if (&V == C || isa(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 @@ Use &U = cast(&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; } } diff --git a/llvm/test/Transforms/Attributor/ArgumentPromotion/fp80.ll b/llvm/test/Transforms/Attributor/ArgumentPromotion/fp80.ll --- a/llvm/test/Transforms/Attributor/ArgumentPromotion/fp80.ll +++ b/llvm/test/Transforms/Attributor/ArgumentPromotion/fp80.ll @@ -43,9 +43,8 @@ ; 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 ; diff --git a/llvm/test/Transforms/Attributor/IPConstantProp/2009-09-24-byval-ptr.ll b/llvm/test/Transforms/Attributor/IPConstantProp/2009-09-24-byval-ptr.ll --- a/llvm/test/Transforms/Attributor/IPConstantProp/2009-09-24-byval-ptr.ll +++ b/llvm/test/Transforms/Attributor/IPConstantProp/2009-09-24-byval-ptr.ll @@ -59,11 +59,10 @@ ; 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 @@ ; 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 @@ ; 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 ; [#uses=1] @@ -245,9 +242,8 @@ ; 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]] diff --git a/llvm/test/Transforms/Attributor/IPConstantProp/PR16052.ll b/llvm/test/Transforms/Attributor/IPConstantProp/PR16052.ll --- a/llvm/test/Transforms/Attributor/IPConstantProp/PR16052.ll +++ b/llvm/test/Transforms/Attributor/IPConstantProp/PR16052.ll @@ -15,19 +15,11 @@ ; 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 @@ ; ; 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]] diff --git a/llvm/test/Transforms/Attributor/misc_crash.ll b/llvm/test/Transforms/Attributor/misc_crash.ll --- a/llvm/test/Transforms/Attributor/misc_crash.ll +++ b/llvm/test/Transforms/Attributor/misc_crash.ll @@ -26,21 +26,16 @@ ; 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 diff --git a/llvm/test/Transforms/Attributor/noreturn_async.ll b/llvm/test/Transforms/Attributor/noreturn_async.ll --- a/llvm/test/Transforms/Attributor/noreturn_async.ll +++ b/llvm/test/Transforms/Attributor/noreturn_async.ll @@ -86,7 +86,7 @@ ; 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)) diff --git a/llvm/test/Transforms/Attributor/noreturn_sync.ll b/llvm/test/Transforms/Attributor/noreturn_sync.ll --- a/llvm/test/Transforms/Attributor/noreturn_sync.ll +++ b/llvm/test/Transforms/Attributor/noreturn_sync.ll @@ -82,7 +82,7 @@ ; 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)) diff --git a/llvm/test/Transforms/Attributor/value-simplify.ll b/llvm/test/Transforms/Attributor/value-simplify.ll --- a/llvm/test/Transforms/Attributor/value-simplify.ll +++ b/llvm/test/Transforms/Attributor/value-simplify.ll @@ -623,15 +623,13 @@ ; 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