mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2026-07-18 13:15:38 -04:00
OpaquePtr: Add type to sret attribute
Make the corresponding change that was made for byval in b7141207a483d39b99c2b4da4eb3bb591eca9e1a. Like byval, this requires a bulk update of the test IR tests to include the type before this can be mandatory.
This commit is contained in:
+7
-3
@@ -1057,8 +1057,8 @@ Currently, only the following parameter attributes are defined:
|
||||
``byval`` parameters). This is not a valid attribute for return
|
||||
values.
|
||||
|
||||
The byval attribute also supports an optional type argument, which must be
|
||||
the same as the pointee type of the argument.
|
||||
The byval attribute also supports an optional type argument, which
|
||||
must be the same as the pointee type of the argument.
|
||||
|
||||
The byval attribute also supports specifying an alignment with the
|
||||
align attribute. It indicates the alignment of the stack slot to
|
||||
@@ -1144,7 +1144,7 @@ Currently, only the following parameter attributes are defined:
|
||||
See :doc:`InAlloca` for more information on how to use this
|
||||
attribute.
|
||||
|
||||
``sret``
|
||||
``sret`` or ``sret(<ty>)``
|
||||
This indicates that the pointer parameter specifies the address of a
|
||||
structure that is the return value of the function in the source
|
||||
program. This pointer must be guaranteed by the caller to be valid:
|
||||
@@ -1152,6 +1152,10 @@ Currently, only the following parameter attributes are defined:
|
||||
to trap and to be properly aligned. This is not a valid attribute
|
||||
for return values.
|
||||
|
||||
The sret attribute also supports an optional type argument, which
|
||||
must be the same as the pointee type of the argument. In the
|
||||
future this will be required.
|
||||
|
||||
.. _attr_align:
|
||||
|
||||
``align <n>`` or ``align(<n>)``
|
||||
|
||||
@@ -63,6 +63,9 @@ Changes to the LLVM IR
|
||||
* Added the ``byref`` attribute to better represent argument passing
|
||||
for the `amdgpu_kernel` calling convention.
|
||||
|
||||
* Added type parameter to the ``sret`` attribute to continue work on
|
||||
removing pointer element types.
|
||||
|
||||
Changes to building LLVM
|
||||
------------------------
|
||||
|
||||
|
||||
@@ -108,6 +108,7 @@ public:
|
||||
unsigned ElemSizeArg,
|
||||
const Optional<unsigned> &NumElemsArg);
|
||||
static Attribute getWithByValType(LLVMContext &Context, Type *Ty);
|
||||
static Attribute getWithStructRetType(LLVMContext &Context, Type *Ty);
|
||||
static Attribute getWithByRefType(LLVMContext &Context, Type *Ty);
|
||||
static Attribute getWithPreallocatedType(LLVMContext &Context, Type *Ty);
|
||||
|
||||
@@ -307,6 +308,7 @@ public:
|
||||
uint64_t getDereferenceableBytes() const;
|
||||
uint64_t getDereferenceableOrNullBytes() const;
|
||||
Type *getByValType() const;
|
||||
Type *getStructRetType() const;
|
||||
Type *getByRefType() const;
|
||||
Type *getPreallocatedType() const;
|
||||
std::pair<unsigned, Optional<unsigned>> getAllocSizeArgs() const;
|
||||
@@ -631,6 +633,9 @@ public:
|
||||
/// Return the byval type for the specified function parameter.
|
||||
Type *getParamByValType(unsigned ArgNo) const;
|
||||
|
||||
/// Return the sret type for the specified function parameter.
|
||||
Type *getParamStructRetType(unsigned ArgNo) const;
|
||||
|
||||
/// Return the byref type for the specified function parameter.
|
||||
Type *getParamByRefType(unsigned ArgNo) const;
|
||||
|
||||
@@ -737,6 +742,7 @@ class AttrBuilder {
|
||||
uint64_t DerefOrNullBytes = 0;
|
||||
uint64_t AllocSizeArgs = 0;
|
||||
Type *ByValType = nullptr;
|
||||
Type *StructRetType = nullptr;
|
||||
Type *ByRefType = nullptr;
|
||||
Type *PreallocatedType = nullptr;
|
||||
|
||||
@@ -824,6 +830,9 @@ public:
|
||||
/// Retrieve the byval type.
|
||||
Type *getByValType() const { return ByValType; }
|
||||
|
||||
/// Retrieve the sret type.
|
||||
Type *getStructRetType() const { return StructRetType; }
|
||||
|
||||
/// Retrieve the byref type.
|
||||
Type *getByRefType() const { return ByRefType; }
|
||||
|
||||
@@ -873,6 +882,9 @@ public:
|
||||
/// This turns a byval type into the form used internally in Attribute.
|
||||
AttrBuilder &addByValAttr(Type *Ty);
|
||||
|
||||
/// This turns a sret type into the form used internally in Attribute.
|
||||
AttrBuilder &addStructRetAttr(Type *Ty);
|
||||
|
||||
/// This turns a byref type into the form used internally in Attribute.
|
||||
AttrBuilder &addByRefAttr(Type *Ty);
|
||||
|
||||
|
||||
@@ -192,7 +192,7 @@ def StackProtectStrong : EnumAttr<"sspstrong">;
|
||||
def StrictFP : EnumAttr<"strictfp">;
|
||||
|
||||
/// Hidden pointer to structure to return.
|
||||
def StructRet : EnumAttr<"sret">;
|
||||
def StructRet : TypeAttr<"sret">;
|
||||
|
||||
/// AddressSanitizer is on.
|
||||
def SanitizeAddress : EnumAttr<"sanitize_address">;
|
||||
|
||||
@@ -474,8 +474,8 @@ public:
|
||||
|
||||
/// Extract the sret type for a parameter.
|
||||
Type *getParamStructRetType(unsigned ArgNo) const {
|
||||
// FIXME: Add type to attribute like byval
|
||||
return (arg_begin() + ArgNo)->getType()->getPointerElementType();
|
||||
Type *Ty = AttributeSets.getParamStructRetType(ArgNo);
|
||||
return Ty ? Ty : (arg_begin() + ArgNo)->getType()->getPointerElementType();
|
||||
}
|
||||
|
||||
/// Extract the byref type for a parameter.
|
||||
|
||||
@@ -1657,11 +1657,18 @@ bool LLParser::ParseOptionalParamAttrs(AttrBuilder &B) {
|
||||
}
|
||||
case lltok::kw_byval: {
|
||||
Type *Ty;
|
||||
if (ParseByValWithOptionalType(Ty))
|
||||
if (ParseOptionalTypeAttr(Ty, lltok::kw_byval))
|
||||
return true;
|
||||
B.addByValAttr(Ty);
|
||||
continue;
|
||||
}
|
||||
case lltok::kw_sret: {
|
||||
Type *Ty;
|
||||
if (ParseOptionalTypeAttr(Ty, lltok::kw_sret))
|
||||
return true;
|
||||
B.addStructRetAttr(Ty);
|
||||
continue;
|
||||
}
|
||||
case lltok::kw_preallocated: {
|
||||
Type *Ty;
|
||||
if (ParsePreallocated(Ty))
|
||||
@@ -1704,7 +1711,6 @@ bool LLParser::ParseOptionalParamAttrs(AttrBuilder &B) {
|
||||
case lltok::kw_readonly: B.addAttribute(Attribute::ReadOnly); break;
|
||||
case lltok::kw_returned: B.addAttribute(Attribute::Returned); break;
|
||||
case lltok::kw_signext: B.addAttribute(Attribute::SExt); break;
|
||||
case lltok::kw_sret: B.addAttribute(Attribute::StructRet); break;
|
||||
case lltok::kw_swifterror: B.addAttribute(Attribute::SwiftError); break;
|
||||
case lltok::kw_swiftself: B.addAttribute(Attribute::SwiftSelf); break;
|
||||
case lltok::kw_writeonly: B.addAttribute(Attribute::WriteOnly); break;
|
||||
@@ -2571,9 +2577,9 @@ bool LLParser::ParseParameterList(SmallVectorImpl<ParamInfo> &ArgList,
|
||||
/// ParseByValWithOptionalType
|
||||
/// ::= byval
|
||||
/// ::= byval(<ty>)
|
||||
bool LLParser::ParseByValWithOptionalType(Type *&Result) {
|
||||
bool LLParser::ParseOptionalTypeAttr(Type *&Result, lltok::Kind AttrName) {
|
||||
Result = nullptr;
|
||||
if (!EatIfPresent(lltok::kw_byval))
|
||||
if (!EatIfPresent(AttrName))
|
||||
return true;
|
||||
if (!EatIfPresent(lltok::lparen))
|
||||
return false;
|
||||
|
||||
@@ -332,8 +332,7 @@ namespace llvm {
|
||||
bool ParseFnAttributeValuePairs(AttrBuilder &B,
|
||||
std::vector<unsigned> &FwdRefAttrGrps,
|
||||
bool inAttrGrp, LocTy &BuiltinLoc);
|
||||
bool ParseByValWithOptionalType(Type *&Result);
|
||||
|
||||
bool ParseOptionalTypeAttr(Type *&Result, lltok::Kind AttrName);
|
||||
bool ParseRequiredTypeAttr(Type *&Result, lltok::Kind AttrName);
|
||||
bool ParsePreallocated(Type *&Result);
|
||||
bool ParseByRef(Type *&Result);
|
||||
|
||||
@@ -717,9 +717,9 @@ private:
|
||||
return getFnValueByID(ValNo, Ty);
|
||||
}
|
||||
|
||||
/// Upgrades old-style typeless byval attributes by adding the corresponding
|
||||
/// argument's pointee type.
|
||||
void propagateByValTypes(CallBase *CB, ArrayRef<Type *> ArgsFullTys);
|
||||
/// Upgrades old-style typeless byval or sret attributes by adding the
|
||||
/// corresponding argument's pointee type.
|
||||
void propagateByValSRetTypes(CallBase *CB, ArrayRef<Type *> ArgsFullTys);
|
||||
|
||||
/// Converts alignment exponent (i.e. power of two (or zero)) to the
|
||||
/// corresponding alignment to use. If alignment is too large, returns
|
||||
@@ -1611,6 +1611,8 @@ Error BitcodeReader::parseAttributeGroupBlock() {
|
||||
// this AttributeList with a function.
|
||||
if (Kind == Attribute::ByVal)
|
||||
B.addByValAttr(nullptr);
|
||||
else if (Kind == Attribute::StructRet)
|
||||
B.addStructRetAttr(nullptr);
|
||||
|
||||
B.addAttribute(Kind);
|
||||
} else if (Record[i] == 1) { // Integer attribute
|
||||
@@ -1654,6 +1656,8 @@ Error BitcodeReader::parseAttributeGroupBlock() {
|
||||
return Err;
|
||||
if (Kind == Attribute::ByVal) {
|
||||
B.addByValAttr(HasType ? getTypeByID(Record[++i]) : nullptr);
|
||||
} else if (Kind == Attribute::StructRet) {
|
||||
B.addStructRetAttr(HasType ? getTypeByID(Record[++i]) : nullptr);
|
||||
} else if (Kind == Attribute::ByRef) {
|
||||
B.addByRefAttr(getTypeByID(Record[++i]));
|
||||
} else if (Kind == Attribute::Preallocated) {
|
||||
@@ -3288,17 +3292,24 @@ Error BitcodeReader::parseFunctionRecord(ArrayRef<uint64_t> Record) {
|
||||
Func->setLinkage(getDecodedLinkage(RawLinkage));
|
||||
Func->setAttributes(getAttributes(Record[4]));
|
||||
|
||||
// Upgrade any old-style byval without a type by propagating the argument's
|
||||
// pointee type. There should be no opaque pointers where the byval type is
|
||||
// implicit.
|
||||
// Upgrade any old-style byval or sret without a type by propagating the
|
||||
// argument's pointee type. There should be no opaque pointers where the byval
|
||||
// type is implicit.
|
||||
for (unsigned i = 0; i != Func->arg_size(); ++i) {
|
||||
if (!Func->hasParamAttribute(i, Attribute::ByVal))
|
||||
continue;
|
||||
for (Attribute::AttrKind Kind : {Attribute::ByVal, Attribute::StructRet}) {
|
||||
if (!Func->hasParamAttribute(i, Kind))
|
||||
continue;
|
||||
|
||||
Type *PTy = cast<FunctionType>(FullFTy)->getParamType(i);
|
||||
Func->removeParamAttr(i, Attribute::ByVal);
|
||||
Func->addParamAttr(i, Attribute::getWithByValType(
|
||||
Context, getPointerElementFlatType(PTy)));
|
||||
Func->removeParamAttr(i, Kind);
|
||||
|
||||
Type *PTy = cast<FunctionType>(FullFTy)->getParamType(i);
|
||||
Type *PtrEltTy = getPointerElementFlatType(PTy);
|
||||
Attribute NewAttr =
|
||||
Kind == Attribute::ByVal
|
||||
? Attribute::getWithByValType(Context, PtrEltTy)
|
||||
: Attribute::getWithStructRetType(Context, PtrEltTy);
|
||||
Func->addParamAttr(i, NewAttr);
|
||||
}
|
||||
}
|
||||
|
||||
MaybeAlign Alignment;
|
||||
@@ -3759,16 +3770,22 @@ Error BitcodeReader::typeCheckLoadStoreInst(Type *ValType, Type *PtrType) {
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
void BitcodeReader::propagateByValTypes(CallBase *CB,
|
||||
ArrayRef<Type *> ArgsFullTys) {
|
||||
void BitcodeReader::propagateByValSRetTypes(CallBase *CB,
|
||||
ArrayRef<Type *> ArgsFullTys) {
|
||||
for (unsigned i = 0; i != CB->arg_size(); ++i) {
|
||||
if (!CB->paramHasAttr(i, Attribute::ByVal))
|
||||
continue;
|
||||
for (Attribute::AttrKind Kind : {Attribute::ByVal, Attribute::StructRet}) {
|
||||
if (!CB->paramHasAttr(i, Kind))
|
||||
continue;
|
||||
|
||||
CB->removeParamAttr(i, Attribute::ByVal);
|
||||
CB->addParamAttr(
|
||||
i, Attribute::getWithByValType(
|
||||
Context, getPointerElementFlatType(ArgsFullTys[i])));
|
||||
CB->removeParamAttr(i, Kind);
|
||||
|
||||
Type *PtrEltTy = getPointerElementFlatType(ArgsFullTys[i]);
|
||||
Attribute NewAttr =
|
||||
Kind == Attribute::ByVal
|
||||
? Attribute::getWithByValType(Context, PtrEltTy)
|
||||
: Attribute::getWithStructRetType(Context, PtrEltTy);
|
||||
CB->addParamAttr(i, NewAttr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4620,7 +4637,7 @@ Error BitcodeReader::parseFunctionBody(Function *F) {
|
||||
cast<InvokeInst>(I)->setCallingConv(
|
||||
static_cast<CallingConv::ID>(CallingConv::MaxID & CCInfo));
|
||||
cast<InvokeInst>(I)->setAttributes(PAL);
|
||||
propagateByValTypes(cast<CallBase>(I), ArgsFullTys);
|
||||
propagateByValSRetTypes(cast<CallBase>(I), ArgsFullTys);
|
||||
|
||||
break;
|
||||
}
|
||||
@@ -5227,7 +5244,7 @@ Error BitcodeReader::parseFunctionBody(Function *F) {
|
||||
TCK = CallInst::TCK_NoTail;
|
||||
cast<CallInst>(I)->setTailCallKind(TCK);
|
||||
cast<CallInst>(I)->setAttributes(PAL);
|
||||
propagateByValTypes(cast<CallBase>(I), ArgsFullTys);
|
||||
propagateByValSRetTypes(cast<CallBase>(I), ArgsFullTys);
|
||||
if (FMF.any()) {
|
||||
if (!isa<FPMathOperator>(I))
|
||||
return error("Fast-math-flags specified for call without "
|
||||
|
||||
@@ -4288,12 +4288,15 @@ void AssemblyWriter::writeAttribute(const Attribute &Attr, bool InAttrGroup) {
|
||||
}
|
||||
|
||||
assert((Attr.hasAttribute(Attribute::ByVal) ||
|
||||
Attr.hasAttribute(Attribute::StructRet) ||
|
||||
Attr.hasAttribute(Attribute::ByRef) ||
|
||||
Attr.hasAttribute(Attribute::Preallocated)) &&
|
||||
"unexpected type attr");
|
||||
|
||||
if (Attr.hasAttribute(Attribute::ByVal)) {
|
||||
Out << "byval";
|
||||
} else if (Attr.hasAttribute(Attribute::StructRet)) {
|
||||
Out << "sret";
|
||||
} else if (Attr.hasAttribute(Attribute::ByRef)) {
|
||||
Out << "byref";
|
||||
} else {
|
||||
|
||||
@@ -254,6 +254,7 @@ public:
|
||||
std::pair<unsigned, Optional<unsigned>> getAllocSizeArgs() const;
|
||||
std::string getAsString(bool InAttrGrp) const;
|
||||
Type *getByValType() const;
|
||||
Type *getStructRetType() const;
|
||||
Type *getByRefType() const;
|
||||
Type *getPreallocatedType() const;
|
||||
|
||||
|
||||
+44
-6
@@ -172,6 +172,10 @@ Attribute Attribute::getWithByValType(LLVMContext &Context, Type *Ty) {
|
||||
return get(Context, ByVal, Ty);
|
||||
}
|
||||
|
||||
Attribute Attribute::getWithStructRetType(LLVMContext &Context, Type *Ty) {
|
||||
return get(Context, StructRet, Ty);
|
||||
}
|
||||
|
||||
Attribute Attribute::getWithByRefType(LLVMContext &Context, Type *Ty) {
|
||||
return get(Context, ByRef, Ty);
|
||||
}
|
||||
@@ -433,8 +437,6 @@ std::string Attribute::getAsString(bool InAttrGrp) const {
|
||||
return "shadowcallstack";
|
||||
if (hasAttribute(Attribute::StrictFP))
|
||||
return "strictfp";
|
||||
if (hasAttribute(Attribute::StructRet))
|
||||
return "sret";
|
||||
if (hasAttribute(Attribute::SanitizeThread))
|
||||
return "sanitize_thread";
|
||||
if (hasAttribute(Attribute::SanitizeMemory))
|
||||
@@ -450,9 +452,10 @@ std::string Attribute::getAsString(bool InAttrGrp) const {
|
||||
if (hasAttribute(Attribute::NoUndef))
|
||||
return "noundef";
|
||||
|
||||
if (hasAttribute(Attribute::ByVal)) {
|
||||
const bool IsByVal = hasAttribute(Attribute::ByVal);
|
||||
if (IsByVal || hasAttribute(Attribute::StructRet)) {
|
||||
std::string Result;
|
||||
Result += "byval";
|
||||
Result += IsByVal ? "byval" : "sret";
|
||||
if (Type *Ty = getValueAsType()) {
|
||||
raw_string_ostream OS(Result);
|
||||
Result += '(';
|
||||
@@ -754,6 +757,10 @@ Type *AttributeSet::getByValType() const {
|
||||
return SetNode ? SetNode->getByValType() : nullptr;
|
||||
}
|
||||
|
||||
Type *AttributeSet::getStructRetType() const {
|
||||
return SetNode ? SetNode->getStructRetType() : nullptr;
|
||||
}
|
||||
|
||||
Type *AttributeSet::getPreallocatedType() const {
|
||||
return SetNode ? SetNode->getPreallocatedType() : nullptr;
|
||||
}
|
||||
@@ -850,6 +857,9 @@ AttributeSetNode *AttributeSetNode::get(LLVMContext &C, const AttrBuilder &B) {
|
||||
case Attribute::ByVal:
|
||||
Attr = Attribute::getWithByValType(C, B.getByValType());
|
||||
break;
|
||||
case Attribute::StructRet:
|
||||
Attr = Attribute::getWithStructRetType(C, B.getStructRetType());
|
||||
break;
|
||||
case Attribute::ByRef:
|
||||
Attr = Attribute::getWithByRefType(C, B.getByRefType());
|
||||
break;
|
||||
@@ -939,6 +949,12 @@ Type *AttributeSetNode::getByValType() const {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
Type *AttributeSetNode::getStructRetType() const {
|
||||
if (auto A = findEnumAttribute(Attribute::StructRet))
|
||||
return A->getValueAsType();
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
Type *AttributeSetNode::getByRefType() const {
|
||||
if (auto A = findEnumAttribute(Attribute::ByRef))
|
||||
return A->getValueAsType();
|
||||
@@ -1466,6 +1482,10 @@ Type *AttributeList::getParamByValType(unsigned Index) const {
|
||||
return getAttributes(Index+FirstArgIndex).getByValType();
|
||||
}
|
||||
|
||||
Type *AttributeList::getParamStructRetType(unsigned Index) const {
|
||||
return getAttributes(Index + FirstArgIndex).getStructRetType();
|
||||
}
|
||||
|
||||
Type *AttributeList::getParamByRefType(unsigned Index) const {
|
||||
return getAttributes(Index + FirstArgIndex).getByRefType();
|
||||
}
|
||||
@@ -1555,6 +1575,7 @@ void AttrBuilder::clear() {
|
||||
DerefBytes = DerefOrNullBytes = 0;
|
||||
AllocSizeArgs = 0;
|
||||
ByValType = nullptr;
|
||||
StructRetType = nullptr;
|
||||
ByRefType = nullptr;
|
||||
PreallocatedType = nullptr;
|
||||
}
|
||||
@@ -1574,6 +1595,8 @@ AttrBuilder &AttrBuilder::addAttribute(Attribute Attr) {
|
||||
StackAlignment = Attr.getStackAlignment();
|
||||
else if (Kind == Attribute::ByVal)
|
||||
ByValType = Attr.getValueAsType();
|
||||
else if (Kind == Attribute::StructRet)
|
||||
StructRetType = Attr.getValueAsType();
|
||||
else if (Kind == Attribute::ByRef)
|
||||
ByRefType = Attr.getValueAsType();
|
||||
else if (Kind == Attribute::Preallocated)
|
||||
@@ -1602,6 +1625,8 @@ AttrBuilder &AttrBuilder::removeAttribute(Attribute::AttrKind Val) {
|
||||
StackAlignment.reset();
|
||||
else if (Val == Attribute::ByVal)
|
||||
ByValType = nullptr;
|
||||
else if (Val == Attribute::StructRet)
|
||||
StructRetType = nullptr;
|
||||
else if (Val == Attribute::ByRef)
|
||||
ByRefType = nullptr;
|
||||
else if (Val == Attribute::Preallocated)
|
||||
@@ -1694,6 +1719,12 @@ AttrBuilder &AttrBuilder::addByValAttr(Type *Ty) {
|
||||
return *this;
|
||||
}
|
||||
|
||||
AttrBuilder &AttrBuilder::addStructRetAttr(Type *Ty) {
|
||||
Attrs[Attribute::StructRet] = true;
|
||||
StructRetType = Ty;
|
||||
return *this;
|
||||
}
|
||||
|
||||
AttrBuilder &AttrBuilder::addByRefAttr(Type *Ty) {
|
||||
Attrs[Attribute::ByRef] = true;
|
||||
ByRefType = Ty;
|
||||
@@ -1726,6 +1757,9 @@ AttrBuilder &AttrBuilder::merge(const AttrBuilder &B) {
|
||||
if (!ByValType)
|
||||
ByValType = B.ByValType;
|
||||
|
||||
if (!StructRetType)
|
||||
StructRetType = B.StructRetType;
|
||||
|
||||
if (!ByRefType)
|
||||
ByRefType = B.ByRefType;
|
||||
|
||||
@@ -1760,6 +1794,9 @@ AttrBuilder &AttrBuilder::remove(const AttrBuilder &B) {
|
||||
if (B.ByValType)
|
||||
ByValType = nullptr;
|
||||
|
||||
if (B.StructRetType)
|
||||
StructRetType = nullptr;
|
||||
|
||||
if (B.ByRefType)
|
||||
ByRefType = nullptr;
|
||||
|
||||
@@ -1826,7 +1863,8 @@ bool AttrBuilder::operator==(const AttrBuilder &B) {
|
||||
|
||||
return Alignment == B.Alignment && StackAlignment == B.StackAlignment &&
|
||||
DerefBytes == B.DerefBytes && ByValType == B.ByValType &&
|
||||
ByRefType == B.ByRefType && PreallocatedType == B.PreallocatedType;
|
||||
StructRetType == B.StructRetType && ByRefType == B.ByRefType &&
|
||||
PreallocatedType == B.PreallocatedType;
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
@@ -1852,10 +1890,10 @@ AttrBuilder AttributeFuncs::typeIncompatible(Type *Ty) {
|
||||
.addDereferenceableOrNullAttr(1) // the int here is ignored
|
||||
.addAttribute(Attribute::ReadNone)
|
||||
.addAttribute(Attribute::ReadOnly)
|
||||
.addAttribute(Attribute::StructRet)
|
||||
.addAttribute(Attribute::InAlloca)
|
||||
.addPreallocatedAttr(Ty)
|
||||
.addByValAttr(Ty)
|
||||
.addStructRetAttr(Ty)
|
||||
.addByRefAttr(Ty);
|
||||
|
||||
return Incompatible;
|
||||
|
||||
@@ -0,0 +1,43 @@
|
||||
; RUN: llvm-as < %s | llvm-dis | llvm-as | llvm-dis | FileCheck %s
|
||||
|
||||
; CHECK: define void @foo(i32* sret(i32) align 4 %0)
|
||||
define void @foo(i32* sret(i32) align 4 %0) {
|
||||
ret void
|
||||
}
|
||||
|
||||
; CHECK: define void @bar({ i32*, i8 }* sret({ i32*, i8 }) align 4 %0)
|
||||
define void @bar({i32*, i8}* sret({i32*, i8}) align 4 %0) {
|
||||
ret void
|
||||
}
|
||||
|
||||
define void @caller({ i32*, i8 }* %ptr) personality i8* bitcast (i32 (...)* @__gxx_personality_v0 to i8*) {
|
||||
; CHECK: call void @bar({ i32*, i8 }* sret({ i32*, i8 }) %ptr)
|
||||
; CHECK: invoke void @bar({ i32*, i8 }* sret({ i32*, i8 }) %ptr)
|
||||
call void @bar({i32*, i8}* sret %ptr)
|
||||
invoke void @bar({i32*, i8}* sret %ptr) to label %success unwind label %fail
|
||||
|
||||
success:
|
||||
ret void
|
||||
|
||||
fail:
|
||||
landingpad { i8*, i32 } cleanup
|
||||
ret void
|
||||
}
|
||||
|
||||
; CHECK: declare void @baz([8 x i8]* sret([8 x i8]))
|
||||
%named_type = type [8 x i8]
|
||||
declare void @baz(%named_type* sret(%named_type))
|
||||
|
||||
declare i32 @__gxx_personality_v0(...)
|
||||
|
||||
%0 = type opaque
|
||||
|
||||
; CHECK: define void @anon({ %0* }* sret({ %0* }) %arg)
|
||||
; CHECK: call void @anon_callee({ %0* }* sret({ %0* }) %arg)
|
||||
define void @anon({ %0* }* sret({ %0* }) %arg) {
|
||||
call void @anon_callee({ %0* }* sret({ %0* }) %arg)
|
||||
ret void
|
||||
}
|
||||
|
||||
; CHECK: declare void @anon_callee({ %0* }* sret({ %0* }))
|
||||
declare void @anon_callee({ %0* }* sret({ %0* }))
|
||||
@@ -30,7 +30,7 @@ define void @f4(i8 inreg %0)
|
||||
}
|
||||
|
||||
define void @f5(i8* sret %0)
|
||||
; CHECK: define void @f5(i8* sret %0)
|
||||
; CHECK: define void @f5(i8* sret(i8) %0)
|
||||
{
|
||||
ret void;
|
||||
}
|
||||
|
||||
@@ -27,7 +27,7 @@ define void @f4(i8 inreg %0)
|
||||
}
|
||||
|
||||
define void @f5(i8* sret %0)
|
||||
; CHECK: define void @f5(i8* sret %0)
|
||||
; CHECK: define void @f5(i8* sret(i8) %0)
|
||||
{
|
||||
ret void;
|
||||
}
|
||||
|
||||
@@ -408,7 +408,7 @@ declare void @f.param.byval({ i8, i8 }* byval)
|
||||
declare void @f.param.inalloca(i8* inalloca)
|
||||
; CHECK: declare void @f.param.inalloca(i8* inalloca)
|
||||
declare void @f.param.sret(i8* sret)
|
||||
; CHECK: declare void @f.param.sret(i8* sret)
|
||||
; CHECK: declare void @f.param.sret(i8* sret(i8))
|
||||
declare void @f.param.noalias(i8* noalias)
|
||||
; CHECK: declare void @f.param.noalias(i8* noalias)
|
||||
declare void @f.param.nocapture(i8* nocapture)
|
||||
|
||||
@@ -414,7 +414,7 @@ declare void @f.param.byval({ i8, i8 }* byval)
|
||||
declare void @f.param.inalloca(i8* inalloca)
|
||||
; CHECK: declare void @f.param.inalloca(i8* inalloca)
|
||||
declare void @f.param.sret(i8* sret)
|
||||
; CHECK: declare void @f.param.sret(i8* sret)
|
||||
; CHECK: declare void @f.param.sret(i8* sret(i8))
|
||||
declare void @f.param.noalias(i8* noalias)
|
||||
; CHECK: declare void @f.param.noalias(i8* noalias)
|
||||
declare void @f.param.nocapture(i8* nocapture)
|
||||
|
||||
@@ -439,7 +439,7 @@ declare void @f.param.byval({ i8, i8 }* byval)
|
||||
declare void @f.param.inalloca(i8* inalloca)
|
||||
; CHECK: declare void @f.param.inalloca(i8* inalloca)
|
||||
declare void @f.param.sret(i8* sret)
|
||||
; CHECK: declare void @f.param.sret(i8* sret)
|
||||
; CHECK: declare void @f.param.sret(i8* sret(i8))
|
||||
declare void @f.param.noalias(i8* noalias)
|
||||
; CHECK: declare void @f.param.noalias(i8* noalias)
|
||||
declare void @f.param.nocapture(i8* nocapture)
|
||||
|
||||
@@ -508,7 +508,7 @@ declare void @f.param.byval({ i8, i8 }* byval)
|
||||
declare void @f.param.inalloca(i8* inalloca)
|
||||
; CHECK: declare void @f.param.inalloca(i8* inalloca)
|
||||
declare void @f.param.sret(i8* sret)
|
||||
; CHECK: declare void @f.param.sret(i8* sret)
|
||||
; CHECK: declare void @f.param.sret(i8* sret(i8))
|
||||
declare void @f.param.noalias(i8* noalias)
|
||||
; CHECK: declare void @f.param.noalias(i8* noalias)
|
||||
declare void @f.param.nocapture(i8* nocapture)
|
||||
|
||||
@@ -508,7 +508,7 @@ declare void @f.param.byval({ i8, i8 }* byval)
|
||||
declare void @f.param.inalloca(i8* inalloca)
|
||||
; CHECK: declare void @f.param.inalloca(i8* inalloca)
|
||||
declare void @f.param.sret(i8* sret)
|
||||
; CHECK: declare void @f.param.sret(i8* sret)
|
||||
; CHECK: declare void @f.param.sret(i8* sret(i8))
|
||||
declare void @f.param.noalias(i8* noalias)
|
||||
; CHECK: declare void @f.param.noalias(i8* noalias)
|
||||
declare void @f.param.nocapture(i8* nocapture)
|
||||
|
||||
@@ -512,7 +512,7 @@ declare void @f.param.byval({ i8, i8 }* byval)
|
||||
declare void @f.param.inalloca(i8* inalloca)
|
||||
; CHECK: declare void @f.param.inalloca(i8* inalloca)
|
||||
declare void @f.param.sret(i8* sret)
|
||||
; CHECK: declare void @f.param.sret(i8* sret)
|
||||
; CHECK: declare void @f.param.sret(i8* sret(i8))
|
||||
declare void @f.param.noalias(i8* noalias)
|
||||
; CHECK: declare void @f.param.noalias(i8* noalias)
|
||||
declare void @f.param.nocapture(i8* nocapture)
|
||||
|
||||
@@ -519,7 +519,7 @@ declare void @f.param.byval({ i8, i8 }* byval)
|
||||
declare void @f.param.inalloca(i8* inalloca)
|
||||
; CHECK: declare void @f.param.inalloca(i8* inalloca)
|
||||
declare void @f.param.sret(i8* sret)
|
||||
; CHECK: declare void @f.param.sret(i8* sret)
|
||||
; CHECK: declare void @f.param.sret(i8* sret(i8))
|
||||
declare void @f.param.noalias(i8* noalias)
|
||||
; CHECK: declare void @f.param.noalias(i8* noalias)
|
||||
declare void @f.param.nocapture(i8* nocapture)
|
||||
|
||||
@@ -533,7 +533,7 @@ declare void @f.param.byval({ i8, i8 }* byval)
|
||||
declare void @f.param.inalloca(i8* inalloca)
|
||||
; CHECK: declare void @f.param.inalloca(i8* inalloca)
|
||||
declare void @f.param.sret(i8* sret)
|
||||
; CHECK: declare void @f.param.sret(i8* sret)
|
||||
; CHECK: declare void @f.param.sret(i8* sret(i8))
|
||||
declare void @f.param.noalias(i8* noalias)
|
||||
; CHECK: declare void @f.param.noalias(i8* noalias)
|
||||
declare void @f.param.nocapture(i8* nocapture)
|
||||
|
||||
@@ -35,7 +35,7 @@ module asm "some assembly"
|
||||
declare void @ParamAttr1(i8 zeroext)
|
||||
; CHECK: declare void @ParamAttr2(i8* nest)
|
||||
declare void @ParamAttr2(i8* nest)
|
||||
; CHECK: declare void @ParamAttr3(i8* sret)
|
||||
; CHECK: declare void @ParamAttr3(i8* sret(i8))
|
||||
declare void @ParamAttr3(i8* sret)
|
||||
; CHECK: declare void @ParamAttr4(i8 signext)
|
||||
declare void @ParamAttr4(i8 signext)
|
||||
|
||||
@@ -7,11 +7,11 @@
|
||||
target datalayout = "e-m:w-i64:64-f80:128-n8:16:32:64-S128"
|
||||
target triple = "x86_64-pc-windows-msvc"
|
||||
|
||||
define internal void @add({i32, i32}* %this, i32* sret %r) {
|
||||
define internal void @add({i32, i32}* %this, i32* sret(i32) %r) {
|
||||
;
|
||||
; IS__TUNIT_OPM: Function Attrs: argmemonly nofree nosync nounwind willreturn
|
||||
; IS__TUNIT_OPM-LABEL: define {{[^@]+}}@add
|
||||
; IS__TUNIT_OPM-SAME: ({ i32, i32 }* nocapture nofree noundef nonnull readonly align 8 dereferenceable(8) [[THIS:%.*]], i32* nocapture nofree noundef nonnull sret writeonly align 4 dereferenceable(4) [[R:%.*]]) [[ATTR0:#.*]] {
|
||||
; IS__TUNIT_OPM-SAME: ({ i32, i32 }* nocapture nofree noundef nonnull readonly align 8 dereferenceable(8) [[THIS:%.*]], i32* nocapture nofree noundef nonnull writeonly sret(i32) align 4 dereferenceable(4) [[R:%.*]]) [[ATTR0:#.*]] {
|
||||
; IS__TUNIT_OPM-NEXT: [[AP:%.*]] = getelementptr { i32, i32 }, { i32, i32 }* [[THIS]], i32 0, i32 0
|
||||
; IS__TUNIT_OPM-NEXT: [[BP:%.*]] = getelementptr { i32, i32 }, { i32, i32 }* [[THIS]], i32 0, i32 1
|
||||
; IS__TUNIT_OPM-NEXT: [[A:%.*]] = load i32, i32* [[AP]], align 8
|
||||
@@ -22,7 +22,7 @@ define internal void @add({i32, i32}* %this, i32* sret %r) {
|
||||
;
|
||||
; IS__TUNIT_NPM: Function Attrs: argmemonly nofree nosync nounwind willreturn
|
||||
; IS__TUNIT_NPM-LABEL: define {{[^@]+}}@add
|
||||
; IS__TUNIT_NPM-SAME: ({ i32, i32 }* noalias nocapture nofree noundef nonnull readonly align 8 dereferenceable(8) [[THIS:%.*]], i32* noalias nocapture nofree noundef nonnull sret writeonly align 4 dereferenceable(4) [[R:%.*]]) [[ATTR0:#.*]] {
|
||||
; IS__TUNIT_NPM-SAME: ({ i32, i32 }* noalias nocapture nofree noundef nonnull readonly align 8 dereferenceable(8) [[THIS:%.*]], i32* noalias nocapture nofree noundef nonnull writeonly sret(i32) align 4 dereferenceable(4) [[R:%.*]]) [[ATTR0:#.*]] {
|
||||
; IS__TUNIT_NPM-NEXT: [[AP:%.*]] = getelementptr { i32, i32 }, { i32, i32 }* [[THIS]], i32 0, i32 0
|
||||
; IS__TUNIT_NPM-NEXT: [[BP:%.*]] = getelementptr { i32, i32 }, { i32, i32 }* [[THIS]], i32 0, i32 1
|
||||
; IS__TUNIT_NPM-NEXT: [[A:%.*]] = load i32, i32* [[AP]], align 8
|
||||
@@ -33,7 +33,7 @@ define internal void @add({i32, i32}* %this, i32* sret %r) {
|
||||
;
|
||||
; IS__CGSCC_OPM: Function Attrs: argmemonly nofree norecurse nosync nounwind willreturn
|
||||
; IS__CGSCC_OPM-LABEL: define {{[^@]+}}@add
|
||||
; IS__CGSCC_OPM-SAME: ({ i32, i32 }* nocapture nofree noundef nonnull readonly align 8 dereferenceable(8) [[THIS:%.*]], i32* nocapture nofree noundef nonnull sret writeonly align 4 dereferenceable(4) [[R:%.*]]) [[ATTR0:#.*]] {
|
||||
; IS__CGSCC_OPM-SAME: ({ i32, i32 }* nocapture nofree noundef nonnull readonly align 8 dereferenceable(8) [[THIS:%.*]], i32* nocapture nofree noundef nonnull writeonly sret(i32) align 4 dereferenceable(4) [[R:%.*]]) [[ATTR0:#.*]] {
|
||||
; IS__CGSCC_OPM-NEXT: [[AP:%.*]] = getelementptr { i32, i32 }, { i32, i32 }* [[THIS]], i32 0, i32 0
|
||||
; IS__CGSCC_OPM-NEXT: [[BP:%.*]] = getelementptr { i32, i32 }, { i32, i32 }* [[THIS]], i32 0, i32 1
|
||||
; IS__CGSCC_OPM-NEXT: [[A:%.*]] = load i32, i32* [[AP]], align 8
|
||||
@@ -44,7 +44,7 @@ define internal void @add({i32, i32}* %this, i32* sret %r) {
|
||||
;
|
||||
; IS__CGSCC_NPM: Function Attrs: argmemonly nofree norecurse nosync nounwind willreturn
|
||||
; IS__CGSCC_NPM-LABEL: define {{[^@]+}}@add
|
||||
; IS__CGSCC_NPM-SAME: ({ i32, i32 }* noalias nocapture nofree noundef nonnull readonly align 8 dereferenceable(8) [[THIS:%.*]], i32* noalias nocapture nofree noundef nonnull sret writeonly align 4 dereferenceable(4) [[R:%.*]]) [[ATTR0:#.*]] {
|
||||
; IS__CGSCC_NPM-SAME: ({ i32, i32 }* noalias nocapture nofree noundef nonnull readonly align 8 dereferenceable(8) [[THIS:%.*]], i32* noalias nocapture nofree noundef nonnull writeonly sret(i32) align 4 dereferenceable(4) [[R:%.*]]) [[ATTR0:#.*]] {
|
||||
; IS__CGSCC_NPM-NEXT: [[AP:%.*]] = getelementptr { i32, i32 }, { i32, i32 }* [[THIS]], i32 0, i32 0
|
||||
; IS__CGSCC_NPM-NEXT: [[BP:%.*]] = getelementptr { i32, i32 }, { i32, i32 }* [[THIS]], i32 0, i32 1
|
||||
; IS__CGSCC_NPM-NEXT: [[A:%.*]] = load i32, i32* [[AP]], align 8
|
||||
@@ -68,7 +68,7 @@ define void @f() {
|
||||
; IS__TUNIT_OPM-SAME: () [[ATTR1:#.*]] {
|
||||
; IS__TUNIT_OPM-NEXT: [[R:%.*]] = alloca i32, align 4
|
||||
; IS__TUNIT_OPM-NEXT: [[PAIR:%.*]] = alloca { i32, i32 }, align 8
|
||||
; IS__TUNIT_OPM-NEXT: call void @add({ i32, i32 }* nocapture nofree noundef nonnull readonly align 8 dereferenceable(8) [[PAIR]], i32* nocapture nofree noundef nonnull sret writeonly align 4 dereferenceable(4) [[R]]) [[ATTR2:#.*]]
|
||||
; IS__TUNIT_OPM-NEXT: call void @add({ i32, i32 }* nocapture nofree noundef nonnull readonly align 8 dereferenceable(8) [[PAIR]], i32* nocapture nofree noundef nonnull writeonly sret(i32) align 4 dereferenceable(4) [[R]]) [[ATTR2:#.*]]
|
||||
; IS__TUNIT_OPM-NEXT: ret void
|
||||
;
|
||||
; IS__TUNIT_NPM: Function Attrs: nofree nosync nounwind readnone willreturn
|
||||
@@ -76,7 +76,7 @@ define void @f() {
|
||||
; IS__TUNIT_NPM-SAME: () [[ATTR1:#.*]] {
|
||||
; IS__TUNIT_NPM-NEXT: [[R:%.*]] = alloca i32, align 4
|
||||
; IS__TUNIT_NPM-NEXT: [[PAIR:%.*]] = alloca { i32, i32 }, align 8
|
||||
; IS__TUNIT_NPM-NEXT: call void @add({ i32, i32 }* noalias nocapture nofree noundef nonnull readonly align 8 dereferenceable(8) [[PAIR]], i32* noalias nocapture nofree noundef nonnull sret writeonly align 4 dereferenceable(4) [[R]]) [[ATTR2:#.*]]
|
||||
; IS__TUNIT_NPM-NEXT: call void @add({ i32, i32 }* noalias nocapture nofree noundef nonnull readonly align 8 dereferenceable(8) [[PAIR]], i32* noalias nocapture nofree noundef nonnull writeonly sret(i32) align 4 dereferenceable(4) [[R]]) [[ATTR2:#.*]]
|
||||
; IS__TUNIT_NPM-NEXT: ret void
|
||||
;
|
||||
; IS__CGSCC_OPM: Function Attrs: nofree norecurse nosync nounwind readnone willreturn
|
||||
@@ -84,7 +84,7 @@ define void @f() {
|
||||
; IS__CGSCC_OPM-SAME: () [[ATTR1:#.*]] {
|
||||
; IS__CGSCC_OPM-NEXT: [[R:%.*]] = alloca i32, align 4
|
||||
; IS__CGSCC_OPM-NEXT: [[PAIR:%.*]] = alloca { i32, i32 }, align 8
|
||||
; IS__CGSCC_OPM-NEXT: call void @add({ i32, i32 }* nocapture nofree noundef nonnull readonly align 8 dereferenceable(8) [[PAIR]], i32* nocapture nofree noundef nonnull sret writeonly align 4 dereferenceable(4) [[R]]) [[ATTR2:#.*]]
|
||||
; IS__CGSCC_OPM-NEXT: call void @add({ i32, i32 }* nocapture nofree noundef nonnull readonly align 8 dereferenceable(8) [[PAIR]], i32* nocapture nofree noundef nonnull writeonly sret(i32) align 4 dereferenceable(4) [[R]]) [[ATTR2:#.*]]
|
||||
; IS__CGSCC_OPM-NEXT: ret void
|
||||
;
|
||||
; IS__CGSCC_NPM: Function Attrs: nofree norecurse nosync nounwind readnone willreturn
|
||||
@@ -92,12 +92,12 @@ define void @f() {
|
||||
; IS__CGSCC_NPM-SAME: () [[ATTR1:#.*]] {
|
||||
; IS__CGSCC_NPM-NEXT: [[R:%.*]] = alloca i32, align 4
|
||||
; IS__CGSCC_NPM-NEXT: [[PAIR:%.*]] = alloca { i32, i32 }, align 8
|
||||
; IS__CGSCC_NPM-NEXT: call void @add({ i32, i32 }* noalias nocapture nofree noundef nonnull readonly align 8 dereferenceable(8) [[PAIR]], i32* noalias nocapture nofree noundef nonnull sret writeonly align 4 dereferenceable(4) [[R]]) [[ATTR2:#.*]]
|
||||
; IS__CGSCC_NPM-NEXT: call void @add({ i32, i32 }* noalias nocapture nofree noundef nonnull readonly align 8 dereferenceable(8) [[PAIR]], i32* noalias nocapture nofree noundef nonnull writeonly sret(i32) align 4 dereferenceable(4) [[R]]) [[ATTR2:#.*]]
|
||||
; IS__CGSCC_NPM-NEXT: ret void
|
||||
;
|
||||
%r = alloca i32
|
||||
%pair = alloca {i32, i32}
|
||||
|
||||
call void @add({i32, i32}* %pair, i32* sret %r)
|
||||
call void @add({i32, i32}* %pair, i32* sret(i32) %r)
|
||||
ret void
|
||||
}
|
||||
|
||||
@@ -412,17 +412,17 @@ define i32* @complicated_args_preallocated() {
|
||||
ret i32* %call
|
||||
}
|
||||
|
||||
define internal void @test_sret(%struct.X* sret %a, %struct.X** %b) {
|
||||
define internal void @test_sret(%struct.X* sret(%struct.X) %a, %struct.X** %b) {
|
||||
;
|
||||
; IS__TUNIT____: Function Attrs: argmemonly nofree nosync nounwind willreturn writeonly
|
||||
; IS__TUNIT____-LABEL: define {{[^@]+}}@test_sret
|
||||
; IS__TUNIT____-SAME: (%struct.X* noalias nofree noundef nonnull sret writeonly align 536870912 dereferenceable(8) [[A:%.*]], %struct.X** nocapture nofree nonnull writeonly align 8 dereferenceable(8) [[B:%.*]]) [[ATTR2:#.*]] {
|
||||
; IS__TUNIT____-SAME: (%struct.X* noalias nofree noundef nonnull writeonly sret(%struct.X) align 536870912 dereferenceable(8) [[A:%.*]], %struct.X** nocapture nofree nonnull writeonly align 8 dereferenceable(8) [[B:%.*]]) [[ATTR2:#.*]] {
|
||||
; IS__TUNIT____-NEXT: store %struct.X* [[A]], %struct.X** [[B]], align 8
|
||||
; IS__TUNIT____-NEXT: ret void
|
||||
;
|
||||
; IS__CGSCC____: Function Attrs: argmemonly nofree norecurse nosync nounwind willreturn writeonly
|
||||
; IS__CGSCC____-LABEL: define {{[^@]+}}@test_sret
|
||||
; IS__CGSCC____-SAME: (%struct.X* noalias nofree noundef nonnull sret writeonly align 536870912 dereferenceable(8) [[A:%.*]], %struct.X** nocapture nofree nonnull writeonly align 8 dereferenceable(8) [[B:%.*]]) [[ATTR2:#.*]] {
|
||||
; IS__CGSCC____-SAME: (%struct.X* noalias nofree noundef nonnull writeonly sret(%struct.X) align 536870912 dereferenceable(8) [[A:%.*]], %struct.X** nocapture nofree nonnull writeonly align 8 dereferenceable(8) [[B:%.*]]) [[ATTR2:#.*]] {
|
||||
; IS__CGSCC____-NEXT: store %struct.X* [[A]], %struct.X** [[B]], align 8
|
||||
; IS__CGSCC____-NEXT: ret void
|
||||
;
|
||||
|
||||
@@ -56,7 +56,7 @@ define void @byref_nest(i32* byref(i32) nest) {
|
||||
ret void
|
||||
}
|
||||
|
||||
; CHECK: Wrong types for attribute: inalloca nest noalias nocapture nonnull readnone readonly sret byref(i32) byval(i32) preallocated(i32) dereferenceable(1) dereferenceable_or_null(1)
|
||||
; CHECK: Wrong types for attribute: inalloca nest noalias nocapture nonnull readnone readonly byref(i32) byval(i32) preallocated(i32) sret(i32) dereferenceable(1) dereferenceable_or_null(1)
|
||||
; CHECK-NEXT: void (i32)* @byref_non_pointer
|
||||
define void @byref_non_pointer(i32 byref(i32)) {
|
||||
ret void
|
||||
|
||||
Reference in New Issue
Block a user