Index: lib/Analysis/IPA/InlineCost.cpp =================================================================== --- lib/Analysis/IPA/InlineCost.cpp +++ lib/Analysis/IPA/InlineCost.cpp @@ -1284,20 +1284,46 @@ return getInlineCost(CS, CS.getCalledFunction(), Threshold); } -/// \brief Test that two functions either have or have not the given attribute -/// at the same time. -static bool attributeMatches(Function *F1, Function *F2, - Attribute::AttrKind Attr) { - return F1->hasFnAttribute(Attr) == F2->hasFnAttribute(Attr); +/// \brief Remove attributes not needed for testing compatibility. +static AttributeSet removeWhiteListedAttrs(AttributeSet AS, LLVMContext &C) { + AttrBuilder Builder(AS, AttributeSet::FunctionIndex); + + Builder.removeAttribute(Attribute::AlwaysInline); + Builder.removeAttribute(Attribute::Cold); + Builder.removeAttribute(Attribute::InlineHint); + Builder.removeAttribute(Attribute::JumpTable); + Builder.removeAttribute(Attribute::MinSize); + Builder.removeAttribute(Attribute::Naked); + Builder.removeAttribute(Attribute::NoBuiltin); + Builder.removeAttribute(Attribute::NoDuplicate); + Builder.removeAttribute(Attribute::NoInline); + Builder.removeAttribute(Attribute::NonLazyBind); + Builder.removeAttribute(Attribute::NoRedZone); + Builder.removeAttribute(Attribute::NoReturn); + Builder.removeAttribute(Attribute::NoUnwind); + Builder.removeAttribute(Attribute::OptimizeForSize); + Builder.removeAttribute(Attribute::OptimizeNone); + Builder.removeAttribute(Attribute::ReadNone); + Builder.removeAttribute(Attribute::ReadOnly); + Builder.removeAttribute(Attribute::ReturnsTwice); + Builder.removeAttribute(Attribute::StackProtect); + Builder.removeAttribute(Attribute::StackProtectReq); + Builder.removeAttribute(Attribute::StackProtectStrong); + Builder.removeAttribute(Attribute::UWTable); + + return AttributeSet::get(C, AttributeSet::FunctionIndex, Builder); } /// \brief Test that there are no attribute conflicts between Caller and Callee /// that prevent inlining. static bool functionsHaveCompatibleAttributes(Function *Caller, Function *Callee) { - return attributeMatches(Caller, Callee, Attribute::SanitizeAddress) && - attributeMatches(Caller, Callee, Attribute::SanitizeMemory) && - attributeMatches(Caller, Callee, Attribute::SanitizeThread); + AttributeSet CallerAttrs = Caller->getAttributes().getFnAttributes(); + AttributeSet CalleeAttrs = Callee->getAttributes().getFnAttributes(); + LLVMContext &C = Caller->getContext(); + + return removeWhiteListedAttrs(CallerAttrs, C) == + removeWhiteListedAttrs(CalleeAttrs, C); } InlineCost InlineCostAnalysis::getInlineCost(CallSite CS, Function *Callee, Index: test/Transforms/Inline/attributes.ll =================================================================== --- test/Transforms/Inline/attributes.ll +++ test/Transforms/Inline/attributes.ll @@ -110,3 +110,131 @@ ; CHECK-NEXT: @noattr_callee ; CHECK-NEXT: ret i32 } + +define i32 @alignstack_callee0(i32 %i) alignstack(8) { + %1 = call i32 @noattr_callee(i32 %i) + ret i32 %1 +; CHECK-LABEL: @alignstack_callee0( +; CHECK-NEXT: @noattr_callee +; CHECK-NEXT: ret i32 +} + +define i32 @test_alignstack0(i32 %i) alignstack(4) { + %1 = call i32 @alignstack_callee0(i32 %i) + ret i32 %1 +; CHECK-LABEL: @test_alignstack0( +; CHECK-NEXT: @alignstack_callee0 +; CHECK-NEXT: ret i32 +} + +define i32 @alignstack_callee1(i32 %i) alignstack(4) { + %1 = call i32 @noattr_callee(i32 %i) + ret i32 %1 +; CHECK-LABEL: @alignstack_callee1( +; CHECK-NEXT: @noattr_callee +; CHECK-NEXT: ret i32 +} + +define i32 @test_alignstack1(i32 %i) alignstack(4) { + %1 = call i32 @alignstack_callee1(i32 %i) + ret i32 %1 +; CHECK-LABEL: @test_alignstack1( +; CHECK-NEXT: @noattr_callee +; CHECK-NEXT: ret i32 +} + +define i32 @noimplicitfloat_callee(i32 %i) noimplicitfloat { + %1 = call i32 @noattr_callee(i32 %i) + ret i32 %1 +; CHECK-LABEL: @noimplicitfloat_callee( +; CHECK-NEXT: @noattr_callee +; CHECK-NEXT: ret i32 +} + +define i32 @test_noimplicitfloat(i32 %i) { + %1 = call i32 @noimplicitfloat_callee(i32 %i) + ret i32 %1 +; CHECK-LABEL: @test_noimplicitfloat( +; CHECK-NEXT: @noimplicitfloat_callee +; CHECK-NEXT: ret i32 +} + +define i32 @less-precise-fpmad_callee(i32 %i) "less-precise-fpmad"="true" { + %1 = call i32 @noattr_callee(i32 %i) + ret i32 %1 +; CHECK-LABEL: @less-precise-fpmad_callee( +; CHECK-NEXT: @noattr_callee +; CHECK-NEXT: ret i32 +} + +define i32 @test_less-precise-fpmad(i32 %i) "less-precise-fpmad"="false" { + %1 = call i32 @less-precise-fpmad_callee(i32 %i) + ret i32 %1 +; CHECK-LABEL: @test_less-precise-fpmad( +; CHECK-NEXT: @less-precise-fpmad_callee +; CHECK-NEXT: ret i32 +} + +define i32 @no-infs-fp-math_callee(i32 %i) "no-infs-fp-math"="true" { + %1 = call i32 @noattr_callee(i32 %i) + ret i32 %1 +; CHECK-LABEL: @no-infs-fp-math_callee( +; CHECK-NEXT: @noattr_callee +; CHECK-NEXT: ret i32 +} + +define i32 @test_no-infs-fp-math(i32 %i) "no-infs-fp-math"="false" { + %1 = call i32 @no-infs-fp-math_callee(i32 %i) + ret i32 %1 +; CHECK-LABEL: @test_no-infs-fp-math( +; CHECK-NEXT: @no-infs-fp-math_callee +; CHECK-NEXT: ret i32 +} + +define i32 @no-nans-fp-math_callee(i32 %i) "no-nans-fp-math"="true" { + %1 = call i32 @noattr_callee(i32 %i) + ret i32 %1 +; CHECK-LABEL: @no-nans-fp-math_callee( +; CHECK-NEXT: @noattr_callee +; CHECK-NEXT: ret i32 +} + +define i32 @test_no-nans-fp-math(i32 %i) "no-nans-fp-math"="false" { + %1 = call i32 @no-nans-fp-math_callee(i32 %i) + ret i32 %1 +; CHECK-LABEL: @test_no-nans-fp-math( +; CHECK-NEXT: @no-nans-fp-math_callee +; CHECK-NEXT: ret i32 +} + +define i32 @unsafe-fp-math_callee(i32 %i) "unsafe-fp-math"="true" { + %1 = call i32 @noattr_callee(i32 %i) + ret i32 %1 +; CHECK-LABEL: @unsafe-fp-math_callee( +; CHECK-NEXT: @noattr_callee +; CHECK-NEXT: ret i32 +} + +define i32 @test_unsafe-fp-math(i32 %i) "unsafe-fp-math"="false" { + %1 = call i32 @unsafe-fp-math_callee(i32 %i) + ret i32 %1 +; CHECK-LABEL: @test_unsafe-fp-math( +; CHECK-NEXT: @unsafe-fp-math_callee +; CHECK-NEXT: ret i32 +} + +define i32 @use-soft-float_callee(i32 %i) "use-soft-float"="true" { + %1 = call i32 @noattr_callee(i32 %i) + ret i32 %1 +; CHECK-LABEL: @use-soft-float_callee( +; CHECK-NEXT: @noattr_callee +; CHECK-NEXT: ret i32 +} + +define i32 @test_use-soft-float(i32 %i) "use-soft-float"="false" { + %1 = call i32 @use-soft-float_callee(i32 %i) + ret i32 %1 +; CHECK-LABEL: @test_use-soft-float( +; CHECK-NEXT: @use-soft-float_callee +; CHECK-NEXT: ret i32 +}