mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2024-11-25 04:02:41 +01:00
Reapply "OpaquePtr: Turn inalloca into a type attribute"
This reverts commit 07e46367baeca96d84b03fa215b41775f69d5989.
This commit is contained in:
parent
8d90020fab
commit
efe6c99b52
@ -52,7 +52,6 @@ func TestAttributes(t *testing.T) {
|
||||
"alwaysinline",
|
||||
"builtin",
|
||||
"convergent",
|
||||
"inalloca",
|
||||
"inlinehint",
|
||||
"inreg",
|
||||
"jumptable",
|
||||
|
@ -1119,7 +1119,7 @@ Currently, only the following parameter attributes are defined:
|
||||
|
||||
.. _attr_inalloca:
|
||||
|
||||
``inalloca``
|
||||
``inalloca(<ty>)``
|
||||
|
||||
The ``inalloca`` argument attribute allows the caller to take the
|
||||
address of outgoing stack arguments. An ``inalloca`` argument must
|
||||
@ -1143,6 +1143,9 @@ Currently, only the following parameter attributes are defined:
|
||||
must be cleared off with :ref:`llvm.stackrestore
|
||||
<int_stackrestore>`.
|
||||
|
||||
The inalloca attribute requires a type argument, which must be the
|
||||
same as the pointee type of the argument.
|
||||
|
||||
See :doc:`InAlloca` for more information on how to use this
|
||||
attribute.
|
||||
|
||||
|
@ -58,7 +58,8 @@ Non-comprehensive list of changes in this release
|
||||
Changes to the LLVM IR
|
||||
----------------------
|
||||
|
||||
* ...
|
||||
* The ``inalloca`` attribute now has a mandatory type field, similar
|
||||
to ``byval`` and ``sret``.
|
||||
|
||||
|
||||
Changes to building LLVM
|
||||
|
@ -111,6 +111,9 @@ public:
|
||||
/// If this is a byref argument, return its type.
|
||||
Type *getParamByRefType() const;
|
||||
|
||||
/// If this is an inalloca argument, return its type.
|
||||
Type *getParamInAllocaType() const;
|
||||
|
||||
/// Return true if this argument has the nest attribute.
|
||||
bool hasNestAttr() const;
|
||||
|
||||
|
@ -114,6 +114,7 @@ public:
|
||||
static Attribute getWithStructRetType(LLVMContext &Context, Type *Ty);
|
||||
static Attribute getWithByRefType(LLVMContext &Context, Type *Ty);
|
||||
static Attribute getWithPreallocatedType(LLVMContext &Context, Type *Ty);
|
||||
static Attribute getWithInAllocaType(LLVMContext &Context, Type *Ty);
|
||||
|
||||
/// For a typed attribute, return the equivalent attribute with the type
|
||||
/// changed to \p ReplacementTy.
|
||||
@ -160,7 +161,7 @@ public:
|
||||
bool hasAttribute(StringRef Val) const;
|
||||
|
||||
/// Return the attribute's kind as an enum (Attribute::AttrKind). This
|
||||
/// requires the attribute to be an enum or integer attribute.
|
||||
/// requires the attribute to be an enum, integer, or type attribute.
|
||||
Attribute::AttrKind getKindAsEnum() const;
|
||||
|
||||
/// Return the attribute's value as an integer. This requires that the
|
||||
@ -325,6 +326,7 @@ public:
|
||||
Type *getStructRetType() const;
|
||||
Type *getByRefType() const;
|
||||
Type *getPreallocatedType() const;
|
||||
Type *getInAllocaType() const;
|
||||
std::pair<unsigned, Optional<unsigned>> getAllocSizeArgs() const;
|
||||
std::pair<unsigned, unsigned> getVScaleRangeArgs() const;
|
||||
std::string getAsString(bool InAttrGrp = false) const;
|
||||
@ -684,6 +686,9 @@ public:
|
||||
/// Return the preallocated type for the specified function parameter.
|
||||
Type *getParamPreallocatedType(unsigned ArgNo) const;
|
||||
|
||||
/// Return the inalloca type for the specified function parameter.
|
||||
Type *getParamInAllocaType(unsigned ArgNo) const;
|
||||
|
||||
/// Get the stack alignment.
|
||||
MaybeAlign getStackAlignment(unsigned Index) const;
|
||||
|
||||
@ -791,6 +796,7 @@ class AttrBuilder {
|
||||
Type *StructRetType = nullptr;
|
||||
Type *ByRefType = nullptr;
|
||||
Type *PreallocatedType = nullptr;
|
||||
Type *InAllocaType = nullptr;
|
||||
|
||||
public:
|
||||
AttrBuilder() = default;
|
||||
@ -885,6 +891,9 @@ public:
|
||||
/// Retrieve the preallocated type.
|
||||
Type *getPreallocatedType() const { return PreallocatedType; }
|
||||
|
||||
/// Retrieve the inalloca type.
|
||||
Type *getInAllocaType() const { return InAllocaType; }
|
||||
|
||||
/// Retrieve the allocsize args, if the allocsize attribute exists. If it
|
||||
/// doesn't exist, pair(0, 0) is returned.
|
||||
std::pair<unsigned, Optional<unsigned>> getAllocSizeArgs() const;
|
||||
@ -944,6 +953,9 @@ public:
|
||||
/// This turns a preallocated type into the form used internally in Attribute.
|
||||
AttrBuilder &addPreallocatedAttr(Type *Ty);
|
||||
|
||||
/// This turns an inalloca type into the form used internally in Attribute.
|
||||
AttrBuilder &addInAllocaAttr(Type *Ty);
|
||||
|
||||
/// Add an allocsize attribute, using the representation returned by
|
||||
/// Attribute.getIntValue().
|
||||
AttrBuilder &addAllocSizeAttrFromRawRepr(uint64_t RawAllocSizeRepr);
|
||||
|
@ -80,7 +80,7 @@ def InaccessibleMemOnly : EnumAttr<"inaccessiblememonly">;
|
||||
def InaccessibleMemOrArgMemOnly : EnumAttr<"inaccessiblemem_or_argmemonly">;
|
||||
|
||||
/// Pass structure in an alloca.
|
||||
def InAlloca : EnumAttr<"inalloca">;
|
||||
def InAlloca : TypeAttr<"inalloca">;
|
||||
|
||||
/// Source said inlining was desirable.
|
||||
def InlineHint : EnumAttr<"inlinehint">;
|
||||
|
@ -493,6 +493,11 @@ public:
|
||||
return AttributeSets.getParamStructRetType(ArgNo);
|
||||
}
|
||||
|
||||
/// Extract the inalloca type for a parameter.
|
||||
Type *getParamInAllocaType(unsigned ArgNo) const {
|
||||
return AttributeSets.getParamInAllocaType(ArgNo);
|
||||
}
|
||||
|
||||
/// Extract the byref type for a parameter.
|
||||
Type *getParamByRefType(unsigned ArgNo) const {
|
||||
return AttributeSets.getParamByRefType(ArgNo);
|
||||
|
@ -1736,6 +1736,13 @@ bool LLParser::parseOptionalParamAttrs(AttrBuilder &B) {
|
||||
B.addPreallocatedAttr(Ty);
|
||||
continue;
|
||||
}
|
||||
case lltok::kw_inalloca: {
|
||||
Type *Ty;
|
||||
if (parseInalloca(Ty))
|
||||
return true;
|
||||
B.addInAllocaAttr(Ty);
|
||||
continue;
|
||||
}
|
||||
case lltok::kw_dereferenceable: {
|
||||
uint64_t Bytes;
|
||||
if (parseOptionalDerefAttrBytes(lltok::kw_dereferenceable, Bytes))
|
||||
@ -1757,7 +1764,6 @@ bool LLParser::parseOptionalParamAttrs(AttrBuilder &B) {
|
||||
B.addByRefAttr(Ty);
|
||||
continue;
|
||||
}
|
||||
case lltok::kw_inalloca: B.addAttribute(Attribute::InAlloca); break;
|
||||
case lltok::kw_inreg: B.addAttribute(Attribute::InReg); break;
|
||||
case lltok::kw_nest: B.addAttribute(Attribute::Nest); break;
|
||||
case lltok::kw_noundef:
|
||||
@ -2694,6 +2700,12 @@ bool LLParser::parsePreallocated(Type *&Result) {
|
||||
return parseRequiredTypeAttr(Result, lltok::kw_preallocated);
|
||||
}
|
||||
|
||||
/// parseInalloca
|
||||
/// ::= inalloca(<ty>)
|
||||
bool LLParser::parseInalloca(Type *&Result) {
|
||||
return parseRequiredTypeAttr(Result, lltok::kw_inalloca);
|
||||
}
|
||||
|
||||
/// parseByRef
|
||||
/// ::= byref(<type>)
|
||||
bool LLParser::parseByRef(Type *&Result) {
|
||||
|
@ -331,6 +331,7 @@ namespace llvm {
|
||||
bool inAttrGrp, LocTy &BuiltinLoc);
|
||||
bool parseRequiredTypeAttr(Type *&Result, lltok::Kind AttrName);
|
||||
bool parsePreallocated(Type *&Result);
|
||||
bool parseInalloca(Type *&Result);
|
||||
bool parseByRef(Type *&Result);
|
||||
|
||||
// Module Summary Index Parsing.
|
||||
|
@ -1624,6 +1624,8 @@ Error BitcodeReader::parseAttributeGroupBlock() {
|
||||
B.addByValAttr(nullptr);
|
||||
else if (Kind == Attribute::StructRet)
|
||||
B.addStructRetAttr(nullptr);
|
||||
else if (Kind == Attribute::InAlloca)
|
||||
B.addInAllocaAttr(nullptr);
|
||||
|
||||
B.addAttribute(Kind);
|
||||
} else if (Record[i] == 1) { // Integer attribute
|
||||
@ -1675,6 +1677,8 @@ Error BitcodeReader::parseAttributeGroupBlock() {
|
||||
B.addByRefAttr(getTypeByID(Record[++i]));
|
||||
} else if (Kind == Attribute::Preallocated) {
|
||||
B.addPreallocatedAttr(getTypeByID(Record[++i]));
|
||||
} else if (Kind == Attribute::InAlloca) {
|
||||
B.addInAllocaAttr(HasType ? getTypeByID(Record[++i]) : nullptr);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -3328,7 +3332,8 @@ Error BitcodeReader::parseFunctionRecord(ArrayRef<uint64_t> Record) {
|
||||
// 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) {
|
||||
for (Attribute::AttrKind Kind : {Attribute::ByVal, Attribute::StructRet}) {
|
||||
for (Attribute::AttrKind Kind : {Attribute::ByVal, Attribute::StructRet,
|
||||
Attribute::InAlloca}) {
|
||||
if (!Func->hasParamAttribute(i, Kind))
|
||||
continue;
|
||||
|
||||
@ -3336,10 +3341,21 @@ Error BitcodeReader::parseFunctionRecord(ArrayRef<uint64_t> Record) {
|
||||
|
||||
Type *PTy = cast<FunctionType>(FullFTy)->getParamType(i);
|
||||
Type *PtrEltTy = getPointerElementFlatType(PTy);
|
||||
Attribute NewAttr =
|
||||
Kind == Attribute::ByVal
|
||||
? Attribute::getWithByValType(Context, PtrEltTy)
|
||||
: Attribute::getWithStructRetType(Context, PtrEltTy);
|
||||
Attribute NewAttr;
|
||||
switch (Kind) {
|
||||
case Attribute::ByVal:
|
||||
NewAttr = Attribute::getWithByValType(Context, PtrEltTy);
|
||||
break;
|
||||
case Attribute::StructRet:
|
||||
NewAttr = Attribute::getWithStructRetType(Context, PtrEltTy);
|
||||
break;
|
||||
case Attribute::InAlloca:
|
||||
NewAttr = Attribute::getWithInAllocaType(Context, PtrEltTy);
|
||||
break;
|
||||
default:
|
||||
llvm_unreachable("not an upgraded type attribute");
|
||||
}
|
||||
|
||||
Func->addParamAttr(i, NewAttr);
|
||||
}
|
||||
}
|
||||
@ -3805,17 +3821,29 @@ Error BitcodeReader::typeCheckLoadStoreInst(Type *ValType, Type *PtrType) {
|
||||
void BitcodeReader::propagateByValSRetTypes(CallBase *CB,
|
||||
ArrayRef<Type *> ArgsFullTys) {
|
||||
for (unsigned i = 0; i != CB->arg_size(); ++i) {
|
||||
for (Attribute::AttrKind Kind : {Attribute::ByVal, Attribute::StructRet}) {
|
||||
for (Attribute::AttrKind Kind : {Attribute::ByVal, Attribute::StructRet,
|
||||
Attribute::InAlloca}) {
|
||||
if (!CB->paramHasAttr(i, Kind))
|
||||
continue;
|
||||
|
||||
CB->removeParamAttr(i, Kind);
|
||||
|
||||
Type *PtrEltTy = getPointerElementFlatType(ArgsFullTys[i]);
|
||||
Attribute NewAttr =
|
||||
Kind == Attribute::ByVal
|
||||
? Attribute::getWithByValType(Context, PtrEltTy)
|
||||
: Attribute::getWithStructRetType(Context, PtrEltTy);
|
||||
Attribute NewAttr;
|
||||
switch (Kind) {
|
||||
case Attribute::ByVal:
|
||||
NewAttr = Attribute::getWithByValType(Context, PtrEltTy);
|
||||
break;
|
||||
case Attribute::StructRet:
|
||||
NewAttr = Attribute::getWithStructRetType(Context, PtrEltTy);
|
||||
break;
|
||||
case Attribute::InAlloca:
|
||||
NewAttr = Attribute::getWithInAllocaType(Context, PtrEltTy);
|
||||
break;
|
||||
default:
|
||||
llvm_unreachable("not an upgraded type attribute");
|
||||
}
|
||||
|
||||
CB->addParamAttr(i, NewAttr);
|
||||
}
|
||||
}
|
||||
|
@ -4413,20 +4413,18 @@ void AssemblyWriter::writeAttribute(const Attribute &Attr, bool InAttrGroup) {
|
||||
return;
|
||||
}
|
||||
|
||||
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 {
|
||||
} else if (Attr.hasAttribute(Attribute::Preallocated)) {
|
||||
Out << "preallocated";
|
||||
} else if (Attr.hasAttribute(Attribute::InAlloca)) {
|
||||
Out << "inalloca";
|
||||
} else {
|
||||
llvm_unreachable("unexpected type attr");
|
||||
}
|
||||
|
||||
if (Type *Ty = Attr.getValueAsType()) {
|
||||
|
@ -258,6 +258,7 @@ public:
|
||||
Type *getStructRetType() const;
|
||||
Type *getByRefType() const;
|
||||
Type *getPreallocatedType() const;
|
||||
Type *getInAllocaType() const;
|
||||
|
||||
using iterator = const Attribute *;
|
||||
|
||||
|
@ -195,6 +195,10 @@ Attribute Attribute::getWithPreallocatedType(LLVMContext &Context, Type *Ty) {
|
||||
return get(Context, Preallocated, Ty);
|
||||
}
|
||||
|
||||
Attribute Attribute::getWithInAllocaType(LLVMContext &Context, Type *Ty) {
|
||||
return get(Context, InAlloca, Ty);
|
||||
}
|
||||
|
||||
Attribute
|
||||
Attribute::getWithAllocSizeArgs(LLVMContext &Context, unsigned ElemSizeArg,
|
||||
const Optional<unsigned> &NumElemsArg) {
|
||||
@ -377,8 +381,6 @@ std::string Attribute::getAsString(bool InAttrGrp) const {
|
||||
return "inaccessiblememonly";
|
||||
if (hasAttribute(Attribute::InaccessibleMemOrArgMemOnly))
|
||||
return "inaccessiblemem_or_argmemonly";
|
||||
if (hasAttribute(Attribute::InAlloca))
|
||||
return "inalloca";
|
||||
if (hasAttribute(Attribute::InlineHint))
|
||||
return "inlinehint";
|
||||
if (hasAttribute(Attribute::InReg))
|
||||
@ -484,24 +486,30 @@ std::string Attribute::getAsString(bool InAttrGrp) const {
|
||||
if (hasAttribute(Attribute::MustProgress))
|
||||
return "mustprogress";
|
||||
|
||||
const bool IsByVal = hasAttribute(Attribute::ByVal);
|
||||
if (IsByVal || hasAttribute(Attribute::StructRet)) {
|
||||
if (isTypeAttribute()) {
|
||||
std::string Result;
|
||||
Result += IsByVal ? "byval" : "sret";
|
||||
if (Type *Ty = getValueAsType()) {
|
||||
raw_string_ostream OS(Result);
|
||||
Result += '(';
|
||||
Ty->print(OS, false, true);
|
||||
OS.flush();
|
||||
Result += ')';
|
||||
}
|
||||
return Result;
|
||||
}
|
||||
|
||||
const bool IsByRef = hasAttribute(Attribute::ByRef);
|
||||
if (IsByRef || hasAttribute(Attribute::Preallocated)) {
|
||||
std::string Result = IsByRef ? "byref" : "preallocated";
|
||||
raw_string_ostream OS(Result);
|
||||
|
||||
switch (getKindAsEnum()) {
|
||||
case Attribute::ByVal:
|
||||
Result += "byval";
|
||||
break;
|
||||
case Attribute::StructRet:
|
||||
Result += "sret";
|
||||
break;
|
||||
case Attribute::ByRef:
|
||||
Result += "byref";
|
||||
break;
|
||||
case Attribute::Preallocated:
|
||||
Result += "preallocated";
|
||||
break;
|
||||
case Attribute::InAlloca:
|
||||
Result += "inalloca";
|
||||
break;
|
||||
default:
|
||||
llvm_unreachable("unhandled type attribute");
|
||||
}
|
||||
|
||||
Result += '(';
|
||||
getValueAsType()->print(OS, false, true);
|
||||
OS.flush();
|
||||
@ -809,6 +817,10 @@ Type *AttributeSet::getPreallocatedType() const {
|
||||
return SetNode ? SetNode->getPreallocatedType() : nullptr;
|
||||
}
|
||||
|
||||
Type *AttributeSet::getInAllocaType() const {
|
||||
return SetNode ? SetNode->getInAllocaType() : nullptr;
|
||||
}
|
||||
|
||||
std::pair<unsigned, Optional<unsigned>> AttributeSet::getAllocSizeArgs() const {
|
||||
return SetNode ? SetNode->getAllocSizeArgs()
|
||||
: std::pair<unsigned, Optional<unsigned>>(0, 0);
|
||||
@ -915,6 +927,9 @@ AttributeSetNode *AttributeSetNode::get(LLVMContext &C, const AttrBuilder &B) {
|
||||
case Attribute::Preallocated:
|
||||
Attr = Attribute::getWithPreallocatedType(C, B.getPreallocatedType());
|
||||
break;
|
||||
case Attribute::InAlloca:
|
||||
Attr = Attribute::getWithInAllocaType(C, B.getInAllocaType());
|
||||
break;
|
||||
case Attribute::Alignment:
|
||||
assert(B.getAlignment() && "Alignment must be set");
|
||||
Attr = Attribute::getWithAlignment(C, *B.getAlignment());
|
||||
@ -1021,6 +1036,12 @@ Type *AttributeSetNode::getPreallocatedType() const {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
Type *AttributeSetNode::getInAllocaType() const {
|
||||
if (auto A = findEnumAttribute(Attribute::InAlloca))
|
||||
return A->getValueAsType();
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
uint64_t AttributeSetNode::getDereferenceableBytes() const {
|
||||
if (auto A = findEnumAttribute(Attribute::Dereferenceable))
|
||||
return A->getDereferenceableBytes();
|
||||
@ -1578,6 +1599,10 @@ Type *AttributeList::getParamPreallocatedType(unsigned Index) const {
|
||||
return getAttributes(Index + FirstArgIndex).getPreallocatedType();
|
||||
}
|
||||
|
||||
Type *AttributeList::getParamInAllocaType(unsigned Index) const {
|
||||
return getAttributes(Index + FirstArgIndex).getInAllocaType();
|
||||
}
|
||||
|
||||
MaybeAlign AttributeList::getStackAlignment(unsigned Index) const {
|
||||
return getAttributes(Index).getStackAlignment();
|
||||
}
|
||||
@ -1699,6 +1724,9 @@ AttrBuilder &AttrBuilder::addAttribute(Attribute Attr) {
|
||||
AllocSizeArgs = Attr.getValueAsInt();
|
||||
else if (Kind == Attribute::VScaleRange)
|
||||
VScaleRangeArgs = Attr.getValueAsInt();
|
||||
else if (Kind == Attribute::InAlloca)
|
||||
InAllocaType = Attr.getValueAsType();
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
@ -1723,6 +1751,8 @@ AttrBuilder &AttrBuilder::removeAttribute(Attribute::AttrKind Val) {
|
||||
ByRefType = nullptr;
|
||||
else if (Val == Attribute::Preallocated)
|
||||
PreallocatedType = nullptr;
|
||||
else if (Val == Attribute::InAlloca)
|
||||
InAllocaType = nullptr;
|
||||
else if (Val == Attribute::Dereferenceable)
|
||||
DerefBytes = 0;
|
||||
else if (Val == Attribute::DereferenceableOrNull)
|
||||
@ -1852,6 +1882,12 @@ AttrBuilder &AttrBuilder::addPreallocatedAttr(Type *Ty) {
|
||||
return *this;
|
||||
}
|
||||
|
||||
AttrBuilder &AttrBuilder::addInAllocaAttr(Type *Ty) {
|
||||
Attrs[Attribute::InAlloca] = true;
|
||||
InAllocaType = Ty;
|
||||
return *this;
|
||||
}
|
||||
|
||||
AttrBuilder &AttrBuilder::merge(const AttrBuilder &B) {
|
||||
// FIXME: What if both have alignments, but they don't match?!
|
||||
if (!Alignment)
|
||||
@ -1881,6 +1917,9 @@ AttrBuilder &AttrBuilder::merge(const AttrBuilder &B) {
|
||||
if (!PreallocatedType)
|
||||
PreallocatedType = B.PreallocatedType;
|
||||
|
||||
if (!InAllocaType)
|
||||
InAllocaType = B.InAllocaType;
|
||||
|
||||
if (!VScaleRangeArgs)
|
||||
VScaleRangeArgs = B.VScaleRangeArgs;
|
||||
|
||||
@ -1921,6 +1960,9 @@ AttrBuilder &AttrBuilder::remove(const AttrBuilder &B) {
|
||||
if (B.PreallocatedType)
|
||||
PreallocatedType = nullptr;
|
||||
|
||||
if (B.InAllocaType)
|
||||
InAllocaType = nullptr;
|
||||
|
||||
if (B.VScaleRangeArgs)
|
||||
VScaleRangeArgs = 0;
|
||||
|
||||
@ -1985,6 +2027,7 @@ bool AttrBuilder::operator==(const AttrBuilder &B) const {
|
||||
DerefBytes == B.DerefBytes && ByValType == B.ByValType &&
|
||||
StructRetType == B.StructRetType && ByRefType == B.ByRefType &&
|
||||
PreallocatedType == B.PreallocatedType &&
|
||||
InAllocaType == B.InAllocaType &&
|
||||
VScaleRangeArgs == B.VScaleRangeArgs;
|
||||
}
|
||||
|
||||
@ -2014,6 +2057,7 @@ AttrBuilder AttributeFuncs::typeIncompatible(Type *Ty) {
|
||||
.addAttribute(Attribute::ReadOnly)
|
||||
.addAttribute(Attribute::InAlloca)
|
||||
.addPreallocatedAttr(Ty)
|
||||
.addInAllocaAttr(Ty)
|
||||
.addByValAttr(Ty)
|
||||
.addStructRetAttr(Ty)
|
||||
.addByRefAttr(Ty);
|
||||
|
@ -162,6 +162,8 @@ static Type *getMemoryParamAllocType(AttributeSet ParamAttrs, Type *ArgTy) {
|
||||
return ByRefTy;
|
||||
if (Type *PreAllocTy = ParamAttrs.getPreallocatedType())
|
||||
return PreAllocTy;
|
||||
if (Type *InAllocaTy = ParamAttrs.getInAllocaType())
|
||||
return InAllocaTy;
|
||||
|
||||
// FIXME: sret and inalloca always depends on pointee element type. It's also
|
||||
// possible for byval to miss it.
|
||||
@ -213,6 +215,11 @@ Type *Argument::getParamByRefType() const {
|
||||
return getParent()->getParamByRefType(getArgNo());
|
||||
}
|
||||
|
||||
Type *Argument::getParamInAllocaType() const {
|
||||
assert(getType()->isPointerTy() && "Only pointers have inalloca types");
|
||||
return getParent()->getParamInAllocaType(getArgNo());
|
||||
}
|
||||
|
||||
uint64_t Argument::getDereferenceableBytes() const {
|
||||
assert(getType()->isPointerTy() &&
|
||||
"Only pointers have dereferenceable bytes");
|
||||
|
@ -1813,6 +1813,11 @@ void Verifier::verifyParameterAttrs(AttributeSet Attrs, Type *Ty,
|
||||
Assert(Attrs.getPreallocatedType() == PTy->getElementType(),
|
||||
"Attribute 'preallocated' type does not match parameter!", V);
|
||||
}
|
||||
|
||||
if (Attrs.hasAttribute(Attribute::InAlloca)) {
|
||||
Assert(Attrs.getInAllocaType() == PTy->getElementType(),
|
||||
"Attribute 'inalloca' type does not match parameter!", V);
|
||||
}
|
||||
} else {
|
||||
Assert(!Attrs.hasAttribute(Attribute::ByVal),
|
||||
"Attribute 'byval' only applies to parameters with pointer type!",
|
||||
|
@ -647,7 +647,8 @@ GlobalVariable *IRLinker::copyGlobalVariableProto(const GlobalVariable *SGVar) {
|
||||
AttributeList IRLinker::mapAttributeTypes(LLVMContext &C, AttributeList Attrs) {
|
||||
for (unsigned i = 0; i < Attrs.getNumAttrSets(); ++i) {
|
||||
for (Attribute::AttrKind TypedAttr :
|
||||
{Attribute::ByVal, Attribute::StructRet, Attribute::ByRef}) {
|
||||
{Attribute::ByVal, Attribute::StructRet, Attribute::ByRef,
|
||||
Attribute::InAlloca}) {
|
||||
if (Attrs.hasAttribute(i, TypedAttr)) {
|
||||
if (Type *Ty = Attrs.getAttribute(i, TypedAttr).getValueAsType()) {
|
||||
Attrs = Attrs.replaceAttributeType(C, i, TypedAttr, TypeMap.get(Ty));
|
||||
|
@ -945,7 +945,8 @@ void Mapper::remapInstruction(Instruction *I) {
|
||||
AttributeList Attrs = CB->getAttributes();
|
||||
for (unsigned i = 0; i < Attrs.getNumAttrSets(); ++i) {
|
||||
for (Attribute::AttrKind TypedAttr :
|
||||
{Attribute::ByVal, Attribute::StructRet, Attribute::ByRef}) {
|
||||
{Attribute::ByVal, Attribute::StructRet, Attribute::ByRef,
|
||||
Attribute::InAlloca}) {
|
||||
if (Type *Ty = Attrs.getAttribute(i, TypedAttr).getValueAsType()) {
|
||||
Attrs = Attrs.replaceAttributeType(C, i, TypedAttr,
|
||||
TypeMapper->remapType(Ty));
|
||||
|
6
test/Assembler/inalloca-parse-error0.ll
Normal file
6
test/Assembler/inalloca-parse-error0.ll
Normal file
@ -0,0 +1,6 @@
|
||||
; RUN: not llvm-as < %s 2>&1 | FileCheck %s
|
||||
|
||||
; CHECK: <stdin>:[[@LINE+1]]:40: error: expected '('{{$}}
|
||||
define void @test_inalloca(i8* inalloca) {
|
||||
ret void
|
||||
}
|
@ -4,7 +4,7 @@
|
||||
declare void @llvm.immarg.byval(i32* byval(i32) immarg)
|
||||
|
||||
; CHECK: Attribute 'immarg' is incompatible with other attributes
|
||||
declare void @llvm.immarg.inalloca(i32* inalloca immarg)
|
||||
declare void @llvm.immarg.inalloca(i32* inalloca(i32) immarg)
|
||||
|
||||
; CHECK: Attribute 'immarg' is incompatible with other attributes
|
||||
declare void @llvm.immarg.inreg(i32 inreg immarg)
|
||||
|
BIN
test/Bitcode/Inputs/inalloca-upgrade.bc
Normal file
BIN
test/Bitcode/Inputs/inalloca-upgrade.bc
Normal file
Binary file not shown.
@ -214,8 +214,8 @@ define void @f35() optnone noinline
|
||||
ret void;
|
||||
}
|
||||
|
||||
define void @f36(i8* inalloca %0) {
|
||||
; CHECK: define void @f36(i8* inalloca %0) {
|
||||
define void @f36(i8* inalloca(i8) %0) {
|
||||
; CHECK: define void @f36(i8* inalloca(i8) %0) {
|
||||
ret void
|
||||
}
|
||||
|
||||
|
@ -406,7 +406,7 @@ declare void @f.param.inreg(i8 inreg)
|
||||
declare void @f.param.byval({ i8, i8 }* byval({ i8, i8 }))
|
||||
; CHECK: declare void @f.param.byval({ i8, i8 }* byval({ i8, i8 }))
|
||||
declare void @f.param.inalloca(i8* inalloca)
|
||||
; CHECK: declare void @f.param.inalloca(i8* inalloca)
|
||||
; CHECK: declare void @f.param.inalloca(i8* inalloca(i8))
|
||||
declare void @f.param.sret(i8* sret(i8))
|
||||
; CHECK: declare void @f.param.sret(i8* sret(i8))
|
||||
declare void @f.param.noalias(i8* noalias)
|
||||
@ -993,7 +993,7 @@ exit:
|
||||
|
||||
define void @instructions.call_musttail(i8* inalloca %val) {
|
||||
musttail call void @f.param.inalloca(i8* inalloca %val)
|
||||
; CHECK: musttail call void @f.param.inalloca(i8* inalloca %val)
|
||||
; CHECK: musttail call void @f.param.inalloca(i8* inalloca(i8) %val)
|
||||
|
||||
ret void
|
||||
}
|
||||
|
@ -412,7 +412,7 @@ declare void @f.param.inreg(i8 inreg)
|
||||
declare void @f.param.byval({ i8, i8 }* byval({ i8, i8 }))
|
||||
; CHECK: declare void @f.param.byval({ i8, i8 }* byval({ i8, i8 }))
|
||||
declare void @f.param.inalloca(i8* inalloca)
|
||||
; CHECK: declare void @f.param.inalloca(i8* inalloca)
|
||||
; CHECK: declare void @f.param.inalloca(i8* inalloca(i8))
|
||||
declare void @f.param.sret(i8* sret(i8))
|
||||
; CHECK: declare void @f.param.sret(i8* sret(i8))
|
||||
declare void @f.param.noalias(i8* noalias)
|
||||
@ -1034,7 +1034,7 @@ exit:
|
||||
|
||||
define void @instructions.call_musttail(i8* inalloca %val) {
|
||||
musttail call void @f.param.inalloca(i8* inalloca %val)
|
||||
; CHECK: musttail call void @f.param.inalloca(i8* inalloca %val)
|
||||
; CHECK: musttail call void @f.param.inalloca(i8* inalloca(i8) %val)
|
||||
|
||||
ret void
|
||||
}
|
||||
|
@ -437,7 +437,7 @@ declare void @f.param.inreg(i8 inreg)
|
||||
declare void @f.param.byval({ i8, i8 }* byval({ i8, i8 }))
|
||||
; CHECK: declare void @f.param.byval({ i8, i8 }* byval({ i8, i8 }))
|
||||
declare void @f.param.inalloca(i8* inalloca)
|
||||
; CHECK: declare void @f.param.inalloca(i8* inalloca)
|
||||
; CHECK: declare void @f.param.inalloca(i8* inalloca(i8))
|
||||
declare void @f.param.sret(i8* sret(i8))
|
||||
; CHECK: declare void @f.param.sret(i8* sret(i8))
|
||||
declare void @f.param.noalias(i8* noalias)
|
||||
@ -1182,7 +1182,7 @@ exit:
|
||||
|
||||
define void @instructions.call_musttail(i8* inalloca %val) {
|
||||
musttail call void @f.param.inalloca(i8* inalloca %val)
|
||||
; CHECK: musttail call void @f.param.inalloca(i8* inalloca %val)
|
||||
; CHECK: musttail call void @f.param.inalloca(i8* inalloca(i8) %val)
|
||||
|
||||
ret void
|
||||
}
|
||||
|
@ -506,7 +506,7 @@ declare void @f.param.inreg(i8 inreg)
|
||||
declare void @f.param.byval({ i8, i8 }* byval({ i8, i8 }))
|
||||
; CHECK: declare void @f.param.byval({ i8, i8 }* byval({ i8, i8 }))
|
||||
declare void @f.param.inalloca(i8* inalloca)
|
||||
; CHECK: declare void @f.param.inalloca(i8* inalloca)
|
||||
; CHECK: declare void @f.param.inalloca(i8* inalloca(i8))
|
||||
declare void @f.param.sret(i8* sret(i8))
|
||||
; CHECK: declare void @f.param.sret(i8* sret(i8))
|
||||
declare void @f.param.noalias(i8* noalias)
|
||||
@ -1253,7 +1253,7 @@ exit:
|
||||
|
||||
define void @instructions.call_musttail(i8* inalloca %val) {
|
||||
musttail call void @f.param.inalloca(i8* inalloca %val)
|
||||
; CHECK: musttail call void @f.param.inalloca(i8* inalloca %val)
|
||||
; CHECK: musttail call void @f.param.inalloca(i8* inalloca(i8) %val)
|
||||
|
||||
ret void
|
||||
}
|
||||
|
@ -506,7 +506,7 @@ declare void @f.param.inreg(i8 inreg)
|
||||
declare void @f.param.byval({ i8, i8 }* byval({ i8, i8 }))
|
||||
; CHECK: declare void @f.param.byval({ i8, i8 }* byval({ i8, i8 }))
|
||||
declare void @f.param.inalloca(i8* inalloca)
|
||||
; CHECK: declare void @f.param.inalloca(i8* inalloca)
|
||||
; CHECK: declare void @f.param.inalloca(i8* inalloca(i8))
|
||||
declare void @f.param.sret(i8* sret(i8))
|
||||
; CHECK: declare void @f.param.sret(i8* sret(i8))
|
||||
declare void @f.param.noalias(i8* noalias)
|
||||
@ -1253,7 +1253,7 @@ exit:
|
||||
|
||||
define void @instructions.call_musttail(i8* inalloca %val) {
|
||||
musttail call void @f.param.inalloca(i8* inalloca %val)
|
||||
; CHECK: musttail call void @f.param.inalloca(i8* inalloca %val)
|
||||
; CHECK: musttail call void @f.param.inalloca(i8* inalloca(i8) %val)
|
||||
|
||||
ret void
|
||||
}
|
||||
|
@ -510,7 +510,7 @@ declare void @f.param.inreg(i8 inreg)
|
||||
declare void @f.param.byval({ i8, i8 }* byval({ i8, i8 }))
|
||||
; CHECK: declare void @f.param.byval({ i8, i8 }* byval({ i8, i8 }))
|
||||
declare void @f.param.inalloca(i8* inalloca)
|
||||
; CHECK: declare void @f.param.inalloca(i8* inalloca)
|
||||
; CHECK: declare void @f.param.inalloca(i8* inalloca(i8))
|
||||
declare void @f.param.sret(i8* sret(i8))
|
||||
; CHECK: declare void @f.param.sret(i8* sret(i8))
|
||||
declare void @f.param.noalias(i8* noalias)
|
||||
@ -1265,7 +1265,7 @@ exit:
|
||||
|
||||
define void @instructions.call_musttail(i8* inalloca %val) {
|
||||
musttail call void @f.param.inalloca(i8* inalloca %val)
|
||||
; CHECK: musttail call void @f.param.inalloca(i8* inalloca %val)
|
||||
; CHECK: musttail call void @f.param.inalloca(i8* inalloca(i8) %val)
|
||||
|
||||
ret void
|
||||
}
|
||||
|
@ -517,7 +517,7 @@ declare void @f.param.inreg(i8 inreg)
|
||||
declare void @f.param.byval({ i8, i8 }* byval({ i8, i8 }))
|
||||
; CHECK: declare void @f.param.byval({ i8, i8 }* byval({ i8, i8 }))
|
||||
declare void @f.param.inalloca(i8* inalloca)
|
||||
; CHECK: declare void @f.param.inalloca(i8* inalloca)
|
||||
; CHECK: declare void @f.param.inalloca(i8* inalloca(i8))
|
||||
declare void @f.param.sret(i8* sret(i8))
|
||||
; CHECK: declare void @f.param.sret(i8* sret(i8))
|
||||
declare void @f.param.noalias(i8* noalias)
|
||||
@ -1276,7 +1276,7 @@ exit:
|
||||
|
||||
define void @instructions.call_musttail(i8* inalloca %val) {
|
||||
musttail call void @f.param.inalloca(i8* inalloca %val)
|
||||
; CHECK: musttail call void @f.param.inalloca(i8* inalloca %val)
|
||||
; CHECK: musttail call void @f.param.inalloca(i8* inalloca(i8) %val)
|
||||
|
||||
ret void
|
||||
}
|
||||
|
@ -532,8 +532,8 @@ declare void @f.param.inreg(i8 inreg)
|
||||
; CHECK: declare void @f.param.inreg(i8 inreg)
|
||||
declare void @f.param.byval({ i8, i8 }* byval({ i8, i8 }))
|
||||
; CHECK: declare void @f.param.byval({ i8, i8 }* byval({ i8, i8 }))
|
||||
declare void @f.param.inalloca(i8* inalloca)
|
||||
; CHECK: declare void @f.param.inalloca(i8* inalloca)
|
||||
declare void @f.param.inalloca(i8* inalloca(i8))
|
||||
; CHECK: declare void @f.param.inalloca(i8* inalloca(i8))
|
||||
declare void @f.param.sret(i8* sret(i8))
|
||||
; CHECK: declare void @f.param.sret(i8* sret(i8))
|
||||
declare void @f.param.noalias(i8* noalias)
|
||||
@ -1520,9 +1520,9 @@ exit:
|
||||
ret void
|
||||
}
|
||||
|
||||
define void @instructions.call_musttail(i8* inalloca %val) {
|
||||
musttail call void @f.param.inalloca(i8* inalloca %val)
|
||||
; CHECK: musttail call void @f.param.inalloca(i8* inalloca %val)
|
||||
define void @instructions.call_musttail(i8* inalloca(i8) %val) {
|
||||
musttail call void @f.param.inalloca(i8* inalloca(i8) %val)
|
||||
; CHECK: musttail call void @f.param.inalloca(i8* inalloca(i8) %val)
|
||||
|
||||
ret void
|
||||
}
|
||||
|
7
test/Bitcode/inalloca-upgrade.test
Normal file
7
test/Bitcode/inalloca-upgrade.test
Normal file
@ -0,0 +1,7 @@
|
||||
RUN: llvm-dis %p/Inputs/inalloca-upgrade.bc -o - | FileCheck %s
|
||||
|
||||
Make sure we upgrade old-style IntAttribute inalloca records to a
|
||||
fully typed version correctly.
|
||||
|
||||
CHECK: call void @bar({ i32*, i8 }* inalloca({ i32*, i8 }) %ptr)
|
||||
CHECK: invoke void @bar({ i32*, i8 }* inalloca({ i32*, i8 }) %ptr)
|
@ -3,17 +3,17 @@
|
||||
|
||||
; inalloca should roundtrip.
|
||||
|
||||
define void @foo(i32* inalloca %args) {
|
||||
define void @foo(i32* inalloca(i32) %args) {
|
||||
ret void
|
||||
}
|
||||
; CHECK-LABEL: define void @foo(i32* inalloca %args)
|
||||
; CHECK-LABEL: define void @foo(i32* inalloca(i32) %args)
|
||||
|
||||
define void @bar() {
|
||||
; Use the maximum alignment, since we stuff our bit with alignment.
|
||||
%args = alloca inalloca i32, align 536870912
|
||||
call void @foo(i32* inalloca %args)
|
||||
call void @foo(i32* inalloca(i32) %args)
|
||||
ret void
|
||||
}
|
||||
; CHECK-LABEL: define void @bar() {
|
||||
; CHECK: %args = alloca inalloca i32, align 536870912
|
||||
; CHECK: call void @foo(i32* inalloca %args)
|
||||
; CHECK: call void @foo(i32* inalloca(i32) %args)
|
||||
|
@ -232,7 +232,7 @@ entry:
|
||||
; CHECK: retl
|
||||
|
||||
|
||||
define void @avoid_inalloca(i32* inalloca %x) {
|
||||
define void @avoid_inalloca(i32* inalloca(i32) %x) {
|
||||
entry:
|
||||
%x.p.p = alloca i32*
|
||||
store i32* %x, i32** %x.p.p
|
||||
|
@ -25,7 +25,7 @@ entry:
|
||||
to label %invoke.cont unwind label %ehcleanup
|
||||
|
||||
invoke.cont: ; preds = %entry
|
||||
call void @takes_two(<{ %struct.A, %struct.A }>* inalloca nonnull %argmem)
|
||||
call void @takes_two(<{ %struct.A, %struct.A }>* inalloca(<{ %struct.A, %struct.A }>) nonnull %argmem)
|
||||
ret void
|
||||
|
||||
ehcleanup: ; preds = %entry
|
||||
@ -57,7 +57,7 @@ ehcleanup: ; preds = %entry
|
||||
; CHECK: addl $8, %esp
|
||||
; CHECK: retl
|
||||
|
||||
declare void @takes_two(<{ %struct.A, %struct.A }>* inalloca) #0
|
||||
declare void @takes_two(<{ %struct.A, %struct.A }>* inalloca(<{ %struct.A, %struct.A }>)) #0
|
||||
|
||||
declare x86_thiscallcc %struct.A* @"\01??0A@@QAE@XZ"(%struct.A* returned) #0
|
||||
|
||||
|
@ -4,7 +4,7 @@
|
||||
|
||||
%frame = type { %Foo, i32, %Foo }
|
||||
|
||||
declare void @f(%frame* inalloca %a)
|
||||
declare void @f(%frame* inalloca(%frame) %a)
|
||||
|
||||
declare void @Foo_ctor(%Foo* %this)
|
||||
|
||||
@ -28,7 +28,7 @@ entry:
|
||||
; CHECK-NEXT: pushl
|
||||
; CHECK-NEXT: calll _Foo_ctor
|
||||
; CHECK: addl $4, %esp
|
||||
call void @f(%frame* inalloca %args)
|
||||
call void @f(%frame* inalloca(%frame) %args)
|
||||
; CHECK: calll _f
|
||||
ret void
|
||||
}
|
||||
|
@ -9,7 +9,7 @@ declare void @llvm.stackrestore(i8*)
|
||||
declare i8* @llvm.stacksave()
|
||||
declare void @begin(%Iter* sret(%Iter))
|
||||
declare void @plus(%Iter* sret(%Iter), %Iter*, i32)
|
||||
declare void @reverse(%frame.reverse* inalloca align 4)
|
||||
declare void @reverse(%frame.reverse* inalloca(%frame.reverse) align 4)
|
||||
|
||||
define i32 @main() personality i32 (...)* @pers {
|
||||
%temp.lvalue = alloca %Iter
|
||||
@ -42,7 +42,7 @@ invoke.cont:
|
||||
; CHECK: pushl %[[beg]]
|
||||
; CHECK: calll _begin
|
||||
|
||||
invoke void @reverse(%frame.reverse* inalloca align 4 %rev_args)
|
||||
invoke void @reverse(%frame.reverse* inalloca(%frame.reverse) align 4 %rev_args)
|
||||
to label %invoke.cont5 unwind label %lpad
|
||||
|
||||
invoke.cont5: ; preds = %invoke.cont
|
||||
|
@ -4,11 +4,11 @@
|
||||
; This will compile successfully on x86 but not x86_64, because %b will become a
|
||||
; register parameter.
|
||||
|
||||
declare x86_thiscallcc i32 @f(i32 %a, i32* inalloca %b)
|
||||
declare x86_thiscallcc i32 @f(i32 %a, i32* inalloca(i32) %b)
|
||||
define void @g() {
|
||||
%b = alloca inalloca i32
|
||||
store i32 2, i32* %b
|
||||
call x86_thiscallcc i32 @f(i32 0, i32* inalloca %b)
|
||||
call x86_thiscallcc i32 @f(i32 0, i32* inalloca(i32) %b)
|
||||
ret void
|
||||
}
|
||||
|
||||
|
@ -2,7 +2,7 @@
|
||||
|
||||
%Foo = type { i32, i32 }
|
||||
|
||||
declare x86_stdcallcc void @f(%Foo* inalloca %a)
|
||||
declare x86_stdcallcc void @f(%Foo* inalloca(%Foo) %a)
|
||||
declare x86_stdcallcc void @i(i32 %a)
|
||||
|
||||
define void @g() {
|
||||
@ -17,7 +17,7 @@ define void @g() {
|
||||
; CHECK: movl %esp, %eax
|
||||
; CHECK: movl $13, (%eax)
|
||||
; CHECK: movl $42, 4(%eax)
|
||||
call x86_stdcallcc void @f(%Foo* inalloca %b)
|
||||
call x86_stdcallcc void @f(%Foo* inalloca(%Foo) %b)
|
||||
; CHECK: calll _f@8
|
||||
; CHECK-NOT: %esp
|
||||
; CHECK: pushl
|
||||
|
@ -2,7 +2,7 @@
|
||||
|
||||
%Foo = type { i32, i32 }
|
||||
|
||||
declare void @f(%Foo* inalloca %b)
|
||||
declare void @f(%Foo* inalloca(%Foo) %b)
|
||||
|
||||
define void @a() {
|
||||
; CHECK-LABEL: _a:
|
||||
@ -17,12 +17,12 @@ entry:
|
||||
; CHECK: movl %esp, %eax
|
||||
; CHECK: movl $13, (%eax)
|
||||
; CHECK: movl $42, 4(%eax)
|
||||
call void @f(%Foo* inalloca %b)
|
||||
call void @f(%Foo* inalloca(%Foo) %b)
|
||||
; CHECK: calll _f
|
||||
ret void
|
||||
}
|
||||
|
||||
declare void @inreg_with_inalloca(i32 inreg %a, %Foo* inalloca %b)
|
||||
declare void @inreg_with_inalloca(i32 inreg %a, %Foo* inalloca(%Foo) %b)
|
||||
|
||||
define void @b() {
|
||||
; CHECK-LABEL: _b:
|
||||
@ -37,13 +37,13 @@ entry:
|
||||
; CHECK: movl %esp, %eax
|
||||
; CHECK: movl $13, (%eax)
|
||||
; CHECK: movl $42, 4(%eax)
|
||||
call void @inreg_with_inalloca(i32 inreg 1, %Foo* inalloca %b)
|
||||
call void @inreg_with_inalloca(i32 inreg 1, %Foo* inalloca(%Foo) %b)
|
||||
; CHECK: movl $1, %eax
|
||||
; CHECK: calll _inreg_with_inalloca
|
||||
ret void
|
||||
}
|
||||
|
||||
declare x86_thiscallcc void @thiscall_with_inalloca(i8* %a, %Foo* inalloca %b)
|
||||
declare x86_thiscallcc void @thiscall_with_inalloca(i8* %a, %Foo* inalloca(%Foo) %b)
|
||||
|
||||
define void @c() {
|
||||
; CHECK-LABEL: _c:
|
||||
@ -58,7 +58,7 @@ entry:
|
||||
; CHECK: movl %esp, %eax
|
||||
; CHECK-DAG: movl $13, (%eax)
|
||||
; CHECK-DAG: movl $42, 4(%eax)
|
||||
call x86_thiscallcc void @thiscall_with_inalloca(i8* null, %Foo* inalloca %b)
|
||||
call x86_thiscallcc void @thiscall_with_inalloca(i8* null, %Foo* inalloca(%Foo) %b)
|
||||
; CHECK-DAG: xorl %ecx, %ecx
|
||||
; CHECK: calll _thiscall_with_inalloca
|
||||
ret void
|
||||
|
@ -15,7 +15,7 @@ declare void @eightparams(i32 %a, i32 %b, i32 %c, i32 %d, i32 %e, i32 %f, i32 %g
|
||||
declare void @eightparams16(i16 %a, i16 %b, i16 %c, i16 %d, i16 %e, i16 %f, i16 %g, i16 %h)
|
||||
declare void @eightparams64(i64 %a, i64 %b, i64 %c, i64 %d, i64 %e, i64 %f, i64 %g, i64 %h)
|
||||
declare void @struct(%struct.s* byval(%struct.s) %a, i32 %b, i32 %c, i32 %d)
|
||||
declare void @inalloca(<{ %struct.s }>* inalloca)
|
||||
declare void @inalloca(<{ %struct.s }>* inalloca(<{ %struct.s }>))
|
||||
|
||||
declare i8* @llvm.stacksave()
|
||||
declare void @llvm.stackrestore(i8*)
|
||||
|
@ -11,10 +11,10 @@ target triple = "i386-pc-windows-msvc19.16.0"
|
||||
; 20 bytes of memory.
|
||||
%struct.Args = type { i32, i32, i32, i32, i32 }
|
||||
|
||||
declare dso_local x86_thiscallcc void @methodWithVtorDisp(i8* nocapture readonly, <{ %struct.Args }>* inalloca)
|
||||
declare dso_local x86_thiscallcc void @methodWithVtorDisp(i8* nocapture readonly, <{ %struct.Args }>* inalloca(<{ %struct.Args }>))
|
||||
|
||||
; Function Attrs: nounwind optsize
|
||||
define dso_local x86_thiscallcc void @methodWithVtorDisp_thunk(i8* %0, <{ %struct.Args }>* inalloca %1) #0 {
|
||||
define dso_local x86_thiscallcc void @methodWithVtorDisp_thunk(i8* %0, <{ %struct.Args }>* inalloca(<{ %struct.Args }>) %1) #0 {
|
||||
; CHECK-LABEL: methodWithVtorDisp_thunk:
|
||||
; CHECK: # %bb.0:
|
||||
; CHECK-NEXT: pushl %esi
|
||||
@ -34,7 +34,7 @@ define dso_local x86_thiscallcc void @methodWithVtorDisp_thunk(i8* %0, <{ %struc
|
||||
%7 = getelementptr i8, i8* %0, i32 %6
|
||||
%8 = call i8* @llvm.returnaddress(i32 0)
|
||||
call void @__cyg_profile_func_exit(i8* bitcast (void (i8*, <{ %struct.Args }>*)* @methodWithVtorDisp_thunk to i8*), i8* %8)
|
||||
musttail call x86_thiscallcc void @methodWithVtorDisp(i8* %7, <{ %struct.Args }>* inalloca nonnull %1)
|
||||
musttail call x86_thiscallcc void @methodWithVtorDisp(i8* %7, <{ %struct.Args }>* inalloca(<{ %struct.Args }>) nonnull %1)
|
||||
ret void
|
||||
}
|
||||
|
||||
|
@ -42,13 +42,13 @@ entry:
|
||||
; CHECK-NOT: mov %{{.*}}, {{.*(.*esp.*)}}
|
||||
; CHECK: jmpl
|
||||
; CHECK-NOT: ret
|
||||
define x86_thiscallcc i32 @g_thunk(%struct.B* %this, <{ %struct.A, i32, %struct.A }>* inalloca) {
|
||||
define x86_thiscallcc i32 @g_thunk(%struct.B* %this, <{ %struct.A, i32, %struct.A }>* inalloca(<{ %struct.A, i32, %struct.A }>)) {
|
||||
entry:
|
||||
%1 = bitcast %struct.B* %this to i32 (%struct.B*, <{ %struct.A, i32, %struct.A }>*)***
|
||||
%vtable = load i32 (%struct.B*, <{ %struct.A, i32, %struct.A }>*)**, i32 (%struct.B*, <{ %struct.A, i32, %struct.A }>*)*** %1
|
||||
%vfn = getelementptr inbounds i32 (%struct.B*, <{ %struct.A, i32, %struct.A }>*)*, i32 (%struct.B*, <{ %struct.A, i32, %struct.A }>*)** %vtable, i32 1
|
||||
%2 = load i32 (%struct.B*, <{ %struct.A, i32, %struct.A }>*)*, i32 (%struct.B*, <{ %struct.A, i32, %struct.A }>*)** %vfn
|
||||
%3 = musttail call x86_thiscallcc i32 %2(%struct.B* %this, <{ %struct.A, i32, %struct.A }>* inalloca %0)
|
||||
%3 = musttail call x86_thiscallcc i32 %2(%struct.B* %this, <{ %struct.A, i32, %struct.A }>* inalloca(<{ %struct.A, i32, %struct.A }>) %0)
|
||||
ret i32 %3
|
||||
}
|
||||
|
||||
@ -71,13 +71,13 @@ entry:
|
||||
; CHECK: jmpl
|
||||
; CHECK-NOT: mov %{{.*}}, {{.*(.*esp.*)}}
|
||||
; CHECK-NOT: ret
|
||||
define x86_thiscallcc void @h_thunk(%struct.B* %this, <{ %struct.A, i32, %struct.A }>* inalloca) {
|
||||
define x86_thiscallcc void @h_thunk(%struct.B* %this, <{ %struct.A, i32, %struct.A }>* inalloca(<{ %struct.A, i32, %struct.A }>)) {
|
||||
entry:
|
||||
%1 = bitcast %struct.B* %this to void (%struct.B*, <{ %struct.A, i32, %struct.A }>*)***
|
||||
%vtable = load void (%struct.B*, <{ %struct.A, i32, %struct.A }>*)**, void (%struct.B*, <{ %struct.A, i32, %struct.A }>*)*** %1
|
||||
%vfn = getelementptr inbounds void (%struct.B*, <{ %struct.A, i32, %struct.A }>*)*, void (%struct.B*, <{ %struct.A, i32, %struct.A }>*)** %vtable, i32 2
|
||||
%2 = load void (%struct.B*, <{ %struct.A, i32, %struct.A }>*)*, void (%struct.B*, <{ %struct.A, i32, %struct.A }>*)** %vfn
|
||||
musttail call x86_thiscallcc void %2(%struct.B* %this, <{ %struct.A, i32, %struct.A }>* inalloca %0)
|
||||
musttail call x86_thiscallcc void %2(%struct.B* %this, <{ %struct.A, i32, %struct.A }>* inalloca(<{ %struct.A, i32, %struct.A }>) %0)
|
||||
ret void
|
||||
}
|
||||
|
||||
@ -99,13 +99,13 @@ entry:
|
||||
; CHECK-NOT: mov %{{.*}}, {{.*(.*esp.*)}}
|
||||
; CHECK: jmpl
|
||||
; CHECK-NOT: ret
|
||||
define x86_thiscallcc %struct.A* @i_thunk(%struct.B* %this, <{ %struct.A*, %struct.A, i32, %struct.A }>* inalloca) {
|
||||
define x86_thiscallcc %struct.A* @i_thunk(%struct.B* %this, <{ %struct.A*, %struct.A, i32, %struct.A }>* inalloca(<{ %struct.A*, %struct.A, i32, %struct.A }>)) {
|
||||
entry:
|
||||
%1 = bitcast %struct.B* %this to %struct.A* (%struct.B*, <{ %struct.A*, %struct.A, i32, %struct.A }>*)***
|
||||
%vtable = load %struct.A* (%struct.B*, <{ %struct.A*, %struct.A, i32, %struct.A }>*)**, %struct.A* (%struct.B*, <{ %struct.A*, %struct.A, i32, %struct.A }>*)*** %1
|
||||
%vfn = getelementptr inbounds %struct.A* (%struct.B*, <{ %struct.A*, %struct.A, i32, %struct.A }>*)*, %struct.A* (%struct.B*, <{ %struct.A*, %struct.A, i32, %struct.A }>*)** %vtable, i32 3
|
||||
%2 = load %struct.A* (%struct.B*, <{ %struct.A*, %struct.A, i32, %struct.A }>*)*, %struct.A* (%struct.B*, <{ %struct.A*, %struct.A, i32, %struct.A }>*)** %vfn
|
||||
%3 = musttail call x86_thiscallcc %struct.A* %2(%struct.B* %this, <{ %struct.A*, %struct.A, i32, %struct.A }>* inalloca %0)
|
||||
%3 = musttail call x86_thiscallcc %struct.A* %2(%struct.B* %this, <{ %struct.A*, %struct.A, i32, %struct.A }>* inalloca(<{ %struct.A*, %struct.A, i32, %struct.A }>) %0)
|
||||
ret %struct.A* %3
|
||||
}
|
||||
|
||||
@ -140,7 +140,7 @@ entry:
|
||||
; CHECK-NOT: mov %{{.*}}, {{.*(.*esp.*)}}
|
||||
; CHECK: jmpl
|
||||
; CHECK-NOT: ret
|
||||
define x86_stdcallcc i32 @stdcall_thunk(<{ %struct.B*, %struct.A }>* inalloca) {
|
||||
define x86_stdcallcc i32 @stdcall_thunk(<{ %struct.B*, %struct.A }>* inalloca(<{ %struct.B*, %struct.A }>)) {
|
||||
entry:
|
||||
%this_ptr = getelementptr inbounds <{ %struct.B*, %struct.A }>, <{ %struct.B*, %struct.A }>* %0, i32 0, i32 0
|
||||
%this = load %struct.B*, %struct.B** %this_ptr
|
||||
@ -148,7 +148,7 @@ entry:
|
||||
%vtable = load i32 (<{ %struct.B*, %struct.A }>*)**, i32 (<{ %struct.B*, %struct.A }>*)*** %1
|
||||
%vfn = getelementptr inbounds i32 (<{ %struct.B*, %struct.A }>*)*, i32 (<{ %struct.B*, %struct.A }>*)** %vtable, i32 1
|
||||
%2 = load i32 (<{ %struct.B*, %struct.A }>*)*, i32 (<{ %struct.B*, %struct.A }>*)** %vfn
|
||||
%3 = musttail call x86_stdcallcc i32 %2(<{ %struct.B*, %struct.A }>* inalloca %0)
|
||||
%3 = musttail call x86_stdcallcc i32 %2(<{ %struct.B*, %struct.A }>* inalloca(<{ %struct.B*, %struct.A }>) %0)
|
||||
ret i32 %3
|
||||
}
|
||||
|
||||
@ -172,13 +172,13 @@ entry:
|
||||
; CHECK-NOT: mov %{{.*}}, {{.*(.*esp.*)}}
|
||||
; CHECK: jmpl
|
||||
; CHECK-NOT: ret
|
||||
define x86_fastcallcc i32 @fastcall_thunk(%struct.B* inreg %this, <{ %struct.A }>* inalloca) {
|
||||
define x86_fastcallcc i32 @fastcall_thunk(%struct.B* inreg %this, <{ %struct.A }>* inalloca(<{ %struct.A }>)) {
|
||||
entry:
|
||||
%1 = bitcast %struct.B* %this to i32 (%struct.B*, <{ %struct.A }>*)***
|
||||
%vtable = load i32 (%struct.B*, <{ %struct.A }>*)**, i32 (%struct.B*, <{ %struct.A }>*)*** %1
|
||||
%vfn = getelementptr inbounds i32 (%struct.B*, <{ %struct.A }>*)*, i32 (%struct.B*, <{ %struct.A }>*)** %vtable, i32 1
|
||||
%2 = load i32 (%struct.B*, <{ %struct.A }>*)*, i32 (%struct.B*, <{ %struct.A }>*)** %vfn
|
||||
%3 = musttail call x86_fastcallcc i32 %2(%struct.B* inreg %this, <{ %struct.A }>* inalloca %0)
|
||||
%3 = musttail call x86_fastcallcc i32 %2(%struct.B* inreg %this, <{ %struct.A }>* inalloca(<{ %struct.A }>) %0)
|
||||
ret i32 %3
|
||||
}
|
||||
|
||||
|
@ -21,14 +21,14 @@ declare x86_thiscallcc i32 @t2_callee(i8* %this, i32 %a)
|
||||
|
||||
; CHECK-LABEL: t3:
|
||||
; CHECK: jmp {{_?}}t3_callee
|
||||
define x86_thiscallcc i8* @t3(i8* %this, <{ i8*, i32 }>* inalloca %args) {
|
||||
define x86_thiscallcc i8* @t3(i8* %this, <{ i8*, i32 }>* inalloca(<{ i8*, i32 }>) %args) {
|
||||
%adj = getelementptr i8, i8* %this, i32 4
|
||||
%a_ptr = getelementptr <{ i8*, i32 }>, <{ i8*, i32 }>* %args, i32 0, i32 1
|
||||
store i32 0, i32* %a_ptr
|
||||
%rv = musttail call x86_thiscallcc i8* @t3_callee(i8* %adj, <{ i8*, i32 }>* inalloca %args)
|
||||
%rv = musttail call x86_thiscallcc i8* @t3_callee(i8* %adj, <{ i8*, i32 }>* inalloca(<{ i8*, i32 }>) %args)
|
||||
ret i8* %rv
|
||||
}
|
||||
declare x86_thiscallcc i8* @t3_callee(i8* %this, <{ i8*, i32 }>* inalloca %args);
|
||||
declare x86_thiscallcc i8* @t3_callee(i8* %this, <{ i8*, i32 }>* inalloca(<{ i8*, i32 }>) %args);
|
||||
|
||||
; CHECK-LABEL: t4:
|
||||
; CHECK: jmp {{_?}}t4_callee
|
||||
|
@ -25,7 +25,7 @@ bb1:
|
||||
br label %bb2
|
||||
|
||||
bb2:
|
||||
call void @inalloca_params(<{ %struct.S }>* inalloca nonnull %argmem)
|
||||
call void @inalloca_params(<{ %struct.S }>* inalloca(<{ %struct.S }>) nonnull %argmem)
|
||||
ret void
|
||||
}
|
||||
|
||||
@ -39,7 +39,7 @@ bb2:
|
||||
; CHECK: popl %ebp
|
||||
; CHECK: retl
|
||||
|
||||
declare void @inalloca_params(<{ %struct.S }>* inalloca)
|
||||
declare void @inalloca_params(<{ %struct.S }>* inalloca(<{ %struct.S }>))
|
||||
|
||||
declare i32 @doSomething(i32, i32*)
|
||||
|
||||
|
@ -24,7 +24,7 @@ entry:
|
||||
; CHECK: calll _tail_std@4
|
||||
; CHECK: retl $4
|
||||
|
||||
define x86_thiscallcc void @inalloca(i32* %this, i32* inalloca %args) {
|
||||
define x86_thiscallcc void @inalloca(i32* %this, i32* inalloca(i32) %args) {
|
||||
entry:
|
||||
%val = load i32, i32* %args
|
||||
store i32 0, i32* %args
|
||||
|
@ -5,7 +5,7 @@ target triple = "i686-pc-windows-msvc18.0.0"
|
||||
%struct.T = type { i64, [3 x i32] }
|
||||
|
||||
; Function Attrs: nounwind optsize
|
||||
define void @f(i8* %p, i8* %q, i32* inalloca nocapture %unused) #0 {
|
||||
define void @f(i8* %p, i8* %q, i32* inalloca(i32) nocapture %unused) #0 {
|
||||
entry:
|
||||
%g = alloca %struct.T, align 8
|
||||
%r = alloca i32, align 8
|
||||
@ -25,7 +25,7 @@ while.end: ; preds = %while.body
|
||||
ret void
|
||||
}
|
||||
|
||||
define void @f_pgso(i8* %p, i8* %q, i32* inalloca nocapture %unused) !prof !14 {
|
||||
define void @f_pgso(i8* %p, i8* %q, i32* inalloca(i32) nocapture %unused) !prof !14 {
|
||||
entry:
|
||||
%g = alloca %struct.T, align 8
|
||||
%r = alloca i32, align 8
|
||||
|
@ -109,7 +109,7 @@ target triple = "i386-pc-windows-msvc19.10.24728"
|
||||
%struct.NonTrivial = type { i32 }
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define void @f(<{ %struct.NonTrivial, i32, i32, i32 }>* inalloca) local_unnamed_addr #0 !dbg !7 {
|
||||
define void @f(<{ %struct.NonTrivial, i32, i32, i32 }>* inalloca(<{ %struct.NonTrivial, i32, i32, i32 }>)) local_unnamed_addr #0 !dbg !7 {
|
||||
entry:
|
||||
%a = getelementptr inbounds <{ %struct.NonTrivial, i32, i32, i32 }>, <{ %struct.NonTrivial, i32, i32, i32 }>* %0, i32 0, i32 0
|
||||
%b = getelementptr inbounds <{ %struct.NonTrivial, i32, i32, i32 }>, <{ %struct.NonTrivial, i32, i32, i32 }>* %0, i32 0, i32 1
|
||||
|
@ -31,8 +31,8 @@ define void @has_inalloca() uwtable sanitize_address {
|
||||
entry:
|
||||
%t = alloca inalloca i32
|
||||
store i32 42, i32* %t
|
||||
call void @pass_inalloca(i32* inalloca %t)
|
||||
call void @pass_inalloca(i32* inalloca(i32) %t)
|
||||
ret void
|
||||
}
|
||||
|
||||
declare void @pass_inalloca(i32* inalloca)
|
||||
declare void @pass_inalloca(i32* inalloca(i32))
|
||||
|
13
test/Linker/Inputs/inalloca-type-input.ll
Normal file
13
test/Linker/Inputs/inalloca-type-input.ll
Normal file
@ -0,0 +1,13 @@
|
||||
%a = type { i64 }
|
||||
%struct = type { i32, i8 }
|
||||
|
||||
define void @g(%a* inalloca(%a)) {
|
||||
ret void
|
||||
}
|
||||
|
||||
declare void @baz(%struct* inalloca(%struct))
|
||||
|
||||
define void @foo(%struct* inalloca(%struct) %a) {
|
||||
call void @baz(%struct* inalloca(%struct) %a)
|
||||
ret void
|
||||
}
|
25
test/Linker/inalloca-types.ll
Normal file
25
test/Linker/inalloca-types.ll
Normal file
@ -0,0 +1,25 @@
|
||||
; RUN: llvm-link %s %p/Inputs/inalloca-type-input.ll -S | FileCheck %s
|
||||
|
||||
%a = type { i64 }
|
||||
%struct = type { i32, i8 }
|
||||
|
||||
; CHECK-LABEL: define void @f(%a* inalloca(%a) %0)
|
||||
define void @f(%a* inalloca(%a)) {
|
||||
ret void
|
||||
}
|
||||
|
||||
; CHECK-LABEL: define void @bar(
|
||||
; CHECK: call void @foo(%struct* inalloca(%struct) %ptr)
|
||||
define void @bar() {
|
||||
%ptr = alloca inalloca %struct
|
||||
call void @foo(%struct* inalloca(%struct) %ptr)
|
||||
ret void
|
||||
}
|
||||
|
||||
; CHECK-LABEL: define void @g(%a* inalloca(%a) %0)
|
||||
|
||||
; CHECK-LABEL: define void @foo(%struct* inalloca(%struct) %a)
|
||||
; CHECK-NEXT: call void @baz(%struct* inalloca(%struct) %a)
|
||||
declare void @foo(%struct* inalloca(%struct) %a)
|
||||
|
||||
; CHECK: declare void @baz(%struct* inalloca(%struct))
|
@ -12,25 +12,25 @@ target triple = "i386-pc-windows-msvc19.11.0"
|
||||
|
||||
%struct.a = type { i8 }
|
||||
|
||||
define internal x86_thiscallcc void @internalfun(%struct.a* %this, <{ %struct.a }>* inalloca) {
|
||||
define internal x86_thiscallcc void @internalfun(%struct.a* %this, <{ %struct.a }>* inalloca(<{ %struct.a }>)) {
|
||||
; ARGPROMOTION-LABEL: define {{[^@]+}}@internalfun
|
||||
; ARGPROMOTION-SAME: (%struct.a* [[THIS:%.*]], <{ [[STRUCT_A:%.*]] }>* inalloca [[TMP0:%.*]])
|
||||
; ARGPROMOTION-SAME: (%struct.a* [[THIS:%.*]], <{ [[STRUCT_A:%.*]] }>* inalloca(<{ [[STRUCT_A]] }>) [[TMP0:%.*]]) {
|
||||
; ARGPROMOTION-NEXT: entry:
|
||||
; ARGPROMOTION-NEXT: [[A:%.*]] = getelementptr inbounds <{ [[STRUCT_A]] }>, <{ [[STRUCT_A]] }>* [[TMP0]], i32 0, i32 0
|
||||
; ARGPROMOTION-NEXT: [[ARGMEM:%.*]] = alloca inalloca <{ [[STRUCT_A]] }>, align 4
|
||||
; ARGPROMOTION-NEXT: [[TMP1:%.*]] = getelementptr inbounds <{ [[STRUCT_A]] }>, <{ [[STRUCT_A]] }>* [[ARGMEM]], i32 0, i32 0
|
||||
; ARGPROMOTION-NEXT: [[CALL:%.*]] = call x86_thiscallcc %struct.a* @copy_ctor(%struct.a* [[TMP1]], %struct.a* dereferenceable(1) [[A]])
|
||||
; ARGPROMOTION-NEXT: call void @ext(<{ [[STRUCT_A]] }>* inalloca [[ARGMEM]])
|
||||
; ARGPROMOTION-NEXT: call void @ext(<{ [[STRUCT_A]] }>* inalloca(<{ [[STRUCT_A]] }>) [[ARGMEM]])
|
||||
; ARGPROMOTION-NEXT: ret void
|
||||
;
|
||||
; GLOBALOPT_ARGPROMOTION-LABEL: define {{[^@]+}}@internalfun
|
||||
; GLOBALOPT_ARGPROMOTION-SAME: (<{ [[STRUCT_A:%.*]] }>* [[TMP0:%.*]]) unnamed_addr
|
||||
; GLOBALOPT_ARGPROMOTION-SAME: (<{ [[STRUCT_A:%.*]] }>* [[TMP0:%.*]]) unnamed_addr {
|
||||
; GLOBALOPT_ARGPROMOTION-NEXT: entry:
|
||||
; GLOBALOPT_ARGPROMOTION-NEXT: [[A:%.*]] = getelementptr inbounds <{ [[STRUCT_A]] }>, <{ [[STRUCT_A]] }>* [[TMP0]], i32 0, i32 0
|
||||
; GLOBALOPT_ARGPROMOTION-NEXT: [[ARGMEM:%.*]] = alloca inalloca <{ [[STRUCT_A]] }>, align 4
|
||||
; GLOBALOPT_ARGPROMOTION-NEXT: [[TMP1:%.*]] = getelementptr inbounds <{ [[STRUCT_A]] }>, <{ [[STRUCT_A]] }>* [[ARGMEM]], i32 0, i32 0
|
||||
; GLOBALOPT_ARGPROMOTION-NEXT: [[CALL:%.*]] = call x86_thiscallcc %struct.a* @copy_ctor(%struct.a* [[TMP1]], %struct.a* dereferenceable(1) [[A]])
|
||||
; GLOBALOPT_ARGPROMOTION-NEXT: call void @ext(<{ [[STRUCT_A]] }>* inalloca [[ARGMEM]])
|
||||
; GLOBALOPT_ARGPROMOTION-NEXT: call void @ext(<{ [[STRUCT_A]] }>* inalloca(<{ [[STRUCT_A]] }>) [[ARGMEM]])
|
||||
; GLOBALOPT_ARGPROMOTION-NEXT: ret void
|
||||
;
|
||||
entry:
|
||||
@ -38,22 +38,22 @@ entry:
|
||||
%argmem = alloca inalloca <{ %struct.a }>, align 4
|
||||
%1 = getelementptr inbounds <{ %struct.a }>, <{ %struct.a }>* %argmem, i32 0, i32 0
|
||||
%call = call x86_thiscallcc %struct.a* @copy_ctor(%struct.a* %1, %struct.a* dereferenceable(1) %a)
|
||||
call void @ext(<{ %struct.a }>* inalloca %argmem)
|
||||
call void @ext(<{ %struct.a }>* inalloca(<{ %struct.a }>) %argmem)
|
||||
ret void
|
||||
}
|
||||
|
||||
; This is here to ensure @internalfun is live.
|
||||
define void @exportedfun(%struct.a* %a) {
|
||||
; ARGPROMOTION-LABEL: define {{[^@]+}}@exportedfun
|
||||
; ARGPROMOTION-SAME: (%struct.a* [[A:%.*]])
|
||||
; ARGPROMOTION-SAME: (%struct.a* [[A:%.*]]) {
|
||||
; ARGPROMOTION-NEXT: [[INALLOCA_SAVE:%.*]] = tail call i8* @llvm.stacksave()
|
||||
; ARGPROMOTION-NEXT: [[ARGMEM:%.*]] = alloca inalloca <{ [[STRUCT_A:%.*]] }>, align 4
|
||||
; ARGPROMOTION-NEXT: call x86_thiscallcc void @internalfun(%struct.a* [[A]], <{ [[STRUCT_A]] }>* inalloca [[ARGMEM]])
|
||||
; ARGPROMOTION-NEXT: call x86_thiscallcc void @internalfun(%struct.a* [[A]], <{ [[STRUCT_A]] }>* inalloca(<{ [[STRUCT_A]] }>) [[ARGMEM]])
|
||||
; ARGPROMOTION-NEXT: call void @llvm.stackrestore(i8* [[INALLOCA_SAVE]])
|
||||
; ARGPROMOTION-NEXT: ret void
|
||||
;
|
||||
; GLOBALOPT_ARGPROMOTION-LABEL: define {{[^@]+}}@exportedfun
|
||||
; GLOBALOPT_ARGPROMOTION-SAME: (%struct.a* [[A:%.*]]) local_unnamed_addr
|
||||
; GLOBALOPT_ARGPROMOTION-SAME: (%struct.a* [[A:%.*]]) local_unnamed_addr {
|
||||
; GLOBALOPT_ARGPROMOTION-NEXT: [[INALLOCA_SAVE:%.*]] = tail call i8* @llvm.stacksave()
|
||||
; GLOBALOPT_ARGPROMOTION-NEXT: [[ARGMEM:%.*]] = alloca inalloca <{ [[STRUCT_A:%.*]] }>, align 4
|
||||
; GLOBALOPT_ARGPROMOTION-NEXT: call fastcc void @internalfun(<{ [[STRUCT_A]] }>* [[ARGMEM]])
|
||||
@ -62,12 +62,12 @@ define void @exportedfun(%struct.a* %a) {
|
||||
;
|
||||
%inalloca.save = tail call i8* @llvm.stacksave()
|
||||
%argmem = alloca inalloca <{ %struct.a }>, align 4
|
||||
call x86_thiscallcc void @internalfun(%struct.a* %a, <{ %struct.a }>* inalloca %argmem)
|
||||
call x86_thiscallcc void @internalfun(%struct.a* %a, <{ %struct.a }>* inalloca(<{ %struct.a }>) %argmem)
|
||||
call void @llvm.stackrestore(i8* %inalloca.save)
|
||||
ret void
|
||||
}
|
||||
|
||||
declare x86_thiscallcc %struct.a* @copy_ctor(%struct.a* returned, %struct.a* dereferenceable(1))
|
||||
declare void @ext(<{ %struct.a }>* inalloca)
|
||||
declare void @ext(<{ %struct.a }>* inalloca(<{ %struct.a }>))
|
||||
declare i8* @llvm.stacksave()
|
||||
declare void @llvm.stackrestore(i8*)
|
||||
|
@ -7,9 +7,9 @@ target datalayout = "E-p:64:64:64-a0:0:8-f32:32:32-f64:64:64-i1:8:8-i8:8:8-i16:1
|
||||
%struct.ss = type { i32, i32 }
|
||||
|
||||
; Argpromote + sroa should change this to passing the two integers by value.
|
||||
define internal i32 @f(%struct.ss* inalloca %s) {
|
||||
define internal i32 @f(%struct.ss* inalloca(%struct.ss) %s) {
|
||||
; CHECK-LABEL: define {{[^@]+}}@f
|
||||
; CHECK-SAME: (i32 [[S_0_0_VAL:%.*]], i32 [[S_0_1_VAL:%.*]]) unnamed_addr
|
||||
; CHECK-SAME: (i32 [[S_0_0_VAL:%.*]], i32 [[S_0_1_VAL:%.*]]) unnamed_addr {
|
||||
; CHECK-NEXT: entry:
|
||||
; CHECK-NEXT: [[R:%.*]] = add i32 [[S_0_0_VAL]], [[S_0_1_VAL]]
|
||||
; CHECK-NEXT: ret i32 [[R]]
|
||||
@ -24,7 +24,7 @@ entry:
|
||||
}
|
||||
|
||||
define i32 @main() {
|
||||
; CHECK-LABEL: define {{[^@]+}}@main() local_unnamed_addr
|
||||
; CHECK-LABEL: define {{[^@]+}}@main() local_unnamed_addr {
|
||||
; CHECK-NEXT: entry:
|
||||
; CHECK-NEXT: [[R:%.*]] = call fastcc i32 @f(i32 1, i32 2)
|
||||
; CHECK-NEXT: ret i32 [[R]]
|
||||
@ -35,14 +35,14 @@ entry:
|
||||
%f1 = getelementptr %struct.ss, %struct.ss* %S, i32 0, i32 1
|
||||
store i32 1, i32* %f0, align 4
|
||||
store i32 2, i32* %f1, align 4
|
||||
%r = call i32 @f(%struct.ss* inalloca %S)
|
||||
%r = call i32 @f(%struct.ss* inalloca(%struct.ss) %S)
|
||||
ret i32 %r
|
||||
}
|
||||
|
||||
; Argpromote can't promote %a because of the icmp use.
|
||||
define internal i1 @g(%struct.ss* %a, %struct.ss* inalloca %b) nounwind {
|
||||
define internal i1 @g(%struct.ss* %a, %struct.ss* inalloca(%struct.ss) %b) nounwind {
|
||||
; CHECK-LABEL: define {{[^@]+}}@g
|
||||
; CHECK-SAME: (%struct.ss* [[A:%.*]], %struct.ss* [[B:%.*]]) unnamed_addr
|
||||
; CHECK-SAME: (%struct.ss* [[A:%.*]], %struct.ss* [[B:%.*]]) unnamed_addr #[[ATTR0:[0-9]+]] {
|
||||
; CHECK-NEXT: entry:
|
||||
; CHECK-NEXT: [[C:%.*]] = icmp eq %struct.ss* [[A]], [[B]]
|
||||
; CHECK-NEXT: ret i1 [[C]]
|
||||
@ -53,14 +53,14 @@ entry:
|
||||
}
|
||||
|
||||
define i32 @test() {
|
||||
; CHECK-LABEL: define {{[^@]+}}@test() local_unnamed_addr
|
||||
; CHECK-LABEL: define {{[^@]+}}@test() local_unnamed_addr {
|
||||
; CHECK-NEXT: entry:
|
||||
; CHECK-NEXT: [[S:%.*]] = alloca inalloca [[STRUCT_SS:%.*]]
|
||||
; CHECK-NEXT: [[S:%.*]] = alloca inalloca [[STRUCT_SS:%.*]], align 4
|
||||
; CHECK-NEXT: [[C:%.*]] = call fastcc i1 @g(%struct.ss* [[S]], %struct.ss* [[S]])
|
||||
; CHECK-NEXT: ret i32 0
|
||||
;
|
||||
entry:
|
||||
%S = alloca inalloca %struct.ss
|
||||
%c = call i1 @g(%struct.ss* %S, %struct.ss* inalloca %S)
|
||||
%c = call i1 @g(%struct.ss* %S, %struct.ss* inalloca(%struct.ss) %S)
|
||||
ret i32 0
|
||||
}
|
||||
|
@ -14,15 +14,15 @@ target triple = "i386-pc-windows-msvc19.11.0"
|
||||
|
||||
%struct.a = type { i8 }
|
||||
|
||||
define internal x86_thiscallcc void @internalfun(%struct.a* %this, <{ %struct.a }>* inalloca) {
|
||||
define internal x86_thiscallcc void @internalfun(%struct.a* %this, <{ %struct.a }>* inalloca(<{ %struct.a }>)) {
|
||||
; CHECK-LABEL: define {{[^@]+}}@internalfun
|
||||
; CHECK-SAME: (%struct.a* noalias nocapture nofree readnone [[THIS:%.*]], <{ [[STRUCT_A:%.*]] }>* inalloca noundef nonnull align 4 dereferenceable(1) [[TMP0:%.*]]) {
|
||||
; CHECK-SAME: (%struct.a* noalias nocapture nofree readnone [[THIS:%.*]], <{ [[STRUCT_A:%.*]] }>* noundef nonnull inalloca(<{ [[STRUCT_A]] }>) align 4 dereferenceable(1) [[TMP0:%.*]]) {
|
||||
; CHECK-NEXT: entry:
|
||||
; CHECK-NEXT: [[A:%.*]] = getelementptr inbounds <{ [[STRUCT_A]] }>, <{ [[STRUCT_A]] }>* [[TMP0]], i32 0, i32 0
|
||||
; CHECK-NEXT: [[ARGMEM:%.*]] = alloca inalloca <{ [[STRUCT_A]] }>, align 4
|
||||
; CHECK-NEXT: [[TMP1:%.*]] = getelementptr inbounds <{ [[STRUCT_A]] }>, <{ [[STRUCT_A]] }>* [[ARGMEM]], i32 0, i32 0
|
||||
; CHECK-NEXT: [[CALL:%.*]] = call x86_thiscallcc %struct.a* @copy_ctor(%struct.a* noundef nonnull align 4 dereferenceable(1) [[TMP1]], %struct.a* noundef nonnull align 4 dereferenceable(1) [[A]])
|
||||
; CHECK-NEXT: call void @ext(<{ [[STRUCT_A]] }>* inalloca noundef nonnull align 4 dereferenceable(1) [[ARGMEM]])
|
||||
; CHECK-NEXT: call void @ext(<{ [[STRUCT_A]] }>* noundef nonnull inalloca(<{ [[STRUCT_A]] }>) align 4 dereferenceable(1) [[ARGMEM]])
|
||||
; CHECK-NEXT: ret void
|
||||
;
|
||||
entry:
|
||||
@ -30,7 +30,7 @@ entry:
|
||||
%argmem = alloca inalloca <{ %struct.a }>, align 4
|
||||
%1 = getelementptr inbounds <{ %struct.a }>, <{ %struct.a }>* %argmem, i32 0, i32 0
|
||||
%call = call x86_thiscallcc %struct.a* @copy_ctor(%struct.a* %1, %struct.a* dereferenceable(1) %a)
|
||||
call void @ext(<{ %struct.a }>* inalloca %argmem)
|
||||
call void @ext(<{ %struct.a }>* inalloca(<{ %struct.a }>) %argmem)
|
||||
ret void
|
||||
}
|
||||
|
||||
@ -40,19 +40,19 @@ define void @exportedfun(%struct.a* %a) {
|
||||
; CHECK-SAME: (%struct.a* nocapture nofree readnone [[A:%.*]]) {
|
||||
; CHECK-NEXT: [[INALLOCA_SAVE:%.*]] = tail call i8* @llvm.stacksave() #[[ATTR1:[0-9]+]]
|
||||
; CHECK-NEXT: [[ARGMEM:%.*]] = alloca inalloca <{ [[STRUCT_A:%.*]] }>, align 4
|
||||
; CHECK-NEXT: call x86_thiscallcc void @internalfun(%struct.a* noalias nocapture nofree readnone undef, <{ [[STRUCT_A]] }>* inalloca noundef nonnull align 4 dereferenceable(1) [[ARGMEM]])
|
||||
; CHECK-NEXT: call x86_thiscallcc void @internalfun(%struct.a* noalias nocapture nofree readnone undef, <{ [[STRUCT_A]] }>* noundef nonnull inalloca(<{ [[STRUCT_A]] }>) align 4 dereferenceable(1) [[ARGMEM]])
|
||||
; CHECK-NEXT: call void @llvm.stackrestore(i8* nofree [[INALLOCA_SAVE]])
|
||||
; CHECK-NEXT: ret void
|
||||
;
|
||||
%inalloca.save = tail call i8* @llvm.stacksave()
|
||||
%argmem = alloca inalloca <{ %struct.a }>, align 4
|
||||
call x86_thiscallcc void @internalfun(%struct.a* %a, <{ %struct.a }>* inalloca %argmem)
|
||||
call x86_thiscallcc void @internalfun(%struct.a* %a, <{ %struct.a }>* inalloca(<{ %struct.a }>) %argmem)
|
||||
call void @llvm.stackrestore(i8* %inalloca.save)
|
||||
ret void
|
||||
}
|
||||
|
||||
declare x86_thiscallcc %struct.a* @copy_ctor(%struct.a* returned, %struct.a* dereferenceable(1))
|
||||
declare void @ext(<{ %struct.a }>* inalloca)
|
||||
declare void @ext(<{ %struct.a }>* inalloca(<{ %struct.a }>))
|
||||
declare i8* @llvm.stacksave()
|
||||
declare void @llvm.stackrestore(i8*)
|
||||
;.
|
||||
|
@ -9,12 +9,12 @@ target datalayout = "E-p:64:64:64-a0:0:8-f32:32:32-f64:64:64-i1:8:8-i8:8:8-i16:1
|
||||
%struct.ss = type { i32, i32 }
|
||||
|
||||
; Argpromote + sroa should change this to passing the two integers by value.
|
||||
define internal i32 @f(%struct.ss* inalloca %s) {
|
||||
define internal i32 @f(%struct.ss* inalloca(%struct.ss) %s) {
|
||||
; IS__TUNIT____: Function Attrs: argmemonly nofree nosync nounwind readonly willreturn
|
||||
; IS__TUNIT____-LABEL: define {{[^@]+}}@f
|
||||
; IS__TUNIT____-SAME: (%struct.ss* inalloca noalias nocapture nofree noundef nonnull align 4 dereferenceable(8) [[S:%.*]]) #[[ATTR0:[0-9]+]] {
|
||||
; IS__TUNIT____-SAME: (%struct.ss* noalias nocapture nofree noundef nonnull inalloca([[STRUCT_SS:%.*]]) align 4 dereferenceable(8) [[S:%.*]]) #[[ATTR0:[0-9]+]] {
|
||||
; IS__TUNIT____-NEXT: entry:
|
||||
; IS__TUNIT____-NEXT: [[F0:%.*]] = getelementptr [[STRUCT_SS:%.*]], %struct.ss* [[S]], i32 0, i32 0
|
||||
; IS__TUNIT____-NEXT: [[F0:%.*]] = getelementptr [[STRUCT_SS]], %struct.ss* [[S]], i32 0, i32 0
|
||||
; IS__TUNIT____-NEXT: [[F1:%.*]] = getelementptr [[STRUCT_SS]], %struct.ss* [[S]], i32 0, i32 1
|
||||
; IS__TUNIT____-NEXT: [[A:%.*]] = load i32, i32* [[F0]], align 4
|
||||
; IS__TUNIT____-NEXT: [[B:%.*]] = load i32, i32* [[F1]], align 4
|
||||
@ -23,9 +23,9 @@ define internal i32 @f(%struct.ss* inalloca %s) {
|
||||
;
|
||||
; IS__CGSCC____: Function Attrs: argmemonly nofree norecurse nosync nounwind readonly willreturn
|
||||
; IS__CGSCC____-LABEL: define {{[^@]+}}@f
|
||||
; IS__CGSCC____-SAME: (%struct.ss* inalloca noalias nocapture nofree noundef nonnull align 4 dereferenceable(8) [[S:%.*]]) #[[ATTR0:[0-9]+]] {
|
||||
; IS__CGSCC____-SAME: (%struct.ss* noalias nocapture nofree noundef nonnull inalloca([[STRUCT_SS:%.*]]) align 4 dereferenceable(8) [[S:%.*]]) #[[ATTR0:[0-9]+]] {
|
||||
; IS__CGSCC____-NEXT: entry:
|
||||
; IS__CGSCC____-NEXT: [[F0:%.*]] = getelementptr [[STRUCT_SS:%.*]], %struct.ss* [[S]], i32 0, i32 0
|
||||
; IS__CGSCC____-NEXT: [[F0:%.*]] = getelementptr [[STRUCT_SS]], %struct.ss* [[S]], i32 0, i32 0
|
||||
; IS__CGSCC____-NEXT: [[F1:%.*]] = getelementptr [[STRUCT_SS]], %struct.ss* [[S]], i32 0, i32 1
|
||||
; IS__CGSCC____-NEXT: [[A:%.*]] = load i32, i32* [[F0]], align 4
|
||||
; IS__CGSCC____-NEXT: [[B:%.*]] = load i32, i32* [[F1]], align 4
|
||||
@ -51,7 +51,7 @@ define i32 @main() {
|
||||
; IS__TUNIT____-NEXT: [[F1:%.*]] = getelementptr [[STRUCT_SS]], %struct.ss* [[S]], i32 0, i32 1
|
||||
; IS__TUNIT____-NEXT: store i32 1, i32* [[F0]], align 4
|
||||
; IS__TUNIT____-NEXT: store i32 2, i32* [[F1]], align 4
|
||||
; IS__TUNIT____-NEXT: [[R:%.*]] = call i32 @f(%struct.ss* inalloca noalias nocapture nofree noundef nonnull align 4 dereferenceable(8) [[S]]) #[[ATTR2:[0-9]+]]
|
||||
; IS__TUNIT____-NEXT: [[R:%.*]] = call i32 @f(%struct.ss* noalias nocapture nofree noundef nonnull inalloca([[STRUCT_SS]]) align 4 dereferenceable(8) [[S]]) #[[ATTR2:[0-9]+]]
|
||||
; IS__TUNIT____-NEXT: ret i32 [[R]]
|
||||
;
|
||||
; IS__CGSCC____: Function Attrs: nofree norecurse nosync nounwind readnone willreturn
|
||||
@ -63,7 +63,7 @@ define i32 @main() {
|
||||
; IS__CGSCC____-NEXT: [[F1:%.*]] = getelementptr [[STRUCT_SS]], %struct.ss* [[S]], i32 0, i32 1
|
||||
; IS__CGSCC____-NEXT: store i32 1, i32* [[F0]], align 4
|
||||
; IS__CGSCC____-NEXT: store i32 2, i32* [[F1]], align 4
|
||||
; IS__CGSCC____-NEXT: [[R:%.*]] = call i32 @f(%struct.ss* inalloca noalias nocapture nofree noundef nonnull align 4 dereferenceable(8) [[S]]) #[[ATTR2:[0-9]+]]
|
||||
; IS__CGSCC____-NEXT: [[R:%.*]] = call i32 @f(%struct.ss* noalias nocapture nofree noundef nonnull inalloca([[STRUCT_SS]]) align 4 dereferenceable(8) [[S]]) #[[ATTR2:[0-9]+]]
|
||||
; IS__CGSCC____-NEXT: ret i32 [[R]]
|
||||
;
|
||||
entry:
|
||||
@ -72,15 +72,15 @@ entry:
|
||||
%f1 = getelementptr %struct.ss, %struct.ss* %S, i32 0, i32 1
|
||||
store i32 1, i32* %f0, align 4
|
||||
store i32 2, i32* %f1, align 4
|
||||
%r = call i32 @f(%struct.ss* inalloca %S)
|
||||
%r = call i32 @f(%struct.ss* inalloca(%struct.ss) %S)
|
||||
ret i32 %r
|
||||
}
|
||||
|
||||
; Argpromote can't promote %a because of the icmp use.
|
||||
define internal i1 @g(%struct.ss* %a, %struct.ss* inalloca %b) nounwind {
|
||||
define internal i1 @g(%struct.ss* %a, %struct.ss* inalloca(%struct.ss) %b) nounwind {
|
||||
; IS__CGSCC____: Function Attrs: nofree norecurse nosync nounwind readnone willreturn
|
||||
; IS__CGSCC____-LABEL: define {{[^@]+}}@g
|
||||
; IS__CGSCC____-SAME: (%struct.ss* noalias nocapture nofree nonnull readnone align 4 dereferenceable(8) [[A:%.*]], %struct.ss* inalloca noalias nocapture nofree nonnull writeonly align 4 dereferenceable(8) [[B:%.*]]) #[[ATTR1]] {
|
||||
; IS__CGSCC____-SAME: (%struct.ss* noalias nocapture nofree nonnull readnone align 4 dereferenceable(8) [[A:%.*]], %struct.ss* noalias nocapture nofree nonnull writeonly inalloca([[STRUCT_SS:%.*]]) align 4 dereferenceable(8) [[B:%.*]]) #[[ATTR1]] {
|
||||
; IS__CGSCC____-NEXT: entry:
|
||||
; IS__CGSCC____-NEXT: ret i1 undef
|
||||
;
|
||||
@ -104,7 +104,7 @@ define i32 @test() {
|
||||
;
|
||||
entry:
|
||||
%S = alloca inalloca %struct.ss
|
||||
%c = call i1 @g(%struct.ss* %S, %struct.ss* inalloca %S)
|
||||
%c = call i1 @g(%struct.ss* %S, %struct.ss* inalloca(%struct.ss) %S)
|
||||
ret i32 0
|
||||
}
|
||||
;.
|
||||
|
@ -107,15 +107,15 @@ define void @test6_2(i8** %p, i8* %q) {
|
||||
}
|
||||
|
||||
; inalloca parameters are always considered written
|
||||
define void @test7_1(i32* inalloca %a) {
|
||||
define void @test7_1(i32* inalloca(i32) %a) {
|
||||
; IS__TUNIT____: Function Attrs: nofree nosync nounwind readnone willreturn
|
||||
; IS__TUNIT____-LABEL: define {{[^@]+}}@test7_1
|
||||
; IS__TUNIT____-SAME: (i32* inalloca nocapture nofree nonnull writeonly dereferenceable(4) [[A:%.*]]) #[[ATTR1]] {
|
||||
; IS__TUNIT____-SAME: (i32* nocapture nofree nonnull writeonly inalloca(i32) dereferenceable(4) [[A:%.*]]) #[[ATTR1]] {
|
||||
; IS__TUNIT____-NEXT: ret void
|
||||
;
|
||||
; IS__CGSCC____: Function Attrs: nofree norecurse nosync nounwind readnone willreturn
|
||||
; IS__CGSCC____-LABEL: define {{[^@]+}}@test7_1
|
||||
; IS__CGSCC____-SAME: (i32* inalloca nocapture nofree nonnull writeonly dereferenceable(4) [[A:%.*]]) #[[ATTR1]] {
|
||||
; IS__CGSCC____-SAME: (i32* nocapture nofree nonnull writeonly inalloca(i32) dereferenceable(4) [[A:%.*]]) #[[ATTR1]] {
|
||||
; IS__CGSCC____-NEXT: ret void
|
||||
;
|
||||
ret void
|
||||
|
@ -332,15 +332,15 @@ define i32 @ipccp3() {
|
||||
|
||||
; Do not touch complicated arguments (for now)
|
||||
%struct.X = type { i8* }
|
||||
define internal i32* @test_inalloca(i32* inalloca %a) {
|
||||
define internal i32* @test_inalloca(i32* inalloca(i32) %a) {
|
||||
; IS__TUNIT____: Function Attrs: nofree nosync nounwind readnone willreturn
|
||||
; IS__TUNIT____-LABEL: define {{[^@]+}}@test_inalloca
|
||||
; IS__TUNIT____-SAME: (i32* inalloca noalias nofree nonnull returned writeonly dereferenceable(4) "no-capture-maybe-returned" [[A:%.*]]) #[[ATTR1]] {
|
||||
; IS__TUNIT____-SAME: (i32* noalias nofree nonnull returned writeonly inalloca(i32) dereferenceable(4) "no-capture-maybe-returned" [[A:%.*]]) #[[ATTR1]] {
|
||||
; IS__TUNIT____-NEXT: ret i32* [[A]]
|
||||
;
|
||||
; IS__CGSCC____: Function Attrs: nofree norecurse nosync nounwind readnone willreturn
|
||||
; IS__CGSCC____-LABEL: define {{[^@]+}}@test_inalloca
|
||||
; IS__CGSCC____-SAME: (i32* inalloca noalias nofree noundef nonnull returned writeonly dereferenceable(4) "no-capture-maybe-returned" [[A:%.*]]) #[[ATTR1]] {
|
||||
; IS__CGSCC____-SAME: (i32* noalias nofree noundef nonnull returned writeonly inalloca(i32) dereferenceable(4) "no-capture-maybe-returned" [[A:%.*]]) #[[ATTR1]] {
|
||||
; IS__CGSCC____-NEXT: ret i32* [[A]]
|
||||
;
|
||||
ret i32* %a
|
||||
|
@ -39,13 +39,13 @@ define void @caller() {
|
||||
|
||||
; We can't remove 'this' here, as that would put argmem in ecx instead of
|
||||
; memory.
|
||||
define internal x86_thiscallcc i32 @unused_this(i32* %this, i32* inalloca %argmem) {
|
||||
define internal x86_thiscallcc i32 @unused_this(i32* %this, i32* inalloca(i32) %argmem) {
|
||||
;
|
||||
;
|
||||
%v = load i32, i32* %argmem
|
||||
ret i32 %v
|
||||
}
|
||||
; CHECK-LABEL: define internal x86_thiscallcc i32 @unused_this(i32* %this, i32* inalloca %argmem)
|
||||
; CHECK-LABEL: define internal x86_thiscallcc i32 @unused_this(i32* %this, i32* inalloca(i32) %argmem)
|
||||
|
||||
define i32 @caller2() {
|
||||
;
|
||||
@ -53,7 +53,7 @@ define i32 @caller2() {
|
||||
%t = alloca i32
|
||||
%m = alloca inalloca i32
|
||||
store i32 42, i32* %m
|
||||
%v = call x86_thiscallcc i32 @unused_this(i32* %t, i32* inalloca %m)
|
||||
%v = call x86_thiscallcc i32 @unused_this(i32* %t, i32* inalloca(i32) %m)
|
||||
ret i32 %v
|
||||
}
|
||||
|
||||
|
@ -148,7 +148,7 @@ define void @test9(%struct.x* byval(%struct.x) %a) nounwind {
|
||||
}
|
||||
|
||||
; Test for inalloca handling.
|
||||
define void @test9_2(%struct.x* inalloca %a) nounwind {
|
||||
define void @test9_2(%struct.x* inalloca(%struct.x) %a) nounwind {
|
||||
; CHECK-LABEL: @test9_2(
|
||||
; CHECK-NEXT: ret void
|
||||
;
|
||||
|
@ -50,9 +50,9 @@ define void @test6_2(i8** %p, i8* %q) {
|
||||
ret void
|
||||
}
|
||||
|
||||
; CHECK: define void @test7_1(i32* inalloca nocapture %a)
|
||||
; CHECK: define void @test7_1(i32* nocapture inalloca(i32) %a)
|
||||
; inalloca parameters are always considered written
|
||||
define void @test7_1(i32* inalloca %a) {
|
||||
define void @test7_1(i32* inalloca(i32) %a) {
|
||||
ret void
|
||||
}
|
||||
|
||||
|
@ -5,7 +5,7 @@ target triple = "i686-pc-windows-msvc18.0.0"
|
||||
|
||||
%struct.S = type { i8* }
|
||||
|
||||
declare void @f(<{ %struct.S }>* inalloca)
|
||||
declare void @f(<{ %struct.S }>* inalloca(<{ %struct.S }>))
|
||||
|
||||
|
||||
; Check that we don't clone the %x alloca and insert it in the live range of
|
||||
@ -41,7 +41,7 @@ false:
|
||||
br label %exit
|
||||
|
||||
exit:
|
||||
call void @f(<{ %struct.S }>* inalloca %argmem)
|
||||
call void @f(<{ %struct.S }>* inalloca(<{ %struct.S }>) %argmem)
|
||||
call void @llvm.stackrestore(i8* %inalloca.save)
|
||||
ret void
|
||||
}
|
||||
|
@ -29,19 +29,19 @@ define internal i32 @j(i32* %m) {
|
||||
ret i32 %v
|
||||
}
|
||||
|
||||
define internal i32 @inalloca(i32* inalloca %p) {
|
||||
define internal i32 @inalloca(i32* inalloca(i32) %p) {
|
||||
; CHECK-LABEL: define internal fastcc i32 @inalloca(i32* %p)
|
||||
%rv = load i32, i32* %p
|
||||
ret i32 %rv
|
||||
}
|
||||
|
||||
define i32 @inalloca2_caller(i32* inalloca %p) {
|
||||
%rv = musttail call i32 @inalloca2(i32* inalloca %p)
|
||||
define i32 @inalloca2_caller(i32* inalloca(i32) %p) {
|
||||
%rv = musttail call i32 @inalloca2(i32* inalloca(i32) %p)
|
||||
ret i32 %rv
|
||||
}
|
||||
define internal i32 @inalloca2(i32* inalloca %p) {
|
||||
define internal i32 @inalloca2(i32* inalloca(i32) %p) {
|
||||
; Because of the musttail caller, this inalloca cannot be dropped.
|
||||
; CHECK-LABEL: define internal i32 @inalloca2(i32* inalloca %p)
|
||||
; CHECK-LABEL: define internal i32 @inalloca2(i32* inalloca(i32) %p)
|
||||
%rv = load i32, i32* %p
|
||||
ret i32 %rv
|
||||
}
|
||||
@ -59,7 +59,7 @@ define void @call_things() {
|
||||
call coldcc i32 @h(i32* %m)
|
||||
call i32 @j(i32* %m)
|
||||
%args = alloca inalloca i32
|
||||
call i32 @inalloca(i32* inalloca %args)
|
||||
call i32 @inalloca(i32* inalloca(i32) %args)
|
||||
%c = call token @llvm.call.preallocated.setup(i32 1)
|
||||
%N = call i8* @llvm.call.preallocated.arg(token %c, i32 0) preallocated(i32)
|
||||
%n = bitcast i8* %N to i32*
|
||||
|
@ -41,13 +41,13 @@ entry:
|
||||
%argmem = alloca inalloca <{ %struct.Foo }>, align 4
|
||||
%0 = getelementptr inbounds <{ %struct.Foo }>, <{ %struct.Foo }>* %argmem, i32 0, i32 0
|
||||
%call = call x86_thiscallcc %struct.Foo* @"\01??0Foo@@QAE@XZ"(%struct.Foo* %0)
|
||||
call void @h(<{ %struct.Foo }>* inalloca %argmem)
|
||||
call void @h(<{ %struct.Foo }>* inalloca(<{ %struct.Foo }>) %argmem)
|
||||
call void @llvm.stackrestore(i8* %inalloca.save)
|
||||
ret void
|
||||
}
|
||||
|
||||
; Function Attrs: alwaysinline inlinehint nounwind
|
||||
define internal void @h(<{ %struct.Foo }>* inalloca) alwaysinline {
|
||||
define internal void @h(<{ %struct.Foo }>* inalloca(<{ %struct.Foo }>)) alwaysinline {
|
||||
entry:
|
||||
%o = getelementptr inbounds <{ %struct.Foo }>, <{ %struct.Foo }>* %0, i32 0, i32 0
|
||||
call x86_thiscallcc void @"\01??1Foo@@QAE@XZ"(%struct.Foo* %o)
|
||||
|
@ -207,7 +207,7 @@ define void @test8() {
|
||||
|
||||
; PR19569
|
||||
%struct_type = type { i32, i32 }
|
||||
declare void @test9_aux(<{ %struct_type }>* inalloca)
|
||||
declare void @test9_aux(<{ %struct_type }>* inalloca(<{ %struct_type }>))
|
||||
declare i8* @llvm.stacksave()
|
||||
declare void @llvm.stackrestore(i8*)
|
||||
|
||||
@ -219,7 +219,7 @@ define void @test9(%struct_type* %a) {
|
||||
; ALL-NEXT: [[TMP0:%.*]] = bitcast %struct_type* [[A:%.*]] to i64*
|
||||
; ALL-NEXT: [[TMP1:%.*]] = load i64, i64* [[TMP0]], align 4
|
||||
; ALL-NEXT: store i64 [[TMP1]], i64* [[ARGMEM]], align 8
|
||||
; ALL-NEXT: call void @test9_aux(<{ [[STRUCT_TYPE]] }>* inalloca nonnull [[TMPCAST]])
|
||||
; ALL-NEXT: call void @test9_aux(<{ [[STRUCT_TYPE]] }>* nonnull inalloca(<{ [[STRUCT_TYPE]] }>) [[TMPCAST]])
|
||||
; ALL-NEXT: ret void
|
||||
;
|
||||
entry:
|
||||
@ -229,7 +229,7 @@ entry:
|
||||
%1 = bitcast %struct_type* %0 to i8*
|
||||
%2 = bitcast %struct_type* %a to i8*
|
||||
call void @llvm.memcpy.p0i8.p0i8.i32(i8* align 4 %1, i8* align 4 %2, i32 8, i1 false)
|
||||
call void @test9_aux(<{ %struct_type }>* inalloca %argmem)
|
||||
call void @test9_aux(<{ %struct_type }>* inalloca(<{ %struct_type }>) %argmem)
|
||||
call void @llvm.stackrestore(i8* %inalloca.save)
|
||||
ret void
|
||||
}
|
||||
|
@ -4,12 +4,12 @@ target datalayout = "e-p:32:32"
|
||||
target triple = "i686-pc-linux-gnu"
|
||||
|
||||
declare void @takes_i32(i32)
|
||||
declare void @takes_i32_inalloca(i32* inalloca)
|
||||
declare void @takes_i32_inalloca(i32* inalloca(i32))
|
||||
|
||||
define void @f() {
|
||||
; CHECK-LABEL: define void @f()
|
||||
%args = alloca inalloca i32
|
||||
call void bitcast (void (i32)* @takes_i32 to void (i32*)*)(i32* inalloca %args)
|
||||
call void bitcast (void (i32)* @takes_i32 to void (i32*)*)(i32* inalloca(i32) %args)
|
||||
; CHECK: call void bitcast
|
||||
ret void
|
||||
}
|
||||
|
@ -9,7 +9,7 @@ declare void @llvm.stackrestore(i8*)
|
||||
define i32* @test1(i32 %P) {
|
||||
%tmp = call i8* @llvm.stacksave( )
|
||||
call void @llvm.stackrestore( i8* %tmp ) ;; not restoring anything
|
||||
%A = alloca i32, i32 %P
|
||||
%A = alloca i32, i32 %P
|
||||
ret i32* %A
|
||||
}
|
||||
|
||||
@ -49,7 +49,7 @@ bb: ; preds = %bb, %bb.preheader
|
||||
%tmp77 = alloca i8, i32 %size ; <i8*> [#uses=1]
|
||||
%tmp78 = call i8* @llvm.stacksave( ) ; <i8*> [#uses=1]
|
||||
%tmp102 = alloca i8, i32 %size ; <i8*> [#uses=1]
|
||||
call void @bar( i32 %i.0.reg2mem.0, i8* %tmp23, i8* %tmp52, i8* %tmp77, i8* %tmp102, i32 %size ) nounwind
|
||||
call void @bar( i32 %i.0.reg2mem.0, i8* %tmp23, i8* %tmp52, i8* %tmp77, i8* %tmp102, i32 %size ) nounwind
|
||||
call void @llvm.stackrestore( i8* %tmp78 )
|
||||
call void @llvm.stackrestore( i8* %tmp53 )
|
||||
call void @llvm.stackrestore( i8* %tmp28 )
|
||||
@ -72,7 +72,7 @@ return: ; preds = %bb, %entry
|
||||
|
||||
declare void @bar(i32, i8*, i8*, i8*, i8*, i32)
|
||||
|
||||
declare void @inalloca_callee(i32* inalloca)
|
||||
declare void @inalloca_callee(i32* inalloca(i32))
|
||||
|
||||
define void @test3(i32 %c) {
|
||||
entry:
|
||||
@ -83,7 +83,7 @@ loop:
|
||||
%save1 = call i8* @llvm.stacksave()
|
||||
%argmem = alloca inalloca i32
|
||||
store i32 0, i32* %argmem
|
||||
call void @inalloca_callee(i32* inalloca %argmem)
|
||||
call void @inalloca_callee(i32* inalloca(i32) %argmem)
|
||||
|
||||
; This restore cannot be deleted, the restore below does not make it dead.
|
||||
call void @llvm.stackrestore(i8* %save1)
|
||||
@ -106,7 +106,7 @@ return:
|
||||
; CHECK: %save1 = call i8* @llvm.stacksave()
|
||||
; CHECK: %argmem = alloca inalloca i32
|
||||
; CHECK: store i32 0, i32* %argmem
|
||||
; CHECK: call void @inalloca_callee(i32* inalloca {{.*}} %argmem)
|
||||
; CHECK: call void @inalloca_callee(i32* {{.*}} inalloca(i32) %argmem)
|
||||
; CHECK: call void @llvm.stackrestore(i8* %save1)
|
||||
; CHECK: br i1 %done, label %loop, label %return
|
||||
; CHECK: 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 byref(i32) byval(i32) preallocated(i32) sret(i32) align 1 dereferenceable(1) dereferenceable_or_null(1)
|
||||
; CHECK: Wrong types for attribute: nest noalias nocapture nonnull readnone readonly byref(i32) byval(i32) inalloca(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 zeroext byref(void) byval(void) preallocated(void) sret(void) align 1 dereferenceable(1) dereferenceable_or_null(1)
|
||||
; CHECK: Wrong types for attribute: nest noalias nocapture noundef nonnull readnone readonly signext zeroext byref(void) byval(void) inalloca(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
|
||||
|
@ -118,7 +118,7 @@ define amdgpu_kernel void @preallocated_as0_cc_amdgpu_kernel(i32* preallocated(i
|
||||
|
||||
; CHECK: Calling convention disallows inalloca
|
||||
; CHECK-NEXT: void (i32*)* @inalloca_as0_cc_amdgpu_kernel
|
||||
define amdgpu_kernel void @inalloca_as0_cc_amdgpu_kernel(i32* inalloca %ptr) {
|
||||
define amdgpu_kernel void @inalloca_as0_cc_amdgpu_kernel(i32* inalloca(i32) %ptr) {
|
||||
ret void
|
||||
}
|
||||
|
||||
|
@ -28,7 +28,7 @@ define void @byref_byval(i32* byref(i32) byval(i32)) {
|
||||
|
||||
; CHECK: Attributes 'byval', 'inalloca', 'preallocated', 'inreg', 'nest', 'byref', and 'sret' are incompatible!
|
||||
; CHECK-NEXT: void (i32*)* @byref_inalloca
|
||||
define void @byref_inalloca(i32* byref(i32) inalloca) {
|
||||
define void @byref_inalloca(i32* byref(i32) inalloca(i32)) {
|
||||
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 byref(i32) byval(i32) preallocated(i32) sret(i32) align 1 dereferenceable(1) dereferenceable_or_null(1)
|
||||
; CHECK: Wrong types for attribute: nest noalias nocapture nonnull readnone readonly byref(i32) byval(i32) inalloca(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,5 +1,5 @@
|
||||
; RUN: not llvm-as < %s -o /dev/null 2>&1 | FileCheck %s
|
||||
|
||||
; 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: Wrong types for attribute: nest noalias nocapture nonnull readnone readonly byref(i32) byval(i32) inalloca(i32) preallocated(i32) sret(i32) align 1 dereferenceable(1) dereferenceable_or_null(1)
|
||||
; CHECK-NEXT: void (i32)* @h
|
||||
declare void @h(i32 byval(i32) %num)
|
||||
|
@ -3,7 +3,7 @@
|
||||
declare void @h(i32, ...)
|
||||
define void @i() {
|
||||
%args = alloca inalloca i32
|
||||
call void (i32, ...) @h(i32 1, i32* inalloca %args, i32 3)
|
||||
call void (i32, ...) @h(i32 1, i32* inalloca(i32) %args, i32 3)
|
||||
; CHECK: inalloca isn't on the last argument!
|
||||
ret void
|
||||
}
|
||||
|
@ -1,22 +1,34 @@
|
||||
; RUN: not llvm-as %s -o /dev/null 2>&1 | FileCheck %s
|
||||
|
||||
declare void @a(i64* byval(i64) inalloca %p)
|
||||
declare void @a(i64* byval(i64) inalloca(i64) %p)
|
||||
; CHECK: Attributes {{.*}} are incompatible
|
||||
|
||||
declare void @b(i64* inreg inalloca %p)
|
||||
declare void @b(i64* inreg inalloca(i64) %p)
|
||||
; CHECK: Attributes {{.*}} are incompatible
|
||||
|
||||
declare void @c(i64* sret(i64) inalloca %p)
|
||||
declare void @c(i64* sret(i64) inalloca(i64) %p)
|
||||
; CHECK: Attributes {{.*}} are incompatible
|
||||
|
||||
declare void @d(i64* nest inalloca %p)
|
||||
declare void @d(i64* nest inalloca(i64) %p)
|
||||
; CHECK: Attributes {{.*}} are incompatible
|
||||
|
||||
declare void @e(i64* readonly inalloca %p)
|
||||
declare void @e(i64* readonly inalloca(i64) %p)
|
||||
; CHECK: Attributes {{.*}} are incompatible
|
||||
|
||||
declare void @f(void ()* inalloca %p)
|
||||
declare void @f(void ()* inalloca(void()) %p)
|
||||
; CHECK: do not support unsized types
|
||||
|
||||
declare void @g(i32* inalloca %p, i32 %p2)
|
||||
declare void @g(i32* inalloca(i32) %p, i32 %p2)
|
||||
; CHECK: inalloca isn't on the last parameter!
|
||||
|
||||
; CHECK: Attribute 'inalloca' type does not match parameter!
|
||||
; CHECK-NEXT: void (i32*)* @inalloca_mismatched_pointee_type0
|
||||
define void @inalloca_mismatched_pointee_type0(i32* inalloca(i8)) {
|
||||
ret void
|
||||
}
|
||||
|
||||
; CHECK: Wrong types for attribute:
|
||||
; CHECK-NEXT: void (i8)* @inalloca_not_pointer
|
||||
define void @inalloca_not_pointer(i8 byref(i8)) {
|
||||
ret void
|
||||
}
|
||||
|
@ -2,21 +2,21 @@
|
||||
; doesn't reject it.
|
||||
; RUN: llvm-as %s -o /dev/null
|
||||
|
||||
declare void @doit(i64* inalloca %a)
|
||||
declare void @doit(i64* inalloca(i64) %a)
|
||||
|
||||
define void @a() {
|
||||
entry:
|
||||
%a = alloca inalloca [2 x i32]
|
||||
%b = bitcast [2 x i32]* %a to i64*
|
||||
call void @doit(i64* inalloca %b)
|
||||
call void @doit(i64* inalloca(i64) %b)
|
||||
ret void
|
||||
}
|
||||
|
||||
define void @b() {
|
||||
entry:
|
||||
%a = alloca inalloca i64
|
||||
call void @doit(i64* inalloca %a)
|
||||
call void @doit(i64* inalloca %a)
|
||||
call void @doit(i64* inalloca(i64) %a)
|
||||
call void @doit(i64* inalloca(i64) %a)
|
||||
ret void
|
||||
}
|
||||
|
||||
@ -34,6 +34,6 @@ else:
|
||||
|
||||
call:
|
||||
%args = phi i64* [ %a, %if ], [ %b, %else ]
|
||||
call void @doit(i64* inalloca %args)
|
||||
call void @doit(i64* inalloca(i64) %args)
|
||||
ret void
|
||||
}
|
||||
|
@ -1,13 +1,13 @@
|
||||
; RUN: not llvm-as %s -o /dev/null 2>&1 | FileCheck %s
|
||||
|
||||
|
||||
declare void @doit(i64* inalloca %a)
|
||||
declare void @doit(i64* inalloca(i64) %a)
|
||||
|
||||
define void @a() {
|
||||
entry:
|
||||
%a = alloca [2 x i32]
|
||||
%b = bitcast [2 x i32]* %a to i64*
|
||||
call void @doit(i64* inalloca %b)
|
||||
call void @doit(i64* inalloca(i64) %b)
|
||||
; CHECK: inalloca argument for call has mismatched alloca
|
||||
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 zeroext byref(void) byval(void) preallocated(void) sret(void) align 1 dereferenceable(1) dereferenceable_or_null(1)
|
||||
; CHECK: Wrong types for attribute: nest noalias nocapture noundef nonnull readnone readonly signext zeroext byref(void) byval(void) inalloca(void) preallocated(void) sret(void) align 1 dereferenceable(1) dereferenceable_or_null(1)
|
||||
; CHECK-NEXT: @noundef_void
|
||||
define noundef void @noundef_void() {
|
||||
ret void
|
||||
|
@ -180,9 +180,6 @@ TEST(Attributes, StringRepresentation) {
|
||||
Attribute A = Attribute::getWithByValType(C, Ty);
|
||||
EXPECT_EQ(A.getAsString(), "byval(%mystruct)");
|
||||
|
||||
A = Attribute::getWithByValType(C, nullptr);
|
||||
EXPECT_EQ(A.getAsString(), "byval");
|
||||
|
||||
A = Attribute::getWithByValType(C, Type::getInt32Ty(C));
|
||||
EXPECT_EQ(A.getAsString(), "byval(i32)");
|
||||
}
|
||||
|
@ -718,10 +718,10 @@ TEST(CloneFunction, CloneEmptyFunction) {
|
||||
|
||||
TEST(CloneFunction, CloneFunctionWithInalloca) {
|
||||
StringRef ImplAssembly = R"(
|
||||
declare void @a(i32* inalloca)
|
||||
declare void @a(i32* inalloca(i32))
|
||||
define void @foo() {
|
||||
%a = alloca inalloca i32
|
||||
call void @a(i32* inalloca %a)
|
||||
call void @a(i32* inalloca(i32) %a)
|
||||
ret void
|
||||
}
|
||||
declare void @bar()
|
||||
|
Loading…
Reference in New Issue
Block a user