mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2025-01-31 12:41:49 +01:00
Reapply "OpaquePtr: Add type to sret attribute"
This reverts commit eb9f7c28e5fe6d75fed3587023e17f2997c8024b. Previously this was incorrectly handling linking of the contained type, so this merges the fixes from D88973.
This commit is contained in:
parent
45720e3d8e
commit
e3bfefd3cc
@ -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,10 +63,14 @@ 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.
|
||||
|
||||
* The ``llvm.experimental.vector.reduce`` family of intrinsics have been renamed
|
||||
to drop the "experimental" from the name, reflecting their now fully supported
|
||||
status in the IR.
|
||||
|
||||
|
||||
Changes to building LLVM
|
||||
------------------------
|
||||
|
||||
|
@ -108,9 +108,17 @@ 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);
|
||||
|
||||
/// For a typed attribute, return the equivalent attribute with the type
|
||||
/// changed to \p ReplacementTy.
|
||||
Attribute getWithNewType(LLVMContext &Context, Type *ReplacementTy) {
|
||||
assert(isTypeAttribute() && "this requires a typed attribute");
|
||||
return get(Context, getKindAsEnum(), ReplacementTy);
|
||||
}
|
||||
|
||||
static Attribute::AttrKind getAttrKindFromName(StringRef AttrName);
|
||||
|
||||
static StringRef getNameFromAttrKind(Attribute::AttrKind AttrKind);
|
||||
@ -307,6 +315,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;
|
||||
@ -508,6 +517,17 @@ public:
|
||||
return removeAttributes(C, ArgNo + FirstArgIndex);
|
||||
}
|
||||
|
||||
/// Replace the type contained by attribute \p AttrKind at index \p ArgNo wih
|
||||
/// \p ReplacementTy, preserving all other attributes.
|
||||
LLVM_NODISCARD AttributeList replaceAttributeType(LLVMContext &C,
|
||||
unsigned ArgNo,
|
||||
Attribute::AttrKind Kind,
|
||||
Type *ReplacementTy) const {
|
||||
Attribute Attr = getAttribute(ArgNo, Kind);
|
||||
auto Attrs = removeAttribute(C, ArgNo, Kind);
|
||||
return Attrs.addAttribute(C, ArgNo, Attr.getWithNewType(C, ReplacementTy));
|
||||
}
|
||||
|
||||
/// \brief Add the dereferenceable attribute to the attribute set at the given
|
||||
/// index. Returns a new list because attribute lists are immutable.
|
||||
LLVM_NODISCARD AttributeList addDereferenceableAttr(LLVMContext &C,
|
||||
@ -631,6 +651,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 +760,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 +848,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 +900,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);
|
||||
|
@ -715,9 +715,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
|
||||
@ -1609,6 +1609,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
|
||||
@ -1652,6 +1654,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) {
|
||||
@ -3286,17 +3290,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;
|
||||
@ -3757,16 +3768,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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -4618,7 +4635,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;
|
||||
}
|
||||
@ -5225,7 +5242,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 "
|
||||
|
@ -973,6 +973,8 @@ void ValueEnumerator::incorporateFunction(const Function &F) {
|
||||
EnumerateValue(&I);
|
||||
if (I.hasAttribute(Attribute::ByVal))
|
||||
EnumerateType(I.getParamByValType());
|
||||
else if (I.hasAttribute(Attribute::StructRet))
|
||||
EnumerateType(I.getParamStructRetType());
|
||||
}
|
||||
FirstFuncConstantID = Values.size();
|
||||
|
||||
|
@ -4303,12 +4303,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;
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
@ -1853,10 +1891,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);
|
||||
|
||||
// Some attributes can apply to all "values" but there are no `void` values.
|
||||
|
@ -146,6 +146,11 @@ LLVMAttributeRef LLVMCreateEnumAttribute(LLVMContextRef C, unsigned KindID,
|
||||
return wrap(Attribute::getWithByValType(Ctx, NULL));
|
||||
}
|
||||
|
||||
if (AttrKind == Attribute::AttrKind::StructRet) {
|
||||
// Same as byval.
|
||||
return wrap(Attribute::getWithStructRetType(Ctx, NULL));
|
||||
}
|
||||
|
||||
return wrap(Attribute::get(Ctx, AttrKind, Val));
|
||||
}
|
||||
|
||||
|
@ -638,14 +638,14 @@ GlobalVariable *IRLinker::copyGlobalVariableProto(const GlobalVariable *SGVar) {
|
||||
|
||||
AttributeList IRLinker::mapAttributeTypes(LLVMContext &C, AttributeList Attrs) {
|
||||
for (unsigned i = 0; i < Attrs.getNumAttrSets(); ++i) {
|
||||
if (Attrs.hasAttribute(i, Attribute::ByVal)) {
|
||||
Type *Ty = Attrs.getAttribute(i, Attribute::ByVal).getValueAsType();
|
||||
if (!Ty)
|
||||
continue;
|
||||
|
||||
Attrs = Attrs.removeAttribute(C, i, Attribute::ByVal);
|
||||
Attrs = Attrs.addAttribute(
|
||||
C, i, Attribute::getWithByValType(C, TypeMap.get(Ty)));
|
||||
for (Attribute::AttrKind TypedAttr :
|
||||
{Attribute::ByVal, Attribute::StructRet}) {
|
||||
if (Attrs.hasAttribute(i, TypedAttr)) {
|
||||
if (Type *Ty = Attrs.getAttribute(i, TypedAttr).getValueAsType()) {
|
||||
Attrs = Attrs.replaceAttributeType(C, i, TypedAttr, TypeMap.get(Ty));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return Attrs;
|
||||
|
@ -900,14 +900,13 @@ void Mapper::remapInstruction(Instruction *I) {
|
||||
LLVMContext &C = CB->getContext();
|
||||
AttributeList Attrs = CB->getAttributes();
|
||||
for (unsigned i = 0; i < Attrs.getNumAttrSets(); ++i) {
|
||||
if (Attrs.hasAttribute(i, Attribute::ByVal)) {
|
||||
Type *Ty = Attrs.getAttribute(i, Attribute::ByVal).getValueAsType();
|
||||
if (!Ty)
|
||||
continue;
|
||||
|
||||
Attrs = Attrs.removeAttribute(C, i, Attribute::ByVal);
|
||||
Attrs = Attrs.addAttribute(
|
||||
C, i, Attribute::getWithByValType(C, TypeMapper->remapType(Ty)));
|
||||
for (Attribute::AttrKind TypedAttr :
|
||||
{Attribute::ByVal, Attribute::StructRet}) {
|
||||
if (Type *Ty = Attrs.getAttribute(i, TypedAttr).getValueAsType()) {
|
||||
Attrs = Attrs.replaceAttributeType(C, i, TypedAttr,
|
||||
TypeMapper->remapType(Ty));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
CB->setAttributes(Attrs);
|
||||
|
43
test/Assembler/sret-type-attr.ll
Normal file
43
test/Assembler/sret-type-attr.ll
Normal file
@ -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)
|
||||
|
13
test/Linker/Inputs/sret-type-input.ll
Normal file
13
test/Linker/Inputs/sret-type-input.ll
Normal file
@ -0,0 +1,13 @@
|
||||
%a = type { i64 }
|
||||
%struct = type { i32, i8 }
|
||||
|
||||
define void @g(%a* sret(%a)) {
|
||||
ret void
|
||||
}
|
||||
|
||||
declare void @baz(%struct* sret(%struct))
|
||||
|
||||
define void @foo(%struct* sret(%struct) %a) {
|
||||
call void @baz(%struct* sret(%struct) %a)
|
||||
ret void
|
||||
}
|
25
test/Linker/sret-types.ll
Normal file
25
test/Linker/sret-types.ll
Normal file
@ -0,0 +1,25 @@
|
||||
; RUN: llvm-link %s %p/Inputs/sret-type-input.ll -S | FileCheck %s
|
||||
|
||||
%a = type { i64 }
|
||||
%struct = type { i32, i8 }
|
||||
|
||||
; CHECK-LABEL: define void @f(%a* sret(%a) %0)
|
||||
define void @f(%a* sret(%a)) {
|
||||
ret void
|
||||
}
|
||||
|
||||
; CHECK-LABEL: define void @bar(
|
||||
; CHECK: call void @foo(%struct* sret(%struct) %ptr)
|
||||
define void @bar() {
|
||||
%ptr = alloca %struct
|
||||
call void @foo(%struct* sret(%struct) %ptr)
|
||||
ret void
|
||||
}
|
||||
|
||||
; CHECK-LABEL: define void @g(%a* sret(%a) %0)
|
||||
|
||||
; CHECK-LABEL: define void @foo(%struct* sret(%struct) %a)
|
||||
; CHECK-NEXT: call void @baz(%struct* sret(%struct) %a)
|
||||
declare void @foo(%struct* sret(%struct) %a)
|
||||
|
||||
; CHECK: declare void @baz(%struct* sret(%struct))
|
@ -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
|
||||
;
|
||||
|
@ -1,12 +1,12 @@
|
||||
; RUN: not llvm-as < %s -o /dev/null 2>&1 | FileCheck %s
|
||||
|
||||
; CHECK: Wrong types for attribute: inalloca nest noalias nocapture nonnull readnone readonly sret byref(i32) byval(i32) preallocated(i32) align 1 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) align 1 dereferenceable(1) dereferenceable_or_null(1)
|
||||
; CHECK-NEXT: @align_non_pointer1
|
||||
define void @align_non_pointer1(i32 align 4 %a) {
|
||||
ret void
|
||||
}
|
||||
|
||||
; CHECK: Wrong types for attribute: inalloca nest noalias nocapture noundef nonnull readnone readonly signext sret zeroext byref(void) byval(void) preallocated(void) align 1 dereferenceable(1) dereferenceable_or_null(1)
|
||||
; CHECK: Wrong types for attribute: inalloca nest noalias nocapture noundef nonnull readnone readonly signext zeroext byref(void) byval(void) preallocated(void) sret(void) align 1 dereferenceable(1) dereferenceable_or_null(1)
|
||||
; CHECK-NEXT: @align_non_pointer2
|
||||
define align 4 void @align_non_pointer2(i32 %a) {
|
||||
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) align 1 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) align 1 dereferenceable(1) dereferenceable_or_null(1)
|
||||
; CHECK-NEXT: void (i32)* @byref_non_pointer
|
||||
define void @byref_non_pointer(i32 byref(i32)) {
|
||||
ret void
|
||||
|
@ -1,6 +1,6 @@
|
||||
; RUN: not llvm-as < %s -o /dev/null 2>&1 | FileCheck %s
|
||||
|
||||
; CHECK: Wrong types for attribute: inalloca nest noalias nocapture noundef nonnull readnone readonly signext sret zeroext byref(void) byval(void) preallocated(void) align 1 dereferenceable(1) dereferenceable_or_null(1)
|
||||
; CHECK: Wrong types for attribute: inalloca nest noalias nocapture noundef nonnull readnone readonly signext zeroext byref(void) byval(void) preallocated(void) sret(void) align 1 dereferenceable(1) dereferenceable_or_null(1)
|
||||
; CHECK-NEXT: @noundef_void
|
||||
define noundef void @noundef_void() {
|
||||
ret void
|
||||
|
Loading…
x
Reference in New Issue
Block a user