summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--docs/LangRef.rst25
-rw-r--r--include/llvm/IR/Argument.h5
-rw-r--r--include/llvm/IR/Instructions.h16
-rw-r--r--lib/AsmParser/LLParser.cpp31
-rw-r--r--lib/AsmParser/LLParser.h1
-rw-r--r--lib/IR/Function.cpp7
-rw-r--r--lib/IR/Instructions.cpp5
-rw-r--r--test/Assembler/inalloca.ll16
-rwxr-xr-xtest/Verifier/inalloca-vararg.ll2
-rw-r--r--test/Verifier/inalloca2.ll22
10 files changed, 100 insertions, 30 deletions
diff --git a/docs/LangRef.rst b/docs/LangRef.rst
index a767700636..8bb834b45e 100644
--- a/docs/LangRef.rst
+++ b/docs/LangRef.rst
@@ -778,19 +778,16 @@ Currently, only the following parameter attributes are defined:
.. Warning:: This feature is unstable and not fully implemented.
The ``inalloca`` argument attribute allows the caller to take the
- address of all stack-allocated arguments to a ``call`` or ``invoke``
- before it executes. It is similar to ``byval`` in that it is used
- to pass arguments by value, but it guarantees that the argument will
- not be copied.
-
- To be :ref:`well formed <wellformed>`, an alloca may be used as an
- ``inalloca`` argument at most once. The attribute can only be
- applied to the last parameter, and it guarantees that they are
- passed in memory. The ``inalloca`` attribute cannot be used in
- 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``.
+ address of outgoing stack arguments. An ``inalloca`` argument must
+ be a pointer to stack memory produced by an ``alloca`` instruction.
+ The alloca, or argument allocation, must also be tagged with the
+ inalloca keyword. Only the past argument may have the ``inalloca``
+ attribute, and that argument is guaranteed to be passed in memory.
+
+ An argument allocation may be used by a call at most once because
+ the call may deallocate it. The ``inalloca`` attribute cannot be
+ used in conjunction with other attributes that affect argument
+ storage, like ``inreg``, ``nest``, ``sret``, or ``byval``.
When the call site is reached, the argument allocation must have
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:
"""""""""
diff --git a/include/llvm/IR/Argument.h b/include/llvm/IR/Argument.h
index 9ba51bc213..7c1ebf6dff 100644
--- a/include/llvm/IR/Argument.h
+++ b/include/llvm/IR/Argument.h
@@ -59,6 +59,11 @@ public:
/// containing function.
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.
unsigned getParamAlignment() const;
diff --git a/include/llvm/IR/Instructions.h b/include/llvm/IR/Instructions.h
index 0843d8fca3..eeea9945e8 100644
--- a/include/llvm/IR/Instructions.h
+++ b/include/llvm/IR/Instructions.h
@@ -101,7 +101,7 @@ public:
/// by the instruction.
///
unsigned getAlignment() const {
- return (1u << getSubclassDataFromInstruction()) >> 1;
+ return (1u << (getSubclassDataFromInstruction() & 31)) >> 1;
}
void setAlignment(unsigned Align);
@@ -110,6 +110,20 @@ public:
/// into the prolog/epilog code, so it is basically free.
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:
static inline bool classof(const Instruction *I) {
return (I->getOpcode() == Instruction::Alloca);
diff --git a/lib/AsmParser/LLParser.cpp b/lib/AsmParser/LLParser.cpp
index a1b5f9946c..ab4b48bf6e 100644
--- a/lib/AsmParser/LLParser.cpp
+++ b/lib/AsmParser/LLParser.cpp
@@ -4069,31 +4069,42 @@ bool LLParser::ParseCall(Instruction *&Inst, PerFunctionState &PFS,
//===----------------------------------------------------------------------===//
/// ParseAlloc
-/// ::= 'alloca' Type (',' TypeAndValue)? (',' OptionalInfo)?
+/// ::= 'alloca' Type (',' 'inalloca')? (',' TypeAndValue)? (',' OptionalInfo)?
int LLParser::ParseAlloc(Instruction *&Inst, PerFunctionState &PFS) {
Value *Size = 0;
LocTy SizeLoc;
unsigned Alignment = 0;
+ bool IsInAlloca = false;
Type *Ty = 0;
if (ParseType(Ty)) return true;
bool AteExtraComma = false;
if (EatIfPresent(lltok::comma)) {
- 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;
+ bool HaveComma = true;
+ if (EatIfPresent(lltok::kw_inalloca)) {
+ IsInAlloca = true;
+ HaveComma = EatIfPresent(lltok::comma);
+ }
+
+ if (HaveComma) {
+ 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())
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;
}
diff --git a/lib/AsmParser/LLParser.h b/lib/AsmParser/LLParser.h
index c62979e6f2..d25374ff05 100644
--- a/lib/AsmParser/LLParser.h
+++ b/lib/AsmParser/LLParser.h
@@ -211,6 +211,7 @@ namespace llvm {
AtomicOrdering &Ordering);
bool ParseOptionalStackAlignment(unsigned &Alignment);
bool ParseOptionalCommaAlign(unsigned &Alignment, bool &AteExtraComma);
+ bool ParseOptionalCommaInAlloca(bool &IsInAlloca);
bool ParseIndexList(SmallVectorImpl<unsigned> &Indices,bool &AteExtraComma);
bool ParseIndexList(SmallVectorImpl<unsigned> &Indices) {
bool AteExtraComma;
diff --git a/lib/IR/Function.cpp b/lib/IR/Function.cpp
index bb6bef7bd0..c1fa3720e3 100644
--- a/lib/IR/Function.cpp
+++ b/lib/IR/Function.cpp
@@ -92,6 +92,13 @@ bool Argument::hasInAllocaAttr() const {
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 {
assert(getType()->isPointerTy() && "Only pointers have alignments");
return getParent()->getParamAlignment(getArgNo()+1);
diff --git a/lib/IR/Instructions.cpp b/lib/IR/Instructions.cpp
index 761f60063f..5a50b73650 100644
--- a/lib/IR/Instructions.cpp
+++ b/lib/IR/Instructions.cpp
@@ -893,7 +893,8 @@ void AllocaInst::setAlignment(unsigned Align) {
assert((Align & (Align-1)) == 0 && "Alignment is not a power of 2!");
assert(Align <= MaximumAlignment &&
"Alignment is greater than MaximumAlignment!");
- setInstructionSubclassData(Log2_32(Align) + 1);
+ setInstructionSubclassData((getSubclassDataFromInstruction() & ~31) |
+ (Log2_32(Align) + 1));
assert(getAlignment() == Align && "Alignment representation error!");
}
@@ -916,7 +917,7 @@ bool AllocaInst::isStaticAlloca() const {
// Must be in the entry block.
const BasicBlock *Parent = getParent();
- return Parent == &Parent->getParent()->front();
+ return Parent == &Parent->getParent()->front() && !isUsedWithInAlloca();
}
//===----------------------------------------------------------------------===//
diff --git a/test/Assembler/inalloca.ll b/test/Assembler/inalloca.ll
new file mode 100644
index 0000000000..94fac26265
--- /dev/null
+++ b/test/Assembler/inalloca.ll
@@ -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 }
diff --git a/test/Verifier/inalloca-vararg.ll b/test/Verifier/inalloca-vararg.ll
index 6729c42830..8521ebce2d 100755
--- a/test/Verifier/inalloca-vararg.ll
+++ b/test/Verifier/inalloca-vararg.ll
@@ -2,7 +2,7 @@
declare void @h(i32, ...)
define void @i() {
- %args = alloca i32
+ %args = alloca i32, inalloca
call void (i32, ...)* @h(i32 1, i32* inalloca %args, i32 3)
; CHECK: inalloca isn't on the last argument!
ret void
diff --git a/test/Verifier/inalloca2.ll b/test/Verifier/inalloca2.ll
index ed65667dc3..e4e81be386 100644
--- a/test/Verifier/inalloca2.ll
+++ b/test/Verifier/inalloca2.ll
@@ -6,7 +6,7 @@ declare void @doit(i64* inalloca %a)
define void @a() {
entry:
- %a = alloca [2 x i32]
+ %a = alloca [2 x i32], inalloca
%b = bitcast [2 x i32]* %a to i64*
call void @doit(i64* inalloca %b)
ret void
@@ -14,8 +14,26 @@ entry:
define void @b() {
entry:
- %a = alloca i64
+ %a = alloca i64, inalloca
call void @doit(i64* inalloca %a)
call void @doit(i64* inalloca %a)
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
+}