Begin adding docs and IR-level support for the inalloca attribute

The inalloca attribute is designed to support passing C++ objects by
value in the Microsoft C++ ABI.  It behaves the same as byval, except
that it always implies that the argument is in memory and that the bytes
are never copied.  This attribute allows the caller to take the address
of an outgoing argument's memory and execute arbitrary code to store
into it.

This patch adds basic IR support, docs, and verification.  It does not
attempt to implement any lowering or fix any possibly broken transforms.

When this patch lands, a complete description of this feature should
appear at http://llvm.org/docs/InAlloca.html .

Differential Revision: http://llvm-reviews.chandlerc.com/D2173

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@197645 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Reid Kleckner
2013-12-19 02:14:12 +00:00
parent 1d4866ccbf
commit 4b70bfc905
20 changed files with 328 additions and 27 deletions

View File

@@ -813,26 +813,25 @@ void Verifier::VerifyParameterAttrs(AttributeSet Attrs, unsigned Idx, Type *Ty,
!Attrs.hasAttribute(Idx, Attribute::Nest) &&
!Attrs.hasAttribute(Idx, Attribute::StructRet) &&
!Attrs.hasAttribute(Idx, Attribute::NoCapture) &&
!Attrs.hasAttribute(Idx, Attribute::Returned),
"Attribute 'byval', 'nest', 'sret', 'nocapture', and 'returned' "
"do not apply to return values!", V);
!Attrs.hasAttribute(Idx, Attribute::Returned) &&
!Attrs.hasAttribute(Idx, Attribute::InAlloca),
"Attributes 'byval', 'inalloca', 'nest', 'sret', 'nocapture', and "
"'returned' do not apply to return values!", V);
// Check for mutually incompatible attributes.
Assert1(!((Attrs.hasAttribute(Idx, Attribute::ByVal) &&
Attrs.hasAttribute(Idx, Attribute::Nest)) ||
(Attrs.hasAttribute(Idx, Attribute::ByVal) &&
Attrs.hasAttribute(Idx, Attribute::StructRet)) ||
(Attrs.hasAttribute(Idx, Attribute::Nest) &&
Attrs.hasAttribute(Idx, Attribute::StructRet))), "Attributes "
"'byval, nest, and sret' are incompatible!", V);
// Check for mutually incompatible attributes. Only inreg is compatible with
// sret.
unsigned AttrCount = 0;
AttrCount += Attrs.hasAttribute(Idx, Attribute::ByVal);
AttrCount += Attrs.hasAttribute(Idx, Attribute::InAlloca);
AttrCount += Attrs.hasAttribute(Idx, Attribute::StructRet) ||
Attrs.hasAttribute(Idx, Attribute::InReg);
AttrCount += Attrs.hasAttribute(Idx, Attribute::Nest);
Assert1(AttrCount <= 1, "Attributes 'byval', 'inalloca', 'inreg', 'nest', "
"and 'sret' are incompatible!", V);
Assert1(!((Attrs.hasAttribute(Idx, Attribute::ByVal) &&
Attrs.hasAttribute(Idx, Attribute::Nest)) ||
(Attrs.hasAttribute(Idx, Attribute::ByVal) &&
Attrs.hasAttribute(Idx, Attribute::InReg)) ||
(Attrs.hasAttribute(Idx, Attribute::Nest) &&
Attrs.hasAttribute(Idx, Attribute::InReg))), "Attributes "
"'byval, nest, and inreg' are incompatible!", V);
Assert1(!(Attrs.hasAttribute(Idx, Attribute::InAlloca) &&
Attrs.hasAttribute(Idx, Attribute::ReadOnly)), "Attributes "
"'inalloca and readonly' are incompatible!", V);
Assert1(!(Attrs.hasAttribute(Idx, Attribute::StructRet) &&
Attrs.hasAttribute(Idx, Attribute::Returned)), "Attributes "
@@ -855,14 +854,18 @@ void Verifier::VerifyParameterAttrs(AttributeSet Attrs, unsigned Idx, Type *Ty,
"Wrong types for attribute: " +
AttributeFuncs::typeIncompatible(Ty, Idx).getAsString(Idx), V);
if (PointerType *PTy = dyn_cast<PointerType>(Ty))
Assert1(!Attrs.hasAttribute(Idx, Attribute::ByVal) ||
PTy->getElementType()->isSized(),
"Attribute 'byval' does not support unsized types!", V);
else
if (PointerType *PTy = dyn_cast<PointerType>(Ty)) {
if (!PTy->getElementType()->isSized()) {
Assert1(!Attrs.hasAttribute(Idx, Attribute::ByVal) &&
!Attrs.hasAttribute(Idx, Attribute::InAlloca),
"Attributes 'byval' and 'inalloca' do not support unsized types!",
V);
}
} else {
Assert1(!Attrs.hasAttribute(Idx, Attribute::ByVal),
"Attribute 'byval' only applies to parameters with pointer type!",
V);
}
}
// VerifyFunctionAttrs - Check parameter attributes against a function type.
@@ -1533,6 +1536,15 @@ void Verifier::VerifyCallSite(CallSite CS) {
// Verify call attributes.
VerifyFunctionAttrs(FTy, Attrs, I);
// Verify that values used for inalloca parameters are in fact allocas.
for (unsigned i = 0, e = CS.arg_size(); i != e; ++i) {
if (!Attrs.hasAttribute(1 + i, Attribute::InAlloca))
continue;
Value *Arg = CS.getArgument(i);
Assert2(isa<AllocaInst>(Arg), "Inalloca argument is not an alloca!", I,
Arg);
}
if (FTy->isVarArg()) {
// FIXME? is 'nest' even legal here?
bool SawNest = false;
@@ -1870,6 +1882,22 @@ void Verifier::visitAllocaInst(AllocaInst &AI) {
&AI);
Assert1(AI.getArraySize()->getType()->isIntegerTy(),
"Alloca array size must have integer type", &AI);
// Verify that an alloca instruction is not used with inalloca more than once.
unsigned InAllocaUses = 0;
for (User::use_iterator UI = AI.use_begin(), UE = AI.use_end(); UI != UE;
++UI) {
CallSite CS(*UI);
if (!CS)
continue;
unsigned ArgNo = CS.getArgumentNo(UI);
if (CS.isInAllocaArgument(ArgNo)) {
InAllocaUses++;
Assert1(InAllocaUses <= 1,
"Allocas can be used at most once with inalloca!", &AI);
}
}
visitInstruction(AI);
}