Add an inalloca flag to allocas

Summary:
The only current use of this flag is to mark the alloca as dynamic, even
if its in the entry block.  The stack adjustment for the alloca can
never be folded into the prologue because the call may clear it and it
has to be allocated at the top of the stack.

Reviewers: majnemer

CC: llvm-commits

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

llvm-svn: 199525
This commit is contained in:
Reid Kleckner 2014-01-17 23:58:17 +00:00
parent 2b164bd98d
commit 436c42ec3d
10 changed files with 99 additions and 29 deletions

View File

@ -778,19 +778,16 @@ Currently, only the following parameter attributes are defined:
.. Warning:: This feature is unstable and not fully implemented. .. Warning:: This feature is unstable and not fully implemented.
The ``inalloca`` argument attribute allows the caller to take the The ``inalloca`` argument attribute allows the caller to take the
address of all stack-allocated arguments to a ``call`` or ``invoke`` address of outgoing stack arguments. An ``inalloca`` argument must
before it executes. It is similar to ``byval`` in that it is used be a pointer to stack memory produced by an ``alloca`` instruction.
to pass arguments by value, but it guarantees that the argument will The alloca, or argument allocation, must also be tagged with the
not be copied. inalloca keyword. Only the past argument may have the ``inalloca``
attribute, and that argument is guaranteed to be passed in memory.
To be :ref:`well formed <wellformed>`, an alloca may be used as an An argument allocation may be used by a call at most once because
``inalloca`` argument at most once. The attribute can only be the call may deallocate it. The ``inalloca`` attribute cannot be
applied to the last parameter, and it guarantees that they are used in conjunction with other attributes that affect argument
passed in memory. The ``inalloca`` attribute cannot be used in storage, like ``inreg``, ``nest``, ``sret``, or ``byval``.
conjunction with other attributes that affect argument storage, like
``inreg``, ``nest``, ``sret``, or ``byval``. The ``inalloca`` stack
space is considered to be clobbered by any call that uses it, so any
``inalloca`` parameters cannot be marked ``readonly``.
When the call site is reached, the argument allocation must have When the call site is reached, the argument allocation must have
been the most recent stack allocation that is still live, or the been the most recent stack allocation that is still live, or the
@ -4693,7 +4690,7 @@ Syntax:
:: ::
<result> = alloca <type>[, <ty> <NumElements>][, align <alignment>] ; yields {type*}:result <result> = alloca <type>[, inalloca][, <ty> <NumElements>][, align <alignment>] ; yields {type*}:result
Overview: Overview:
""""""""" """""""""

View File

@ -59,6 +59,11 @@ public:
/// containing function. /// containing function.
bool hasByValAttr() const; bool hasByValAttr() const;
/// \brief Return true if this argument has the byval attribute or inalloca
/// attribute on it in its containing function. These attributes both
/// represent arguments being passed by value.
bool hasByValOrInAllocaAttr() const;
/// \brief If this is a byval or inalloca argument, return its alignment. /// \brief If this is a byval or inalloca argument, return its alignment.
unsigned getParamAlignment() const; unsigned getParamAlignment() const;

View File

@ -101,7 +101,7 @@ public:
/// by the instruction. /// by the instruction.
/// ///
unsigned getAlignment() const { unsigned getAlignment() const {
return (1u << getSubclassDataFromInstruction()) >> 1; return (1u << (getSubclassDataFromInstruction() & 31)) >> 1;
} }
void setAlignment(unsigned Align); void setAlignment(unsigned Align);
@ -110,6 +110,20 @@ public:
/// into the prolog/epilog code, so it is basically free. /// into the prolog/epilog code, so it is basically free.
bool isStaticAlloca() const; bool isStaticAlloca() const;
/// \brief Return true if this alloca is used as an inalloca argument to a
/// call. Such allocas are never considered static even if they are in the
/// entry block.
bool isUsedWithInAlloca() const {
return getSubclassDataFromInstruction() & 32;
}
/// \brief Specify whether this alloca is used to represent a the arguments to
/// a call.
void setUsedWithInAlloca(bool V) {
setInstructionSubclassData((getSubclassDataFromInstruction() & ~32) |
(V ? 32 : 0));
}
// Methods for support type inquiry through isa, cast, and dyn_cast: // Methods for support type inquiry through isa, cast, and dyn_cast:
static inline bool classof(const Instruction *I) { static inline bool classof(const Instruction *I) {
return (I->getOpcode() == Instruction::Alloca); return (I->getOpcode() == Instruction::Alloca);

View File

@ -4069,31 +4069,42 @@ bool LLParser::ParseCall(Instruction *&Inst, PerFunctionState &PFS,
//===----------------------------------------------------------------------===// //===----------------------------------------------------------------------===//
/// ParseAlloc /// ParseAlloc
/// ::= 'alloca' Type (',' TypeAndValue)? (',' OptionalInfo)? /// ::= 'alloca' Type (',' 'inalloca')? (',' TypeAndValue)? (',' OptionalInfo)?
int LLParser::ParseAlloc(Instruction *&Inst, PerFunctionState &PFS) { int LLParser::ParseAlloc(Instruction *&Inst, PerFunctionState &PFS) {
Value *Size = 0; Value *Size = 0;
LocTy SizeLoc; LocTy SizeLoc;
unsigned Alignment = 0; unsigned Alignment = 0;
bool IsInAlloca = false;
Type *Ty = 0; Type *Ty = 0;
if (ParseType(Ty)) return true; if (ParseType(Ty)) return true;
bool AteExtraComma = false; bool AteExtraComma = false;
if (EatIfPresent(lltok::comma)) { if (EatIfPresent(lltok::comma)) {
if (Lex.getKind() == lltok::kw_align) { bool HaveComma = true;
if (ParseOptionalAlignment(Alignment)) return true; if (EatIfPresent(lltok::kw_inalloca)) {
} else if (Lex.getKind() == lltok::MetadataVar) { IsInAlloca = true;
AteExtraComma = true; HaveComma = EatIfPresent(lltok::comma);
} else { }
if (ParseTypeAndValue(Size, SizeLoc, PFS) ||
ParseOptionalCommaAlign(Alignment, AteExtraComma)) if (HaveComma) {
return true; if (Lex.getKind() == lltok::kw_align) {
if (ParseOptionalAlignment(Alignment)) return true;
} else if (Lex.getKind() == lltok::MetadataVar) {
AteExtraComma = true;
} else {
if (ParseTypeAndValue(Size, SizeLoc, PFS) ||
ParseOptionalCommaAlign(Alignment, AteExtraComma))
return true;
}
} }
} }
if (Size && !Size->getType()->isIntegerTy()) if (Size && !Size->getType()->isIntegerTy())
return Error(SizeLoc, "element count must have integer type"); return Error(SizeLoc, "element count must have integer type");
Inst = new AllocaInst(Ty, Size, Alignment); AllocaInst *AI = new AllocaInst(Ty, Size, Alignment);
AI->setUsedWithInAlloca(IsInAlloca);
Inst = AI;
return AteExtraComma ? InstExtraComma : InstNormal; return AteExtraComma ? InstExtraComma : InstNormal;
} }

View File

@ -211,6 +211,7 @@ namespace llvm {
AtomicOrdering &Ordering); AtomicOrdering &Ordering);
bool ParseOptionalStackAlignment(unsigned &Alignment); bool ParseOptionalStackAlignment(unsigned &Alignment);
bool ParseOptionalCommaAlign(unsigned &Alignment, bool &AteExtraComma); bool ParseOptionalCommaAlign(unsigned &Alignment, bool &AteExtraComma);
bool ParseOptionalCommaInAlloca(bool &IsInAlloca);
bool ParseIndexList(SmallVectorImpl<unsigned> &Indices,bool &AteExtraComma); bool ParseIndexList(SmallVectorImpl<unsigned> &Indices,bool &AteExtraComma);
bool ParseIndexList(SmallVectorImpl<unsigned> &Indices) { bool ParseIndexList(SmallVectorImpl<unsigned> &Indices) {
bool AteExtraComma; bool AteExtraComma;

View File

@ -92,6 +92,13 @@ bool Argument::hasInAllocaAttr() const {
hasAttribute(getArgNo()+1, Attribute::InAlloca); hasAttribute(getArgNo()+1, Attribute::InAlloca);
} }
bool Argument::hasByValOrInAllocaAttr() const {
if (!getType()->isPointerTy()) return false;
AttributeSet Attrs = getParent()->getAttributes();
return Attrs.hasAttribute(getArgNo() + 1, Attribute::ByVal) ||
Attrs.hasAttribute(getArgNo() + 1, Attribute::InAlloca);
}
unsigned Argument::getParamAlignment() const { unsigned Argument::getParamAlignment() const {
assert(getType()->isPointerTy() && "Only pointers have alignments"); assert(getType()->isPointerTy() && "Only pointers have alignments");
return getParent()->getParamAlignment(getArgNo()+1); return getParent()->getParamAlignment(getArgNo()+1);

View File

@ -893,7 +893,8 @@ void AllocaInst::setAlignment(unsigned Align) {
assert((Align & (Align-1)) == 0 && "Alignment is not a power of 2!"); assert((Align & (Align-1)) == 0 && "Alignment is not a power of 2!");
assert(Align <= MaximumAlignment && assert(Align <= MaximumAlignment &&
"Alignment is greater than MaximumAlignment!"); "Alignment is greater than MaximumAlignment!");
setInstructionSubclassData(Log2_32(Align) + 1); setInstructionSubclassData((getSubclassDataFromInstruction() & ~31) |
(Log2_32(Align) + 1));
assert(getAlignment() == Align && "Alignment representation error!"); assert(getAlignment() == Align && "Alignment representation error!");
} }
@ -916,7 +917,7 @@ bool AllocaInst::isStaticAlloca() const {
// Must be in the entry block. // Must be in the entry block.
const BasicBlock *Parent = getParent(); const BasicBlock *Parent = getParent();
return Parent == &Parent->getParent()->front(); return Parent == &Parent->getParent()->front() && !isUsedWithInAlloca();
} }
//===----------------------------------------------------------------------===// //===----------------------------------------------------------------------===//

View File

@ -0,0 +1,16 @@
; RUN: llvm-as %s -o /dev/null
define void @a() {
entry:
%0 = alloca i32, inalloca
%1 = alloca [2 x i32], inalloca
%2 = alloca i32, inalloca, i32 2
%3 = alloca i32, inalloca, i32 2, align 16
%4 = alloca i32, inalloca, i32 2, align 16, !foo !0
%5 = alloca i32, i32 2, align 16, !foo !0
%6 = alloca i32, i32 2, align 16
ret void
}
!0 = metadata !{i32 662302, null}
!foo = !{ !0 }

View File

@ -2,7 +2,7 @@
declare void @h(i32, ...) declare void @h(i32, ...)
define void @i() { define void @i() {
%args = alloca i32 %args = alloca i32, inalloca
call void (i32, ...)* @h(i32 1, i32* inalloca %args, i32 3) call void (i32, ...)* @h(i32 1, i32* inalloca %args, i32 3)
; CHECK: inalloca isn't on the last argument! ; CHECK: inalloca isn't on the last argument!
ret void ret void

View File

@ -6,7 +6,7 @@ declare void @doit(i64* inalloca %a)
define void @a() { define void @a() {
entry: entry:
%a = alloca [2 x i32] %a = alloca [2 x i32], inalloca
%b = bitcast [2 x i32]* %a to i64* %b = bitcast [2 x i32]* %a to i64*
call void @doit(i64* inalloca %b) call void @doit(i64* inalloca %b)
ret void ret void
@ -14,8 +14,26 @@ entry:
define void @b() { define void @b() {
entry: entry:
%a = alloca i64 %a = alloca i64, inalloca
call void @doit(i64* inalloca %a) call void @doit(i64* inalloca %a)
call void @doit(i64* inalloca %a) call void @doit(i64* inalloca %a)
ret void ret void
} }
define void @c(i1 %cond) {
entry:
br i1 %cond, label %if, label %else
if:
%a = alloca i64, inalloca
br label %call
else:
%b = alloca i64, inalloca
br label %call
call:
%args = phi i64* [ %a, %if ], [ %b, %else ]
call void @doit(i64* inalloca %args)
ret void
}