[llvm] r199525 - Add an inalloca flag to allocas

Reid Kleckner reid at kleckner.net
Fri Jan 17 15:58:17 PST 2014


Author: rnk
Date: Fri Jan 17 17:58:17 2014
New Revision: 199525

URL: http://llvm.org/viewvc/llvm-project?rev=199525&view=rev
Log:
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

Added:
    llvm/trunk/test/Assembler/inalloca.ll
Modified:
    llvm/trunk/docs/LangRef.rst
    llvm/trunk/include/llvm/IR/Argument.h
    llvm/trunk/include/llvm/IR/Instructions.h
    llvm/trunk/lib/AsmParser/LLParser.cpp
    llvm/trunk/lib/AsmParser/LLParser.h
    llvm/trunk/lib/IR/Function.cpp
    llvm/trunk/lib/IR/Instructions.cpp
    llvm/trunk/test/Verifier/inalloca-vararg.ll
    llvm/trunk/test/Verifier/inalloca2.ll

Modified: llvm/trunk/docs/LangRef.rst
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/docs/LangRef.rst?rev=199525&r1=199524&r2=199525&view=diff
==============================================================================
--- llvm/trunk/docs/LangRef.rst (original)
+++ llvm/trunk/docs/LangRef.rst Fri Jan 17 17:58:17 2014
@@ -778,19 +778,16 @@ Currently, only the following parameter
 .. 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:
 """""""""

Modified: llvm/trunk/include/llvm/IR/Argument.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/IR/Argument.h?rev=199525&r1=199524&r2=199525&view=diff
==============================================================================
--- llvm/trunk/include/llvm/IR/Argument.h (original)
+++ llvm/trunk/include/llvm/IR/Argument.h Fri Jan 17 17:58:17 2014
@@ -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;
 

Modified: llvm/trunk/include/llvm/IR/Instructions.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/IR/Instructions.h?rev=199525&r1=199524&r2=199525&view=diff
==============================================================================
--- llvm/trunk/include/llvm/IR/Instructions.h (original)
+++ llvm/trunk/include/llvm/IR/Instructions.h Fri Jan 17 17:58:17 2014
@@ -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);

Modified: llvm/trunk/lib/AsmParser/LLParser.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/AsmParser/LLParser.cpp?rev=199525&r1=199524&r2=199525&view=diff
==============================================================================
--- llvm/trunk/lib/AsmParser/LLParser.cpp (original)
+++ llvm/trunk/lib/AsmParser/LLParser.cpp Fri Jan 17 17:58:17 2014
@@ -4069,31 +4069,42 @@ bool LLParser::ParseCall(Instruction *&I
 //===----------------------------------------------------------------------===//
 
 /// 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;
 }
 

Modified: llvm/trunk/lib/AsmParser/LLParser.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/AsmParser/LLParser.h?rev=199525&r1=199524&r2=199525&view=diff
==============================================================================
--- llvm/trunk/lib/AsmParser/LLParser.h (original)
+++ llvm/trunk/lib/AsmParser/LLParser.h Fri Jan 17 17:58:17 2014
@@ -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;

Modified: llvm/trunk/lib/IR/Function.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/IR/Function.cpp?rev=199525&r1=199524&r2=199525&view=diff
==============================================================================
--- llvm/trunk/lib/IR/Function.cpp (original)
+++ llvm/trunk/lib/IR/Function.cpp Fri Jan 17 17:58:17 2014
@@ -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);

Modified: llvm/trunk/lib/IR/Instructions.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/IR/Instructions.cpp?rev=199525&r1=199524&r2=199525&view=diff
==============================================================================
--- llvm/trunk/lib/IR/Instructions.cpp (original)
+++ llvm/trunk/lib/IR/Instructions.cpp Fri Jan 17 17:58:17 2014
@@ -893,7 +893,8 @@ void AllocaInst::setAlignment(unsigned A
   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();
 }
 
 //===----------------------------------------------------------------------===//

Added: llvm/trunk/test/Assembler/inalloca.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Assembler/inalloca.ll?rev=199525&view=auto
==============================================================================
--- llvm/trunk/test/Assembler/inalloca.ll (added)
+++ llvm/trunk/test/Assembler/inalloca.ll Fri Jan 17 17:58:17 2014
@@ -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 }

Modified: llvm/trunk/test/Verifier/inalloca-vararg.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Verifier/inalloca-vararg.ll?rev=199525&r1=199524&r2=199525&view=diff
==============================================================================
--- llvm/trunk/test/Verifier/inalloca-vararg.ll (original)
+++ llvm/trunk/test/Verifier/inalloca-vararg.ll Fri Jan 17 17:58:17 2014
@@ -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

Modified: llvm/trunk/test/Verifier/inalloca2.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Verifier/inalloca2.ll?rev=199525&r1=199524&r2=199525&view=diff
==============================================================================
--- llvm/trunk/test/Verifier/inalloca2.ll (original)
+++ llvm/trunk/test/Verifier/inalloca2.ll Fri Jan 17 17:58:17 2014
@@ -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
+}





More information about the llvm-commits mailing list