2013-01-12 15:13:45 +01:00
|
|
|
//===- llvm/unittest/IR/AttributesTest.cpp - Attributes unit tests --------===//
|
|
|
|
//
|
2019-01-19 09:50:56 +01:00
|
|
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
|
|
|
// See https://llvm.org/LICENSE.txt for license information.
|
|
|
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
2013-01-12 15:13:45 +01:00
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
|
|
|
#include "llvm/IR/Attributes.h"
|
2021-07-07 23:28:41 +02:00
|
|
|
#include "llvm/AsmParser/Parser.h"
|
2019-05-30 20:48:23 +02:00
|
|
|
#include "llvm/IR/DerivedTypes.h"
|
2021-07-07 23:28:41 +02:00
|
|
|
#include "llvm/IR/InstrTypes.h"
|
|
|
|
#include "llvm/IR/LLVMContext.h"
|
|
|
|
#include "llvm/IR/Module.h"
|
|
|
|
#include "llvm/Support/SourceMgr.h"
|
2013-01-12 15:13:45 +01:00
|
|
|
#include "gtest/gtest.h"
|
|
|
|
using namespace llvm;
|
|
|
|
|
|
|
|
namespace {
|
|
|
|
|
|
|
|
TEST(Attributes, Uniquing) {
|
|
|
|
LLVMContext C;
|
|
|
|
|
|
|
|
Attribute AttrA = Attribute::get(C, Attribute::AlwaysInline);
|
|
|
|
Attribute AttrB = Attribute::get(C, Attribute::AlwaysInline);
|
|
|
|
EXPECT_EQ(AttrA, AttrB);
|
|
|
|
|
Rename AttributeSet to AttributeList
Summary:
This class is a list of AttributeSetNodes corresponding the function
prototype of a call or function declaration. This class used to be
called ParamAttrListPtr, then AttrListPtr, then AttributeSet. It is
typically accessed by parameter and return value index, so
"AttributeList" seems like a more intuitive name.
Rename AttributeSetImpl to AttributeListImpl to follow suit.
It's useful to rename this class so that we can rename AttributeSetNode
to AttributeSet later. AttributeSet is the set of attributes that apply
to a single function, argument, or return value.
Reviewers: sanjoy, javed.absar, chandlerc, pete
Reviewed By: pete
Subscribers: pete, jholewinski, arsenm, dschuff, mehdi_amini, jfb, nhaehnle, sbc100, void, llvm-commits
Differential Revision: https://reviews.llvm.org/D31102
llvm-svn: 298393
2017-03-21 17:57:19 +01:00
|
|
|
AttributeList ASs[] = {AttributeList::get(C, 1, Attribute::ZExt),
|
|
|
|
AttributeList::get(C, 2, Attribute::SExt)};
|
2013-01-12 15:13:45 +01:00
|
|
|
|
Rename AttributeSet to AttributeList
Summary:
This class is a list of AttributeSetNodes corresponding the function
prototype of a call or function declaration. This class used to be
called ParamAttrListPtr, then AttrListPtr, then AttributeSet. It is
typically accessed by parameter and return value index, so
"AttributeList" seems like a more intuitive name.
Rename AttributeSetImpl to AttributeListImpl to follow suit.
It's useful to rename this class so that we can rename AttributeSetNode
to AttributeSet later. AttributeSet is the set of attributes that apply
to a single function, argument, or return value.
Reviewers: sanjoy, javed.absar, chandlerc, pete
Reviewed By: pete
Subscribers: pete, jholewinski, arsenm, dschuff, mehdi_amini, jfb, nhaehnle, sbc100, void, llvm-commits
Differential Revision: https://reviews.llvm.org/D31102
llvm-svn: 298393
2017-03-21 17:57:19 +01:00
|
|
|
AttributeList SetA = AttributeList::get(C, ASs);
|
|
|
|
AttributeList SetB = AttributeList::get(C, ASs);
|
2013-01-12 15:13:45 +01:00
|
|
|
EXPECT_EQ(SetA, SetB);
|
|
|
|
}
|
|
|
|
|
2013-08-03 00:29:40 +02:00
|
|
|
TEST(Attributes, Ordering) {
|
|
|
|
LLVMContext C;
|
|
|
|
|
2016-04-05 01:06:05 +02:00
|
|
|
Attribute Align4 = Attribute::get(C, Attribute::Alignment, 4);
|
|
|
|
Attribute Align5 = Attribute::get(C, Attribute::Alignment, 5);
|
|
|
|
Attribute Deref4 = Attribute::get(C, Attribute::Dereferenceable, 4);
|
|
|
|
Attribute Deref5 = Attribute::get(C, Attribute::Dereferenceable, 5);
|
|
|
|
EXPECT_TRUE(Align4 < Align5);
|
|
|
|
EXPECT_TRUE(Align4 < Deref4);
|
|
|
|
EXPECT_TRUE(Align4 < Deref5);
|
|
|
|
EXPECT_TRUE(Align5 < Deref4);
|
|
|
|
|
2019-05-30 20:48:23 +02:00
|
|
|
Attribute ByVal = Attribute::get(C, Attribute::ByVal, Type::getInt32Ty(C));
|
|
|
|
EXPECT_FALSE(ByVal < Attribute::get(C, Attribute::ZExt));
|
|
|
|
EXPECT_TRUE(ByVal < Align4);
|
2020-06-23 13:43:02 +02:00
|
|
|
EXPECT_FALSE(ByVal < ByVal);
|
2019-05-30 20:48:23 +02:00
|
|
|
|
Rename AttributeSet to AttributeList
Summary:
This class is a list of AttributeSetNodes corresponding the function
prototype of a call or function declaration. This class used to be
called ParamAttrListPtr, then AttrListPtr, then AttributeSet. It is
typically accessed by parameter and return value index, so
"AttributeList" seems like a more intuitive name.
Rename AttributeSetImpl to AttributeListImpl to follow suit.
It's useful to rename this class so that we can rename AttributeSetNode
to AttributeSet later. AttributeSet is the set of attributes that apply
to a single function, argument, or return value.
Reviewers: sanjoy, javed.absar, chandlerc, pete
Reviewed By: pete
Subscribers: pete, jholewinski, arsenm, dschuff, mehdi_amini, jfb, nhaehnle, sbc100, void, llvm-commits
Differential Revision: https://reviews.llvm.org/D31102
llvm-svn: 298393
2017-03-21 17:57:19 +01:00
|
|
|
AttributeList ASs[] = {AttributeList::get(C, 2, Attribute::ZExt),
|
|
|
|
AttributeList::get(C, 1, Attribute::SExt)};
|
2013-08-03 00:29:40 +02:00
|
|
|
|
Rename AttributeSet to AttributeList
Summary:
This class is a list of AttributeSetNodes corresponding the function
prototype of a call or function declaration. This class used to be
called ParamAttrListPtr, then AttrListPtr, then AttributeSet. It is
typically accessed by parameter and return value index, so
"AttributeList" seems like a more intuitive name.
Rename AttributeSetImpl to AttributeListImpl to follow suit.
It's useful to rename this class so that we can rename AttributeSetNode
to AttributeSet later. AttributeSet is the set of attributes that apply
to a single function, argument, or return value.
Reviewers: sanjoy, javed.absar, chandlerc, pete
Reviewed By: pete
Subscribers: pete, jholewinski, arsenm, dschuff, mehdi_amini, jfb, nhaehnle, sbc100, void, llvm-commits
Differential Revision: https://reviews.llvm.org/D31102
llvm-svn: 298393
2017-03-21 17:57:19 +01:00
|
|
|
AttributeList SetA = AttributeList::get(C, ASs);
|
2017-05-03 00:07:37 +02:00
|
|
|
AttributeList SetB = SetA.removeAttributes(C, 1, ASs[1].getAttributes(1));
|
2013-08-03 00:29:40 +02:00
|
|
|
EXPECT_NE(SetA, SetB);
|
|
|
|
}
|
|
|
|
|
2017-04-19 00:10:18 +02:00
|
|
|
TEST(Attributes, AddAttributes) {
|
|
|
|
LLVMContext C;
|
|
|
|
AttributeList AL;
|
|
|
|
AttrBuilder B;
|
|
|
|
B.addAttribute(Attribute::NoReturn);
|
|
|
|
AL = AL.addAttributes(C, AttributeList::FunctionIndex, AttributeSet::get(C, B));
|
|
|
|
EXPECT_TRUE(AL.hasFnAttribute(Attribute::NoReturn));
|
2017-04-19 03:51:13 +02:00
|
|
|
B.clear();
|
|
|
|
B.addAttribute(Attribute::SExt);
|
|
|
|
AL = AL.addAttributes(C, AttributeList::ReturnIndex, B);
|
|
|
|
EXPECT_TRUE(AL.hasAttribute(AttributeList::ReturnIndex, Attribute::SExt));
|
|
|
|
EXPECT_TRUE(AL.hasFnAttribute(Attribute::NoReturn));
|
2017-04-19 00:10:18 +02:00
|
|
|
}
|
|
|
|
|
2018-01-17 20:15:21 +01:00
|
|
|
TEST(Attributes, RemoveAlign) {
|
|
|
|
LLVMContext C;
|
|
|
|
|
2019-10-15 14:56:24 +02:00
|
|
|
Attribute AlignAttr = Attribute::getWithAlignment(C, Align(8));
|
|
|
|
Attribute StackAlignAttr = Attribute::getWithStackAlignment(C, Align(32));
|
2018-01-17 20:15:21 +01:00
|
|
|
AttrBuilder B_align_readonly;
|
|
|
|
B_align_readonly.addAttribute(AlignAttr);
|
|
|
|
B_align_readonly.addAttribute(Attribute::ReadOnly);
|
|
|
|
AttrBuilder B_align;
|
|
|
|
B_align.addAttribute(AlignAttr);
|
|
|
|
AttrBuilder B_stackalign_optnone;
|
|
|
|
B_stackalign_optnone.addAttribute(StackAlignAttr);
|
|
|
|
B_stackalign_optnone.addAttribute(Attribute::OptimizeNone);
|
|
|
|
AttrBuilder B_stackalign;
|
|
|
|
B_stackalign.addAttribute(StackAlignAttr);
|
|
|
|
|
|
|
|
AttributeSet AS = AttributeSet::get(C, B_align_readonly);
|
|
|
|
EXPECT_TRUE(AS.getAlignment() == 8);
|
|
|
|
EXPECT_TRUE(AS.hasAttribute(Attribute::ReadOnly));
|
|
|
|
AS = AS.removeAttribute(C, Attribute::Alignment);
|
|
|
|
EXPECT_FALSE(AS.hasAttribute(Attribute::Alignment));
|
|
|
|
EXPECT_TRUE(AS.hasAttribute(Attribute::ReadOnly));
|
|
|
|
AS = AttributeSet::get(C, B_align_readonly);
|
|
|
|
AS = AS.removeAttributes(C, B_align);
|
|
|
|
EXPECT_TRUE(AS.getAlignment() == 0);
|
|
|
|
EXPECT_TRUE(AS.hasAttribute(Attribute::ReadOnly));
|
|
|
|
|
|
|
|
AttributeList AL;
|
|
|
|
AL = AL.addParamAttributes(C, 0, B_align_readonly);
|
|
|
|
AL = AL.addAttributes(C, 0, B_stackalign_optnone);
|
|
|
|
EXPECT_TRUE(AL.hasAttributes(0));
|
|
|
|
EXPECT_TRUE(AL.hasAttribute(0, Attribute::StackAlignment));
|
|
|
|
EXPECT_TRUE(AL.hasAttribute(0, Attribute::OptimizeNone));
|
|
|
|
EXPECT_TRUE(AL.getStackAlignment(0) == 32);
|
|
|
|
EXPECT_TRUE(AL.hasParamAttrs(0));
|
|
|
|
EXPECT_TRUE(AL.hasParamAttr(0, Attribute::Alignment));
|
|
|
|
EXPECT_TRUE(AL.hasParamAttr(0, Attribute::ReadOnly));
|
|
|
|
EXPECT_TRUE(AL.getParamAlignment(0) == 8);
|
|
|
|
|
|
|
|
AL = AL.removeParamAttribute(C, 0, Attribute::Alignment);
|
|
|
|
EXPECT_FALSE(AL.hasParamAttr(0, Attribute::Alignment));
|
|
|
|
EXPECT_TRUE(AL.hasParamAttr(0, Attribute::ReadOnly));
|
|
|
|
EXPECT_TRUE(AL.hasAttribute(0, Attribute::StackAlignment));
|
|
|
|
EXPECT_TRUE(AL.hasAttribute(0, Attribute::OptimizeNone));
|
|
|
|
EXPECT_TRUE(AL.getStackAlignment(0) == 32);
|
|
|
|
|
|
|
|
AL = AL.removeAttribute(C, 0, Attribute::StackAlignment);
|
|
|
|
EXPECT_FALSE(AL.hasParamAttr(0, Attribute::Alignment));
|
|
|
|
EXPECT_TRUE(AL.hasParamAttr(0, Attribute::ReadOnly));
|
|
|
|
EXPECT_FALSE(AL.hasAttribute(0, Attribute::StackAlignment));
|
|
|
|
EXPECT_TRUE(AL.hasAttribute(0, Attribute::OptimizeNone));
|
|
|
|
|
|
|
|
AttributeList AL2;
|
|
|
|
AL2 = AL2.addParamAttributes(C, 0, B_align_readonly);
|
|
|
|
AL2 = AL2.addAttributes(C, 0, B_stackalign_optnone);
|
|
|
|
|
|
|
|
AL2 = AL2.removeParamAttributes(C, 0, B_align);
|
|
|
|
EXPECT_FALSE(AL2.hasParamAttr(0, Attribute::Alignment));
|
|
|
|
EXPECT_TRUE(AL2.hasParamAttr(0, Attribute::ReadOnly));
|
|
|
|
EXPECT_TRUE(AL2.hasAttribute(0, Attribute::StackAlignment));
|
|
|
|
EXPECT_TRUE(AL2.hasAttribute(0, Attribute::OptimizeNone));
|
|
|
|
EXPECT_TRUE(AL2.getStackAlignment(0) == 32);
|
|
|
|
|
|
|
|
AL2 = AL2.removeAttributes(C, 0, B_stackalign);
|
|
|
|
EXPECT_FALSE(AL2.hasParamAttr(0, Attribute::Alignment));
|
|
|
|
EXPECT_TRUE(AL2.hasParamAttr(0, Attribute::ReadOnly));
|
|
|
|
EXPECT_FALSE(AL2.hasAttribute(0, Attribute::StackAlignment));
|
|
|
|
EXPECT_TRUE(AL2.hasAttribute(0, Attribute::OptimizeNone));
|
|
|
|
}
|
|
|
|
|
2017-05-20 00:23:47 +02:00
|
|
|
TEST(Attributes, AddMatchingAlignAttr) {
|
|
|
|
LLVMContext C;
|
|
|
|
AttributeList AL;
|
|
|
|
AL = AL.addAttribute(C, AttributeList::FirstArgIndex,
|
2019-10-15 14:56:24 +02:00
|
|
|
Attribute::getWithAlignment(C, Align(8)));
|
2017-05-20 00:23:47 +02:00
|
|
|
AL = AL.addAttribute(C, AttributeList::FirstArgIndex + 1,
|
2019-10-15 14:56:24 +02:00
|
|
|
Attribute::getWithAlignment(C, Align(32)));
|
2019-10-22 11:51:06 +02:00
|
|
|
EXPECT_EQ(Align(8), AL.getParamAlignment(0));
|
|
|
|
EXPECT_EQ(Align(32), AL.getParamAlignment(1));
|
2017-05-20 00:23:47 +02:00
|
|
|
|
|
|
|
AttrBuilder B;
|
|
|
|
B.addAttribute(Attribute::NonNull);
|
|
|
|
B.addAlignmentAttr(8);
|
|
|
|
AL = AL.addAttributes(C, AttributeList::FirstArgIndex, B);
|
2019-10-22 11:51:06 +02:00
|
|
|
EXPECT_EQ(Align(8), AL.getParamAlignment(0));
|
|
|
|
EXPECT_EQ(Align(32), AL.getParamAlignment(1));
|
2017-05-20 00:23:47 +02:00
|
|
|
EXPECT_TRUE(AL.hasParamAttribute(0, Attribute::NonNull));
|
|
|
|
}
|
|
|
|
|
2017-05-31 16:24:06 +02:00
|
|
|
TEST(Attributes, EmptyGet) {
|
|
|
|
LLVMContext C;
|
|
|
|
AttributeList EmptyLists[] = {AttributeList(), AttributeList()};
|
|
|
|
AttributeList AL = AttributeList::get(C, EmptyLists);
|
|
|
|
EXPECT_TRUE(AL.isEmpty());
|
|
|
|
}
|
|
|
|
|
2018-04-16 19:05:01 +02:00
|
|
|
TEST(Attributes, OverflowGet) {
|
|
|
|
LLVMContext C;
|
|
|
|
std::pair<unsigned, Attribute> Attrs[] = { { AttributeList::ReturnIndex, Attribute::get(C, Attribute::SExt) },
|
|
|
|
{ AttributeList::FunctionIndex, Attribute::get(C, Attribute::ReadOnly) } };
|
|
|
|
AttributeList AL = AttributeList::get(C, Attrs);
|
|
|
|
EXPECT_EQ(2U, AL.getNumAttrSets());
|
|
|
|
}
|
|
|
|
|
2019-05-30 20:48:23 +02:00
|
|
|
TEST(Attributes, StringRepresentation) {
|
|
|
|
LLVMContext C;
|
|
|
|
StructType *Ty = StructType::create(Type::getInt32Ty(C), "mystruct");
|
|
|
|
|
|
|
|
// Insufficiently careful printing can result in byval(%mystruct = { i32 })
|
|
|
|
Attribute A = Attribute::getWithByValType(C, Ty);
|
|
|
|
EXPECT_EQ(A.getAsString(), "byval(%mystruct)");
|
|
|
|
|
|
|
|
A = Attribute::getWithByValType(C, Type::getInt32Ty(C));
|
|
|
|
EXPECT_EQ(A.getAsString(), "byval(i32)");
|
|
|
|
}
|
|
|
|
|
2021-03-25 00:13:29 +01:00
|
|
|
TEST(Attributes, HasParentContext) {
|
|
|
|
LLVMContext C1, C2;
|
|
|
|
|
|
|
|
{
|
|
|
|
Attribute Attr1 = Attribute::get(C1, Attribute::AlwaysInline);
|
|
|
|
Attribute Attr2 = Attribute::get(C2, Attribute::AlwaysInline);
|
|
|
|
EXPECT_TRUE(Attr1.hasParentContext(C1));
|
|
|
|
EXPECT_FALSE(Attr1.hasParentContext(C2));
|
|
|
|
EXPECT_FALSE(Attr2.hasParentContext(C1));
|
|
|
|
EXPECT_TRUE(Attr2.hasParentContext(C2));
|
|
|
|
}
|
|
|
|
|
|
|
|
{
|
|
|
|
AttributeSet AS1 = AttributeSet::get(
|
|
|
|
C1, makeArrayRef(Attribute::get(C1, Attribute::NoReturn)));
|
|
|
|
AttributeSet AS2 = AttributeSet::get(
|
|
|
|
C2, makeArrayRef(Attribute::get(C2, Attribute::NoReturn)));
|
|
|
|
EXPECT_TRUE(AS1.hasParentContext(C1));
|
|
|
|
EXPECT_FALSE(AS1.hasParentContext(C2));
|
|
|
|
EXPECT_FALSE(AS2.hasParentContext(C1));
|
|
|
|
EXPECT_TRUE(AS2.hasParentContext(C2));
|
|
|
|
}
|
|
|
|
|
|
|
|
{
|
|
|
|
AttributeList AL1 = AttributeList::get(C1, 1, Attribute::ZExt);
|
|
|
|
AttributeList AL2 = AttributeList::get(C2, 1, Attribute::ZExt);
|
|
|
|
EXPECT_TRUE(AL1.hasParentContext(C1));
|
|
|
|
EXPECT_FALSE(AL1.hasParentContext(C2));
|
|
|
|
EXPECT_FALSE(AL2.hasParentContext(C1));
|
|
|
|
EXPECT_TRUE(AL2.hasParentContext(C2));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-04-28 22:15:39 +02:00
|
|
|
TEST(Attributes, AttributeListPrinting) {
|
|
|
|
LLVMContext C;
|
|
|
|
|
|
|
|
{
|
|
|
|
std::string S;
|
|
|
|
raw_string_ostream OS(S);
|
|
|
|
AttributeList AL;
|
|
|
|
AL.addAttribute(C, AttributeList::FunctionIndex, Attribute::AlwaysInline)
|
|
|
|
.print(OS);
|
|
|
|
EXPECT_EQ(S, "AttributeList[\n"
|
|
|
|
" { function => alwaysinline }\n"
|
|
|
|
"]\n");
|
|
|
|
}
|
|
|
|
|
|
|
|
{
|
|
|
|
std::string S;
|
|
|
|
raw_string_ostream OS(S);
|
|
|
|
AttributeList AL;
|
|
|
|
AL.addAttribute(C, AttributeList::ReturnIndex, Attribute::SExt).print(OS);
|
|
|
|
EXPECT_EQ(S, "AttributeList[\n"
|
|
|
|
" { return => signext }\n"
|
|
|
|
"]\n");
|
|
|
|
}
|
|
|
|
|
|
|
|
{
|
|
|
|
std::string S;
|
|
|
|
raw_string_ostream OS(S);
|
|
|
|
AttributeList AL;
|
|
|
|
AL.addParamAttribute(C, 5, Attribute::ZExt).print(OS);
|
|
|
|
EXPECT_EQ(S, "AttributeList[\n"
|
|
|
|
" { arg(5) => zeroext }\n"
|
|
|
|
"]\n");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-07-07 23:28:41 +02:00
|
|
|
TEST(Attributes, MismatchedABIAttrs) {
|
|
|
|
const char *IRString = R"IR(
|
|
|
|
declare void @f1(i32* byval(i32))
|
|
|
|
define void @g() {
|
|
|
|
call void @f1(i32* null)
|
|
|
|
ret void
|
|
|
|
}
|
|
|
|
declare void @f2(i32* preallocated(i32))
|
|
|
|
define void @h() {
|
|
|
|
call void @f2(i32* null)
|
|
|
|
ret void
|
|
|
|
}
|
|
|
|
declare void @f3(i32* inalloca(i32))
|
|
|
|
define void @i() {
|
|
|
|
call void @f3(i32* null)
|
|
|
|
ret void
|
|
|
|
}
|
|
|
|
)IR";
|
|
|
|
|
|
|
|
SMDiagnostic Err;
|
|
|
|
LLVMContext Context;
|
|
|
|
std::unique_ptr<Module> M = parseAssemblyString(IRString, Err, Context);
|
|
|
|
ASSERT_TRUE(M);
|
|
|
|
|
|
|
|
{
|
|
|
|
auto *I = cast<CallBase>(&M->getFunction("g")->getEntryBlock().front());
|
|
|
|
ASSERT_TRUE(I->isByValArgument(0));
|
|
|
|
ASSERT_TRUE(I->getParamByValType(0));
|
|
|
|
}
|
|
|
|
{
|
|
|
|
auto *I = cast<CallBase>(&M->getFunction("h")->getEntryBlock().front());
|
|
|
|
ASSERT_TRUE(I->getParamPreallocatedType(0));
|
|
|
|
}
|
|
|
|
{
|
|
|
|
auto *I = cast<CallBase>(&M->getFunction("i")->getEntryBlock().front());
|
|
|
|
ASSERT_TRUE(I->isInAllocaArgument(0));
|
|
|
|
ASSERT_TRUE(I->getParamInAllocaType(0));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-01-12 15:13:45 +01:00
|
|
|
} // end anonymous namespace
|