Add an inalloca flag to allocas
authorReid Kleckner <reid@kleckner.net>
Fri, 17 Jan 2014 23:58:17 +0000 (23:58 +0000)
committerReid Kleckner <reid@kleckner.net>
Fri, 17 Jan 2014 23:58:17 +0000 (23:58 +0000)
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

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@199525 91177308-0d34-0410-b5e6-96231b3b80d8

docs/LangRef.rst
include/llvm/IR/Argument.h
include/llvm/IR/Instructions.h
lib/AsmParser/LLParser.cpp
lib/AsmParser/LLParser.h
lib/IR/Function.cpp
lib/IR/Instructions.cpp
test/Assembler/inalloca.ll [new file with mode: 0644]
test/Verifier/inalloca-vararg.ll
test/Verifier/inalloca2.ll

index a76770063657d1c1ba811067630c97e101d2870d..8bb834b45ed36aa8a2458801a5db0d653454b62e 100644 (file)
@@ -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:
 """""""""
index 9ba51bc2137467c8e6de8a6e0b13eba23d186a7a..7c1ebf6dfffd36aed628d548cb7d950797e8aeee 100644 (file)
@@ -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;
 
index 0843d8fca3e201fef0c35072dd008633ade1ee06..eeea9945e8a46d98f110eb9c1abc94c7cfa00254 100644 (file)
@@ -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);
index a1b5f9946c96bbceee5ef05e516b378499d70804..ab4b48bf6eca5902bb4706b634a7c236b251674a 100644 (file)
@@ -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;
 }
 
index c62979e6f29e22c5a8ab74b517918861601b0458..d25374ff0531bf071bc60229b8e34479151b0d27 100644 (file)
@@ -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;
index bb6bef7bd026ab2a4f276deb9f3256d7752fc128..c1fa3720e3f26942d7655b7ced4d16cbf8939cb5 100644 (file)
@@ -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);
index 761f60063fabcaf8ffcfdc97286696f6a052578c..5a50b73650051791e3aac5af07d1e9d5f5d741d0 100644 (file)
@@ -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 (file)
index 0000000..94fac26
--- /dev/null
@@ -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 }
index 6729c4283046bd61a8df4195e8d5412e7eea46df..8521ebce2d9c129ee2066e978bb05060d3a24777 100755 (executable)
@@ -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
index ed65667dc30808ec721328190185392f9964ef6b..e4e81be38615d0d666ae4554f4c6273c2d7cc903 100644 (file)
@@ -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
+}