diff --git a/docs/LangRef.rst b/docs/LangRef.rst index 5e35b913bef..923dae330d6 100644 --- a/docs/LangRef.rst +++ b/docs/LangRef.rst @@ -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()`` 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 `` or ``align()`` diff --git a/docs/ReleaseNotes.rst b/docs/ReleaseNotes.rst index 47ce9fa10d9..264bd5ebe92 100644 --- a/docs/ReleaseNotes.rst +++ b/docs/ReleaseNotes.rst @@ -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 ------------------------ diff --git a/include/llvm/IR/Attributes.h b/include/llvm/IR/Attributes.h index 74293fdfe8d..1dd7deecdb4 100644 --- a/include/llvm/IR/Attributes.h +++ b/include/llvm/IR/Attributes.h @@ -108,6 +108,7 @@ public: unsigned ElemSizeArg, const Optional &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> 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); diff --git a/include/llvm/IR/Attributes.td b/include/llvm/IR/Attributes.td index 214eb84b6a4..96f7b73fba3 100644 --- a/include/llvm/IR/Attributes.td +++ b/include/llvm/IR/Attributes.td @@ -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">; diff --git a/include/llvm/IR/Function.h b/include/llvm/IR/Function.h index 00803ccf627..dab0ce38f33 100644 --- a/include/llvm/IR/Function.h +++ b/include/llvm/IR/Function.h @@ -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. diff --git a/lib/AsmParser/LLParser.cpp b/lib/AsmParser/LLParser.cpp index 63f8531dbdc..347e853ef78 100644 --- a/lib/AsmParser/LLParser.cpp +++ b/lib/AsmParser/LLParser.cpp @@ -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 &ArgList, /// ParseByValWithOptionalType /// ::= byval /// ::= byval() -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; diff --git a/lib/AsmParser/LLParser.h b/lib/AsmParser/LLParser.h index a7fbcdd5abc..73baaa761c1 100644 --- a/lib/AsmParser/LLParser.h +++ b/lib/AsmParser/LLParser.h @@ -332,8 +332,7 @@ namespace llvm { bool ParseFnAttributeValuePairs(AttrBuilder &B, std::vector &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); diff --git a/lib/Bitcode/Reader/BitcodeReader.cpp b/lib/Bitcode/Reader/BitcodeReader.cpp index 4d69dd7dcc5..1cb7113049d 100644 --- a/lib/Bitcode/Reader/BitcodeReader.cpp +++ b/lib/Bitcode/Reader/BitcodeReader.cpp @@ -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 ArgsFullTys); + /// Upgrades old-style typeless byval or sret attributes by adding the + /// corresponding argument's pointee type. + void propagateByValSRetTypes(CallBase *CB, ArrayRef 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 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(FullFTy)->getParamType(i); - Func->removeParamAttr(i, Attribute::ByVal); - Func->addParamAttr(i, Attribute::getWithByValType( - Context, getPointerElementFlatType(PTy))); + Func->removeParamAttr(i, Kind); + + Type *PTy = cast(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 ArgsFullTys) { +void BitcodeReader::propagateByValSRetTypes(CallBase *CB, + ArrayRef 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(I)->setCallingConv( static_cast(CallingConv::MaxID & CCInfo)); cast(I)->setAttributes(PAL); - propagateByValTypes(cast(I), ArgsFullTys); + propagateByValSRetTypes(cast(I), ArgsFullTys); break; } @@ -5227,7 +5244,7 @@ Error BitcodeReader::parseFunctionBody(Function *F) { TCK = CallInst::TCK_NoTail; cast(I)->setTailCallKind(TCK); cast(I)->setAttributes(PAL); - propagateByValTypes(cast(I), ArgsFullTys); + propagateByValSRetTypes(cast(I), ArgsFullTys); if (FMF.any()) { if (!isa(I)) return error("Fast-math-flags specified for call without " diff --git a/lib/IR/AsmWriter.cpp b/lib/IR/AsmWriter.cpp index 8cb1883da68..96c82cb2a07 100644 --- a/lib/IR/AsmWriter.cpp +++ b/lib/IR/AsmWriter.cpp @@ -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 { diff --git a/lib/IR/AttributeImpl.h b/lib/IR/AttributeImpl.h index 8510be4fd8c..c69fe3fe082 100644 --- a/lib/IR/AttributeImpl.h +++ b/lib/IR/AttributeImpl.h @@ -254,6 +254,7 @@ public: std::pair> getAllocSizeArgs() const; std::string getAsString(bool InAttrGrp) const; Type *getByValType() const; + Type *getStructRetType() const; Type *getByRefType() const; Type *getPreallocatedType() const; diff --git a/lib/IR/Attributes.cpp b/lib/IR/Attributes.cpp index a3940c0fa7f..172341dc45e 100644 --- a/lib/IR/Attributes.cpp +++ b/lib/IR/Attributes.cpp @@ -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; diff --git a/test/Assembler/sret-type-attr.ll b/test/Assembler/sret-type-attr.ll new file mode 100644 index 00000000000..b2efcf576e3 --- /dev/null +++ b/test/Assembler/sret-type-attr.ll @@ -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* })) diff --git a/test/Bitcode/attributes-3.3.ll b/test/Bitcode/attributes-3.3.ll index dc7834eaa16..abec923d8c5 100644 --- a/test/Bitcode/attributes-3.3.ll +++ b/test/Bitcode/attributes-3.3.ll @@ -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; } diff --git a/test/Bitcode/attributes.ll b/test/Bitcode/attributes.ll index 409528230a7..1a95cceec11 100644 --- a/test/Bitcode/attributes.ll +++ b/test/Bitcode/attributes.ll @@ -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; } diff --git a/test/Bitcode/compatibility-3.6.ll b/test/Bitcode/compatibility-3.6.ll index 6bfd4e5a7b6..36bc76837b3 100644 --- a/test/Bitcode/compatibility-3.6.ll +++ b/test/Bitcode/compatibility-3.6.ll @@ -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) diff --git a/test/Bitcode/compatibility-3.7.ll b/test/Bitcode/compatibility-3.7.ll index 9117b1ce5b2..d39e0edf7a2 100644 --- a/test/Bitcode/compatibility-3.7.ll +++ b/test/Bitcode/compatibility-3.7.ll @@ -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) diff --git a/test/Bitcode/compatibility-3.8.ll b/test/Bitcode/compatibility-3.8.ll index c8f19594033..f79fe6404c4 100644 --- a/test/Bitcode/compatibility-3.8.ll +++ b/test/Bitcode/compatibility-3.8.ll @@ -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) diff --git a/test/Bitcode/compatibility-3.9.ll b/test/Bitcode/compatibility-3.9.ll index b251aaec7b2..b13e37d4354 100644 --- a/test/Bitcode/compatibility-3.9.ll +++ b/test/Bitcode/compatibility-3.9.ll @@ -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) diff --git a/test/Bitcode/compatibility-4.0.ll b/test/Bitcode/compatibility-4.0.ll index ba4b196ac01..c0947b8bf6c 100644 --- a/test/Bitcode/compatibility-4.0.ll +++ b/test/Bitcode/compatibility-4.0.ll @@ -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) diff --git a/test/Bitcode/compatibility-5.0.ll b/test/Bitcode/compatibility-5.0.ll index a38bf2d9675..902903ecd6f 100644 --- a/test/Bitcode/compatibility-5.0.ll +++ b/test/Bitcode/compatibility-5.0.ll @@ -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) diff --git a/test/Bitcode/compatibility-6.0.ll b/test/Bitcode/compatibility-6.0.ll index 5af30ddc863..a87329141d4 100644 --- a/test/Bitcode/compatibility-6.0.ll +++ b/test/Bitcode/compatibility-6.0.ll @@ -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) diff --git a/test/Bitcode/compatibility.ll b/test/Bitcode/compatibility.ll index 055397f125b..9ae2137e5aa 100644 --- a/test/Bitcode/compatibility.ll +++ b/test/Bitcode/compatibility.ll @@ -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) diff --git a/test/Bitcode/highLevelStructure.3.2.ll b/test/Bitcode/highLevelStructure.3.2.ll index 91d6ee4ac25..97f9a26c414 100644 --- a/test/Bitcode/highLevelStructure.3.2.ll +++ b/test/Bitcode/highLevelStructure.3.2.ll @@ -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) diff --git a/test/Transforms/Attributor/ArgumentPromotion/sret.ll b/test/Transforms/Attributor/ArgumentPromotion/sret.ll index d49cc627b16..7b656e6166f 100644 --- a/test/Transforms/Attributor/ArgumentPromotion/sret.ll +++ b/test/Transforms/Attributor/ArgumentPromotion/sret.ll @@ -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 } diff --git a/test/Transforms/Attributor/value-simplify.ll b/test/Transforms/Attributor/value-simplify.ll index 174fd799a6e..727dd9dcbec 100644 --- a/test/Transforms/Attributor/value-simplify.ll +++ b/test/Transforms/Attributor/value-simplify.ll @@ -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 ; diff --git a/test/Verifier/byref.ll b/test/Verifier/byref.ll index 5e7d5873a8d..318582a7a61 100644 --- a/test/Verifier/byref.ll +++ b/test/Verifier/byref.ll @@ -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