mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2024-11-25 12:12:47 +01:00
b3ffc2a93b
These currently always require a type parameter. The bitcode reader already upgrades old bitcode without the type parameter to use the pointee type. In cases where the caller does not have byval but the callee does, we need to follow CallBase::paramHasAttr() and also look at the callee for the byval type so that CallBase::isByValArgument() and CallBase::getParamByValType() are in sync. Do the same for preallocated. While we're here add a corresponding version for inalloca since we'll need it soon. Reviewed By: nikic Differential Revision: https://reviews.llvm.org/D104663
300 lines
10 KiB
C++
300 lines
10 KiB
C++
//===- llvm/unittest/IR/AttributesTest.cpp - Attributes unit tests --------===//
|
|
//
|
|
// 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
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#include "llvm/IR/Attributes.h"
|
|
#include "llvm/AsmParser/Parser.h"
|
|
#include "llvm/IR/DerivedTypes.h"
|
|
#include "llvm/IR/InstrTypes.h"
|
|
#include "llvm/IR/LLVMContext.h"
|
|
#include "llvm/IR/Module.h"
|
|
#include "llvm/Support/SourceMgr.h"
|
|
#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);
|
|
|
|
AttributeList ASs[] = {AttributeList::get(C, 1, Attribute::ZExt),
|
|
AttributeList::get(C, 2, Attribute::SExt)};
|
|
|
|
AttributeList SetA = AttributeList::get(C, ASs);
|
|
AttributeList SetB = AttributeList::get(C, ASs);
|
|
EXPECT_EQ(SetA, SetB);
|
|
}
|
|
|
|
TEST(Attributes, Ordering) {
|
|
LLVMContext C;
|
|
|
|
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);
|
|
|
|
Attribute ByVal = Attribute::get(C, Attribute::ByVal, Type::getInt32Ty(C));
|
|
EXPECT_FALSE(ByVal < Attribute::get(C, Attribute::ZExt));
|
|
EXPECT_TRUE(ByVal < Align4);
|
|
EXPECT_FALSE(ByVal < ByVal);
|
|
|
|
AttributeList ASs[] = {AttributeList::get(C, 2, Attribute::ZExt),
|
|
AttributeList::get(C, 1, Attribute::SExt)};
|
|
|
|
AttributeList SetA = AttributeList::get(C, ASs);
|
|
AttributeList SetB = SetA.removeAttributes(C, 1, ASs[1].getAttributes(1));
|
|
EXPECT_NE(SetA, SetB);
|
|
}
|
|
|
|
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));
|
|
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));
|
|
}
|
|
|
|
TEST(Attributes, RemoveAlign) {
|
|
LLVMContext C;
|
|
|
|
Attribute AlignAttr = Attribute::getWithAlignment(C, Align(8));
|
|
Attribute StackAlignAttr = Attribute::getWithStackAlignment(C, Align(32));
|
|
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));
|
|
}
|
|
|
|
TEST(Attributes, AddMatchingAlignAttr) {
|
|
LLVMContext C;
|
|
AttributeList AL;
|
|
AL = AL.addAttribute(C, AttributeList::FirstArgIndex,
|
|
Attribute::getWithAlignment(C, Align(8)));
|
|
AL = AL.addAttribute(C, AttributeList::FirstArgIndex + 1,
|
|
Attribute::getWithAlignment(C, Align(32)));
|
|
EXPECT_EQ(Align(8), AL.getParamAlignment(0));
|
|
EXPECT_EQ(Align(32), AL.getParamAlignment(1));
|
|
|
|
AttrBuilder B;
|
|
B.addAttribute(Attribute::NonNull);
|
|
B.addAlignmentAttr(8);
|
|
AL = AL.addAttributes(C, AttributeList::FirstArgIndex, B);
|
|
EXPECT_EQ(Align(8), AL.getParamAlignment(0));
|
|
EXPECT_EQ(Align(32), AL.getParamAlignment(1));
|
|
EXPECT_TRUE(AL.hasParamAttribute(0, Attribute::NonNull));
|
|
}
|
|
|
|
TEST(Attributes, EmptyGet) {
|
|
LLVMContext C;
|
|
AttributeList EmptyLists[] = {AttributeList(), AttributeList()};
|
|
AttributeList AL = AttributeList::get(C, EmptyLists);
|
|
EXPECT_TRUE(AL.isEmpty());
|
|
}
|
|
|
|
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());
|
|
}
|
|
|
|
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)");
|
|
}
|
|
|
|
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));
|
|
}
|
|
}
|
|
|
|
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");
|
|
}
|
|
}
|
|
|
|
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));
|
|
}
|
|
}
|
|
|
|
} // end anonymous namespace
|