diff --git a/llvm/include/llvm/IR/Attributes.h b/llvm/include/llvm/IR/Attributes.h --- a/llvm/include/llvm/IR/Attributes.h +++ b/llvm/include/llvm/IR/Attributes.h @@ -604,6 +604,10 @@ unsigned MinValue, unsigned MaxValue); + /// Merge two AttributeLists. If either is empty, the other one is returned. + LLVM_NODISCARD AttributeList merge(LLVMContext &C, + const AttributeList &Other); + //===--------------------------------------------------------------------===// // AttributeList Accessors //===--------------------------------------------------------------------===// diff --git a/llvm/lib/IR/Attributes.cpp b/llvm/lib/IR/Attributes.cpp --- a/llvm/lib/IR/Attributes.cpp +++ b/llvm/lib/IR/Attributes.cpp @@ -1550,6 +1550,25 @@ return addAttributes(C, Index, B); } +AttributeList AttributeList::merge(LLVMContext &C, const AttributeList &Other) { + if (isEmpty()) + return Other; + if (Other.isEmpty()) + return *this; + + auto IndexEnd = std::max(this->index_end(), Other.index_end()); + if (index_begin() == IndexEnd) + return {}; + + SmallVector AttrSets; + for (unsigned I = index_begin(); I != IndexEnd; ++I) { + AttrBuilder B1(*this, I); + AttrBuilder B2(Other, I); + AttrSets.push_back(AttributeSet::get(C, B1.merge(B2))); + } + return getImpl(C, AttrSets); +} + //===----------------------------------------------------------------------===// // AttributeList Accessor Methods //===----------------------------------------------------------------------===// diff --git a/llvm/lib/Transforms/Utils/BuildLibCalls.cpp b/llvm/lib/Transforms/Utils/BuildLibCalls.cpp --- a/llvm/lib/Transforms/Utils/BuildLibCalls.cpp +++ b/llvm/lib/Transforms/Utils/BuildLibCalls.cpp @@ -1498,9 +1498,11 @@ // The incoming attribute set may have come from a speculatable intrinsic, but // is being replaced with a library call which is not allowed to be // speculatable. - CI->setAttributes(Attrs.removeAttribute(B.getContext(), - AttributeList::FunctionIndex, - Attribute::Speculatable)); + CI->setAttributes( + Attrs + .removeAttribute(B.getContext(), AttributeList::FunctionIndex, + Attribute::Speculatable) + .merge(B.getContext(), CI->getCalledFunction()->getAttributes())); if (const Function *F = dyn_cast(Callee.getCallee()->stripPointerCasts())) CI->setCallingConv(F->getCallingConv()); diff --git a/llvm/test/Transforms/InstCombine/exp2-1.ll b/llvm/test/Transforms/InstCombine/exp2-1.ll --- a/llvm/test/Transforms/InstCombine/exp2-1.ll +++ b/llvm/test/Transforms/InstCombine/exp2-1.ll @@ -15,7 +15,7 @@ define double @test_simplify1(i32 %x) { ; LDEXP32-LABEL: @test_simplify1( -; LDEXP32-NEXT: [[LDEXP:%.*]] = call double @ldexp(double 1.000000e+00, i32 [[X:%.*]]) +; LDEXP32-NEXT: [[LDEXP:%.*]] = call double @ldexp(double 1.000000e+00, i32 signext [[X:%.*]]) ; LDEXP32-NEXT: ret double [[LDEXP]] ; ; LDEXP16-LABEL: @test_simplify1( @@ -24,7 +24,7 @@ ; LDEXP16-NEXT: ret double [[RET]] ; ; NOLDEXPF-LABEL: @test_simplify1( -; NOLDEXPF-NEXT: [[LDEXP:%.*]] = call double @ldexp(double 1.000000e+00, i32 [[X:%.*]]) +; NOLDEXPF-NEXT: [[LDEXP:%.*]] = call double @ldexp(double 1.000000e+00, i32 signext [[X:%.*]]) ; NOLDEXPF-NEXT: ret double [[LDEXP]] ; ; NOLDEXP-LABEL: @test_simplify1( @@ -40,16 +40,16 @@ define double @test_simplify2(i16 signext %x) { ; LDEXP32-LABEL: @test_simplify2( ; LDEXP32-NEXT: [[TMP1:%.*]] = sext i16 [[X:%.*]] to i32 -; LDEXP32-NEXT: [[LDEXP:%.*]] = call double @ldexp(double 1.000000e+00, i32 [[TMP1]]) +; LDEXP32-NEXT: [[LDEXP:%.*]] = call double @ldexp(double 1.000000e+00, i32 signext [[TMP1]]) ; LDEXP32-NEXT: ret double [[LDEXP]] ; ; LDEXP16-LABEL: @test_simplify2( -; LDEXP16-NEXT: [[LDEXP:%.*]] = call double @ldexp(double 1.000000e+00, i16 [[X:%.*]]) +; LDEXP16-NEXT: [[LDEXP:%.*]] = call double @ldexp(double 1.000000e+00, i16 signext [[X:%.*]]) ; LDEXP16-NEXT: ret double [[LDEXP]] ; ; NOLDEXPF-LABEL: @test_simplify2( ; NOLDEXPF-NEXT: [[TMP1:%.*]] = sext i16 [[X:%.*]] to i32 -; NOLDEXPF-NEXT: [[LDEXP:%.*]] = call double @ldexp(double 1.000000e+00, i32 [[TMP1]]) +; NOLDEXPF-NEXT: [[LDEXP:%.*]] = call double @ldexp(double 1.000000e+00, i32 signext [[TMP1]]) ; NOLDEXPF-NEXT: ret double [[LDEXP]] ; ; NOLDEXP-LABEL: @test_simplify2( @@ -65,17 +65,17 @@ define double @test_simplify3(i8 signext %x) { ; LDEXP32-LABEL: @test_simplify3( ; LDEXP32-NEXT: [[TMP1:%.*]] = sext i8 [[X:%.*]] to i32 -; LDEXP32-NEXT: [[LDEXP:%.*]] = call double @ldexp(double 1.000000e+00, i32 [[TMP1]]) +; LDEXP32-NEXT: [[LDEXP:%.*]] = call double @ldexp(double 1.000000e+00, i32 signext [[TMP1]]) ; LDEXP32-NEXT: ret double [[LDEXP]] ; ; LDEXP16-LABEL: @test_simplify3( ; LDEXP16-NEXT: [[TMP1:%.*]] = sext i8 [[X:%.*]] to i16 -; LDEXP16-NEXT: [[LDEXP:%.*]] = call double @ldexp(double 1.000000e+00, i16 [[TMP1]]) +; LDEXP16-NEXT: [[LDEXP:%.*]] = call double @ldexp(double 1.000000e+00, i16 signext [[TMP1]]) ; LDEXP16-NEXT: ret double [[LDEXP]] ; ; NOLDEXPF-LABEL: @test_simplify3( ; NOLDEXPF-NEXT: [[TMP1:%.*]] = sext i8 [[X:%.*]] to i32 -; NOLDEXPF-NEXT: [[LDEXP:%.*]] = call double @ldexp(double 1.000000e+00, i32 [[TMP1]]) +; NOLDEXPF-NEXT: [[LDEXP:%.*]] = call double @ldexp(double 1.000000e+00, i32 signext [[TMP1]]) ; NOLDEXPF-NEXT: ret double [[LDEXP]] ; ; NOLDEXP-LABEL: @test_simplify3( @@ -90,7 +90,7 @@ define float @test_simplify4(i32 %x) { ; LDEXP32-LABEL: @test_simplify4( -; LDEXP32-NEXT: [[LDEXPF:%.*]] = call float @ldexpf(float 1.000000e+00, i32 [[X:%.*]]) +; LDEXP32-NEXT: [[LDEXPF:%.*]] = call float @ldexpf(float 1.000000e+00, i32 signext [[X:%.*]]) ; LDEXP32-NEXT: ret float [[LDEXPF]] ; ; LDEXP16-LABEL: @test_simplify4( @@ -144,7 +144,7 @@ define double @test_simplify6(i16 zeroext %x) { ; LDEXP32-LABEL: @test_simplify6( ; LDEXP32-NEXT: [[TMP1:%.*]] = zext i16 [[X:%.*]] to i32 -; LDEXP32-NEXT: [[LDEXP:%.*]] = call double @ldexp(double 1.000000e+00, i32 [[TMP1]]) +; LDEXP32-NEXT: [[LDEXP:%.*]] = call double @ldexp(double 1.000000e+00, i32 signext [[TMP1]]) ; LDEXP32-NEXT: ret double [[LDEXP]] ; ; LDEXP16-LABEL: @test_simplify6( @@ -154,7 +154,7 @@ ; ; NOLDEXPF-LABEL: @test_simplify6( ; NOLDEXPF-NEXT: [[TMP1:%.*]] = zext i16 [[X:%.*]] to i32 -; NOLDEXPF-NEXT: [[LDEXP:%.*]] = call double @ldexp(double 1.000000e+00, i32 [[TMP1]]) +; NOLDEXPF-NEXT: [[LDEXP:%.*]] = call double @ldexp(double 1.000000e+00, i32 signext [[TMP1]]) ; NOLDEXPF-NEXT: ret double [[LDEXP]] ; ; NOLDEXP-LABEL: @test_simplify6( @@ -170,17 +170,17 @@ define double @test_simplify7(i8 zeroext %x) { ; LDEXP32-LABEL: @test_simplify7( ; LDEXP32-NEXT: [[TMP1:%.*]] = zext i8 [[X:%.*]] to i32 -; LDEXP32-NEXT: [[LDEXP:%.*]] = call double @ldexp(double 1.000000e+00, i32 [[TMP1]]) +; LDEXP32-NEXT: [[LDEXP:%.*]] = call double @ldexp(double 1.000000e+00, i32 signext [[TMP1]]) ; LDEXP32-NEXT: ret double [[LDEXP]] ; ; LDEXP16-LABEL: @test_simplify7( ; LDEXP16-NEXT: [[TMP1:%.*]] = zext i8 [[X:%.*]] to i16 -; LDEXP16-NEXT: [[LDEXP:%.*]] = call double @ldexp(double 1.000000e+00, i16 [[TMP1]]) +; LDEXP16-NEXT: [[LDEXP:%.*]] = call double @ldexp(double 1.000000e+00, i16 signext [[TMP1]]) ; LDEXP16-NEXT: ret double [[LDEXP]] ; ; NOLDEXPF-LABEL: @test_simplify7( ; NOLDEXPF-NEXT: [[TMP1:%.*]] = zext i8 [[X:%.*]] to i32 -; NOLDEXPF-NEXT: [[LDEXP:%.*]] = call double @ldexp(double 1.000000e+00, i32 [[TMP1]]) +; NOLDEXPF-NEXT: [[LDEXP:%.*]] = call double @ldexp(double 1.000000e+00, i32 signext [[TMP1]]) ; NOLDEXPF-NEXT: ret double [[LDEXP]] ; ; NOLDEXP-LABEL: @test_simplify7( @@ -196,12 +196,12 @@ define float @test_simplify8(i8 zeroext %x) { ; LDEXP32-LABEL: @test_simplify8( ; LDEXP32-NEXT: [[TMP1:%.*]] = zext i8 [[X:%.*]] to i32 -; LDEXP32-NEXT: [[LDEXPF:%.*]] = call float @ldexpf(float 1.000000e+00, i32 [[TMP1]]) +; LDEXP32-NEXT: [[LDEXPF:%.*]] = call float @ldexpf(float 1.000000e+00, i32 signext [[TMP1]]) ; LDEXP32-NEXT: ret float [[LDEXPF]] ; ; LDEXP16-LABEL: @test_simplify8( ; LDEXP16-NEXT: [[TMP1:%.*]] = zext i8 [[X:%.*]] to i16 -; LDEXP16-NEXT: [[LDEXPF:%.*]] = call float @ldexpf(float 1.000000e+00, i16 [[TMP1]]) +; LDEXP16-NEXT: [[LDEXPF:%.*]] = call float @ldexpf(float 1.000000e+00, i16 signext [[TMP1]]) ; LDEXP16-NEXT: ret float [[LDEXPF]] ; ; NOLDEXPF-LABEL: @test_simplify8( @@ -225,17 +225,17 @@ define double @test_simplify9(i8 zeroext %x) { ; LDEXP32-LABEL: @test_simplify9( ; LDEXP32-NEXT: [[TMP1:%.*]] = zext i8 [[X:%.*]] to i32 -; LDEXP32-NEXT: [[LDEXP:%.*]] = call double @ldexp(double 1.000000e+00, i32 [[TMP1]]) +; LDEXP32-NEXT: [[LDEXP:%.*]] = call double @ldexp(double 1.000000e+00, i32 signext [[TMP1]]) ; LDEXP32-NEXT: ret double [[LDEXP]] ; ; LDEXP16-LABEL: @test_simplify9( ; LDEXP16-NEXT: [[TMP1:%.*]] = zext i8 [[X:%.*]] to i16 -; LDEXP16-NEXT: [[LDEXP:%.*]] = call double @ldexp(double 1.000000e+00, i16 [[TMP1]]) +; LDEXP16-NEXT: [[LDEXP:%.*]] = call double @ldexp(double 1.000000e+00, i16 signext [[TMP1]]) ; LDEXP16-NEXT: ret double [[LDEXP]] ; ; NOLDEXPF-LABEL: @test_simplify9( ; NOLDEXPF-NEXT: [[TMP1:%.*]] = zext i8 [[X:%.*]] to i32 -; NOLDEXPF-NEXT: [[LDEXP:%.*]] = call double @ldexp(double 1.000000e+00, i32 [[TMP1]]) +; NOLDEXPF-NEXT: [[LDEXP:%.*]] = call double @ldexp(double 1.000000e+00, i32 signext [[TMP1]]) ; NOLDEXPF-NEXT: ret double [[LDEXP]] ; ; NOLDEXP-LABEL: @test_simplify9( @@ -251,12 +251,12 @@ define float @test_simplify10(i8 zeroext %x) { ; LDEXP32-LABEL: @test_simplify10( ; LDEXP32-NEXT: [[TMP1:%.*]] = zext i8 [[X:%.*]] to i32 -; LDEXP32-NEXT: [[LDEXPF:%.*]] = call float @ldexpf(float 1.000000e+00, i32 [[TMP1]]) +; LDEXP32-NEXT: [[LDEXPF:%.*]] = call float @ldexpf(float 1.000000e+00, i32 signext [[TMP1]]) ; LDEXP32-NEXT: ret float [[LDEXPF]] ; ; LDEXP16-LABEL: @test_simplify10( ; LDEXP16-NEXT: [[TMP1:%.*]] = zext i8 [[X:%.*]] to i16 -; LDEXP16-NEXT: [[LDEXPF:%.*]] = call float @ldexpf(float 1.000000e+00, i16 [[TMP1]]) +; LDEXP16-NEXT: [[LDEXPF:%.*]] = call float @ldexpf(float 1.000000e+00, i16 signext [[TMP1]]) ; LDEXP16-NEXT: ret float [[LDEXPF]] ; ; NOLDEXPF-LABEL: @test_simplify10( diff --git a/llvm/test/Transforms/InstCombine/pow_fp_int.ll b/llvm/test/Transforms/InstCombine/pow_fp_int.ll --- a/llvm/test/Transforms/InstCombine/pow_fp_int.ll +++ b/llvm/test/Transforms/InstCombine/pow_fp_int.ll @@ -51,7 +51,7 @@ define double @pow_sitofp_double_const_base_2_fast(i32 %x) { ; CHECK-LABEL: @pow_sitofp_double_const_base_2_fast( -; CHECK-NEXT: [[LDEXPF:%.*]] = call afn float @ldexpf(float 1.000000e+00, i32 [[X:%.*]]) +; CHECK-NEXT: [[LDEXPF:%.*]] = call afn float @ldexpf(float 1.000000e+00, i32 signext [[X:%.*]]) ; CHECK-NEXT: [[RES:%.*]] = fpext float [[LDEXPF]] to double ; CHECK-NEXT: ret double [[RES]] ; @@ -78,7 +78,7 @@ define double @pow_uitofp_const_base_2_fast(i31 %x) { ; CHECK-LABEL: @pow_uitofp_const_base_2_fast( ; CHECK-NEXT: [[TMP1:%.*]] = zext i31 [[X:%.*]] to i32 -; CHECK-NEXT: [[LDEXPF:%.*]] = call afn float @ldexpf(float 1.000000e+00, i32 [[TMP1]]) +; CHECK-NEXT: [[LDEXPF:%.*]] = call afn float @ldexpf(float 1.000000e+00, i32 signext [[TMP1]]) ; CHECK-NEXT: [[RES:%.*]] = fpext float [[LDEXPF]] to double ; CHECK-NEXT: ret double [[RES]] ; @@ -343,7 +343,7 @@ define double @pow_sitofp_const_base_2_no_fast(i32 %x) { ; CHECK-LABEL: @pow_sitofp_const_base_2_no_fast( -; CHECK-NEXT: [[LDEXPF:%.*]] = call float @ldexpf(float 1.000000e+00, i32 [[X:%.*]]) +; CHECK-NEXT: [[LDEXPF:%.*]] = call float @ldexpf(float 1.000000e+00, i32 signext [[X:%.*]]) ; CHECK-NEXT: [[RES:%.*]] = fpext float [[LDEXPF]] to double ; CHECK-NEXT: ret double [[RES]] ; diff --git a/llvm/test/Transforms/InstCombine/pow_fp_int16.ll b/llvm/test/Transforms/InstCombine/pow_fp_int16.ll --- a/llvm/test/Transforms/InstCombine/pow_fp_int16.ll +++ b/llvm/test/Transforms/InstCombine/pow_fp_int16.ll @@ -57,7 +57,7 @@ define double @pow_sitofp_double_const_base_2_fast(i16 %x) { ; CHECK-LABEL: @pow_sitofp_double_const_base_2_fast( -; CHECK-NEXT: [[LDEXPF:%.*]] = call afn float @ldexpf(float 1.000000e+00, i16 [[X:%.*]]) +; CHECK-NEXT: [[LDEXPF:%.*]] = call afn float @ldexpf(float 1.000000e+00, i16 signext [[X:%.*]]) ; CHECK-NEXT: [[RES:%.*]] = fpext float [[LDEXPF]] to double ; CHECK-NEXT: ret double [[RES]] ; @@ -84,7 +84,7 @@ define double @pow_uitofp_const_base_2_fast(i15 %x) { ; CHECK-LABEL: @pow_uitofp_const_base_2_fast( ; CHECK-NEXT: [[TMP1:%.*]] = zext i15 [[X:%.*]] to i16 -; CHECK-NEXT: [[LDEXPF:%.*]] = call afn float @ldexpf(float 1.000000e+00, i16 [[TMP1]]) +; CHECK-NEXT: [[LDEXPF:%.*]] = call afn float @ldexpf(float 1.000000e+00, i16 signext [[TMP1]]) ; CHECK-NEXT: [[RES:%.*]] = fpext float [[LDEXPF]] to double ; CHECK-NEXT: ret double [[RES]] ; @@ -322,7 +322,7 @@ define double @pow_sitofp_const_base_2_no_fast(i16 %x) { ; CHECK-LABEL: @pow_sitofp_const_base_2_no_fast( -; CHECK-NEXT: [[LDEXPF:%.*]] = call float @ldexpf(float 1.000000e+00, i16 [[X:%.*]]) +; CHECK-NEXT: [[LDEXPF:%.*]] = call float @ldexpf(float 1.000000e+00, i16 signext [[X:%.*]]) ; CHECK-NEXT: [[RES:%.*]] = fpext float [[LDEXPF]] to double ; CHECK-NEXT: ret double [[RES]] ; diff --git a/llvm/test/Transforms/InstCombine/simplify-libcalls.ll b/llvm/test/Transforms/InstCombine/simplify-libcalls.ll --- a/llvm/test/Transforms/InstCombine/simplify-libcalls.ll +++ b/llvm/test/Transforms/InstCombine/simplify-libcalls.ll @@ -190,7 +190,7 @@ } define double @fake_ldexp(i32 %x) { ; CHECK32-LABEL: @fake_ldexp( -; CHECK32-NEXT: [[Z:%.*]] = call double @ldexp(double 1.0{{.*}}, i32 %x) +; CHECK32-NEXT: [[Z:%.*]] = call double @ldexp(double 1.0{{.*}}, i32 signext %x) ; CHECK32-NEXT: ret double [[Z]] ; CHECK16-LABEL: @fake_ldexp( @@ -205,11 +205,11 @@ define double @fake_ldexp_16(i16 %x) { ; CHECK32-LABEL: @fake_ldexp_16( ; CHECK32-NEXT: [[Y:%.*]] = sext i16 %x to i32 -; CHECK32-NEXT: [[Z:%.*]] = call double @ldexp(double 1.0{{.*}}, i32 [[Y]]) +; CHECK32-NEXT: [[Z:%.*]] = call double @ldexp(double 1.0{{.*}}, i32 signext [[Y]]) ; CHECK32-NEXT: ret double [[Z]] ; CHECK16-LABEL: @fake_ldexp_16( -; CHECK16-NEXT: [[Z:%.*]] = call double @ldexp(double 1.0{{.*}}, i16 %x) +; CHECK16-NEXT: [[Z:%.*]] = call double @ldexp(double 1.0{{.*}}, i16 signext %x) ; CHECK16-NEXT: ret double [[Z]] %y = sitofp i16 %x to double @@ -217,6 +217,8 @@ ret double %z } +; CHECK: declare double @ldexp(double, i{{16|32}} signext) + attributes #0 = { nobuiltin } attributes #1 = { builtin } diff --git a/llvm/unittests/IR/AttributesTest.cpp b/llvm/unittests/IR/AttributesTest.cpp --- a/llvm/unittests/IR/AttributesTest.cpp +++ b/llvm/unittests/IR/AttributesTest.cpp @@ -68,6 +68,33 @@ EXPECT_TRUE(AL.hasFnAttribute(Attribute::NoReturn)); } +TEST(Attributes, MergeAttributes) { + LLVMContext C; + AttributeList AL1; + AttributeList AL2; + EXPECT_TRUE(AL1.merge(C, AL2).isEmpty()); + + AttrBuilder B; + B.addAttribute(Attribute::NoReturn); + AL1 = AL1.addAttributes(C, AttributeList::FunctionIndex, AttributeSet::get(C, B)); + AttributeList Merged = AL1.merge(C, AL2); + EXPECT_EQ(Merged, AL1); + + B.clear(); + B.addAttribute(Attribute::Hot); + AL2 = AL2.addParamAttributes(C, 1, B); + B.addAttribute(Attribute::Convergent); + AL1 = AL1.addParamAttributes(C, 1, B); + Merged = AL1.merge(C, AL2); + + EXPECT_TRUE(Merged.hasFnAttribute(Attribute::NoReturn)); + EXPECT_FALSE(Merged.hasParamAttribute(0, Attribute::NoReturn)); + EXPECT_TRUE(Merged.hasParamAttribute(1, Attribute::Hot)); + EXPECT_TRUE(Merged.hasParamAttribute(1, Attribute::Convergent)); + EXPECT_FALSE(Merged.hasAttrSomewhere(Attribute::Cold)); + EXPECT_EQ(Merged, AL2.merge(C, AL1)); +} + TEST(Attributes, RemoveAlign) { LLVMContext C;