Support for trampolines, except for X86 codegen which is
authorDuncan Sands <baldrick@free.fr>
Fri, 27 Jul 2007 12:58:54 +0000 (12:58 +0000)
committerDuncan Sands <baldrick@free.fr>
Fri, 27 Jul 2007 12:58:54 +0000 (12:58 +0000)
still under discussion.

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

20 files changed:
docs/LangRef.html
include/llvm/CodeGen/SelectionDAGNodes.h
include/llvm/Intrinsics.td
include/llvm/ParameterAttributes.h
include/llvm/Target/TargetLowering.h
lib/AsmParser/Lexer.l
lib/AsmParser/llvmAsmParser.y
lib/CodeGen/SelectionDAG/LegalizeDAG.cpp
lib/CodeGen/SelectionDAG/SelectionDAG.cpp
lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp
lib/Target/ARM/ARMISelLowering.cpp
lib/Target/ARM/ARMISelLowering.h
lib/Target/Alpha/AlphaISelLowering.cpp
lib/Target/IA64/IA64ISelLowering.cpp
lib/Target/Mips/MipsISelLowering.cpp
lib/Target/PowerPC/PPCISelLowering.cpp
lib/Target/Sparc/SparcISelDAGToDAG.cpp
lib/Target/TargetCallingConv.td
lib/VMCore/Function.cpp
lib/VMCore/Verifier.cpp

index 6ebbb2930774b9a75fce956acd11d6f31dcf4b34..2cf74c2824f1572f0bc9e3dc5a7de41d7be5ce05 100644 (file)
           <li><a href="#int_memory_barrier">'<tt>llvm.memory.barrier</tt>' Intrinsic</a></li>
         </ol>
       </li>
+      <li><a href="#int_trampoline">Trampoline Intrinsics</a>
+        <ol>
+          <li><a href="#int_it">'<tt>llvm.init.trampoline</tt>' Intrinsic</a></li>
+          <li><a href="#int_at">'<tt>llvm.adjust.trampoline</tt>' Intrinsic</a></li>
+        </ol>
+      </li>
       <li><a href="#int_general">General intrinsics</a>
         <ol>
           <li><a href="#int_var_annotation">
@@ -5121,6 +5127,105 @@ declare void @llvm.memory.barrier( i1 &lt;ll&gt;, i1 &lt;ls&gt;, i1 &lt;sl&gt;,
 </pre>
 </div>
 
+<!-- ======================================================================= -->
+<div class="doc_subsection">
+  <a name="int_trampoline">Trampoline Intrinsics</a>
+</div>
+
+<div class="doc_text">
+<p>
+  These intrinsics make it possible to excise one parameter, marked with
+  the <tt>nest</tt> attribute, from a function.  The result is a callable
+  function pointer lacking the nest parameter - the caller does not need
+  to provide a value for it.  Instead, the value to use is stored in
+  advance in a "trampoline", a block of memory usually allocated
+  on the stack, which also contains code to splice the nest value into the
+  argument list.  This is used to implement the GCC nested function address
+  extension.
+</p>
+<p>
+  For example, if the function is
+  <tt>i32 f(i8* nest  %c, i32 %x, i32 %y)</tt> then the resulting function
+  pointer has signature <tt>i32 (i32, i32)*</tt>.  It can be created as follows:
+<pre>
+  %tramp1 = alloca [10 x i8], align 4 ; size and alignment only correct for X86
+  %tramp = getelementptr [10 x i8]* %tramp1, i32 0, i32 0
+  call void @llvm.init.trampoline( i8* %tramp, i8* bitcast (i32 (i8* nest , i32, i32)* @f to i8*), i8* %nval )
+  %adj = call i8* @llvm.adjust.trampoline( i8* %tramp )
+  %fp = bitcast i8* %adj to i32 (i32, i32)*
+</pre>
+  The call <tt>%val = call i32 %fp( i32 %x, i32 %y )</tt> is then equivalent to
+  <tt>%val = call i32 %f( i8* %nval, i32 %x, i32 %y )</tt>.
+</p>
+<p>
+  Trampolines are currently only supported on the X86 architecture.
+</p>
+</div>
+
+<!-- _______________________________________________________________________ -->
+<div class="doc_subsubsection">
+  <a name="int_it">'<tt>llvm.init.trampoline</tt>' Intrinsic</a>
+</div>
+<div class="doc_text">
+<h5>Syntax:</h5>
+<pre>
+declare void @llvm.init.trampoline(i8* &lt;tramp&gt;, i8* &lt;func&gt;, i8* &lt;nval&gt;)
+</pre>
+<h5>Overview:</h5>
+<p>
+  This initializes the memory pointed to by <tt>tramp</tt> as a trampoline.
+</p>
+<h5>Arguments:</h5>
+<p>
+  The <tt>llvm.init.trampoline</tt> intrinsic takes three arguments, all
+  pointers.  The <tt>tramp</tt> argument must point to a sufficiently large
+  and sufficiently aligned block of memory; this memory is written to by the
+  intrinsic.  Currently LLVM provides no help in determining just how big and
+  aligned the memory needs to be.  The <tt>func</tt> argument must hold a
+  function bitcast to an <tt>i8*</tt>.
+</p>
+<h5>Semantics:</h5>
+<p>
+  The block of memory pointed to by <tt>tramp</tt> is filled with target
+  dependent code, turning it into a function.
+  The new function's signature is the same as that of <tt>func</tt> with
+  any arguments marked with the <tt>nest</tt> attribute removed.  At most
+  one such <tt>nest</tt> argument is allowed, and it must be of pointer
+  type.  Calling the new function is equivalent to calling <tt>func</tt>
+  with the same argument list, but with <tt>nval</tt> used for the missing
+  <tt>nest</tt> argument.
+</p>
+</div>
+
+<!-- _______________________________________________________________________ -->
+<div class="doc_subsubsection">
+  <a name="int_at">'<tt>llvm.adjust.trampoline</tt>' Intrinsic</a>
+</div>
+<div class="doc_text">
+<h5>Syntax:</h5>
+<pre>
+declare i8* @llvm.adjust.trampoline(i8* &lt;tramp&gt;)
+</pre>
+<h5>Overview:</h5>
+<p>
+  This intrinsic returns a function pointer suitable for executing
+  the trampoline code pointed to by <tt>tramp</tt>.
+</p>
+<h5>Arguments:</h5>
+<p>
+  The <tt>llvm.adjust.trampoline</tt> takes one argument, a pointer to a
+  trampoline initialized by the
+  <a href="#int_it">'<tt>llvm.init.trampoline</tt>' intrinsic</a>.
+</p>
+<h5>Semantics:</h5>
+<p>
+  A function pointer that can be used to execute the trampoline code in
+  <tt>tramp</tt> is returned.  The returned value should be bitcast to an
+  <a href="#int_trampoline">appropriate function pointer type</a>
+  before being called.
+</p>
+</div>
+
 <!-- ======================================================================= -->
 <div class="doc_subsection">
   <a name="int_general">General Intrinsics</a>
index a74c04836f966ca798e63741757121ddd9908237..ce7dda402806775f5f379e5309e46fdebed41b3d 100644 (file)
@@ -66,6 +66,8 @@ namespace ISD {
     StructReturnOffs  = 3,
     ByVal             = 1<<4,  ///< Struct passed by value
     ByValOffs         = 4,
+    Nest              = 1<<5,  ///< Parameter is nested function static chain
+    NestOffs          = 5,
     OrigAlignment     = 0x1F<<27,
     OrigAlignmentOffs = 27
   };
@@ -528,7 +530,19 @@ namespace ISD {
     // number, then a column then a file id (provided by MachineModuleInfo.) It
     // produces a token chain as output.
     DEBUG_LOC,
-    
+
+    // ADJUST_TRAMP - This corresponds to the adjust_trampoline intrinsic.
+    // It takes a value as input and returns a value as output.
+    ADJUST_TRAMP,
+
+    // TRAMPOLINE - This corresponds to the init_trampoline intrinsic.
+    // It takes as input a token chain, the pointer to the trampoline,
+    // the pointer to the nested function, the pointer to pass for the
+    // 'nest' parameter, a SRCVALUE for the trampoline and another for
+    // the nested function (allowing targets to access the original
+    // Function*).  It produces a token chain as output.
+    TRAMPOLINE,
+
     // BUILTIN_OP_END - This must be the last enum value in this list.
     BUILTIN_OP_END
   };
index e5bb2f62134710657d5b855d38ce00ebf2ec3362..205eac509a9b625630c936198591e6a1e6b3afc3 100644 (file)
@@ -247,6 +247,14 @@ def int_var_annotation : Intrinsic<[llvm_void_ty, llvm_ptr_ty, llvm_ptr_ty,
                                     llvm_ptr_ty, llvm_i32_ty], 
                                     [], "llvm.var.annotation">;
 
+//===------------------------ Trampoline Intrinsics -----------------------===//
+//
+def int_init_trampoline   : Intrinsic<[llvm_void_ty, llvm_ptr_ty, llvm_ptr_ty,
+                                       llvm_ptr_ty], []>,
+                            GCCBuiltin<"__builtin_init_trampoline">;
+def int_adjust_trampoline : Intrinsic<[llvm_ptr_ty, llvm_ptr_ty], [IntrNoMem]>,
+                            GCCBuiltin<"__builtin_adjust_trampoline">;
+
 //===----------------------------------------------------------------------===//
 // Target-specific intrinsics
 //===----------------------------------------------------------------------===//
index b1cb966e0afa600d1f1d5af9a3d81bc2d5729a41..e2890f5a711324a31823008438be19a7bb232954 100644 (file)
@@ -30,14 +30,15 @@ namespace ParamAttr {
 /// @brief Function parameter attributes.
 enum Attributes {
   None       = 0,      ///< No attributes have been set
-  ZExt       = 1 << 0, ///< zero extended before/after call
-  SExt       = 1 << 1, ///< sign extended before/after call
-  NoReturn   = 1 << 2, ///< mark the function as not returning
-  InReg      = 1 << 3, ///< force argument to be passed in register
-  StructRet  = 1 << 4, ///< hidden pointer to structure to return
+  ZExt       = 1 << 0, ///< Zero extended before/after call
+  SExt       = 1 << 1, ///< Sign extended before/after call
+  NoReturn   = 1 << 2, ///< Mark the function as not returning
+  InReg      = 1 << 3, ///< Force argument to be passed in register
+  StructRet  = 1 << 4, ///< Hidden pointer to structure to return
   NoUnwind   = 1 << 5, ///< Function doesn't unwind stack
-  NoAlias    = 1 << 6, ///< Considered to not alias after call.
-  ByVal      = 1 << 7  ///< Pass structure by value
+  NoAlias    = 1 << 6, ///< Considered to not alias after call
+  ByVal      = 1 << 7, ///< Pass structure by value
+  Nest       = 1 << 8  ///< Nested function static chain
 };
 
 }
index a95a03bca0d5656fa17405ae1a51d9c443c25689..a1aa50c9c793fc5ec79077c4012f043b23cf2429 100644 (file)
@@ -812,8 +812,10 @@ public:
     bool isZExt;
     bool isInReg;
     bool isSRet;
+    bool isNest;
 
-    ArgListEntry():isSExt(false), isZExt(false), isInReg(false), isSRet(false) { };
+    ArgListEntry() : isSExt(false), isZExt(false), isInReg(false),
+      isSRet(false), isNest(false) { };
   };
   typedef std::vector<ArgListEntry> ArgListTy;
   virtual std::pair<SDOperand, SDOperand>
index 24467cf606d96bde9dddc4da811bbf37d68ae3a6..6b8bba5d68d4dc97e1878feb51b397c9f7c67cee 100644 (file)
@@ -233,6 +233,7 @@ nounwind        { return NOUNWIND; }
 noreturn        { return NORETURN; }
 noalias         { return NOALIAS; }
 byval           { return BYVAL; }
+nest            { return NEST; }
 
 void            { RET_TY(Type::VoidTy,  VOID);  }
 float           { RET_TY(Type::FloatTy, FLOAT); }
index 0936af3a4d047156e98bd60e51b095304d17ff9f..0cc7a9831a2da6e2765e8d59ec00a84480708e0d 100644 (file)
@@ -1101,7 +1101,7 @@ Module *llvm::RunVMAsmParser(const char * AsmString, Module * M) {
 %token <OtherOpVal> EXTRACTELEMENT INSERTELEMENT SHUFFLEVECTOR
 
 // Function Attributes
-%token SIGNEXT ZEROEXT NORETURN INREG SRET NOUNWIND NOALIAS BYVAL
+%token SIGNEXT ZEROEXT NORETURN INREG SRET NOUNWIND NOALIAS BYVAL NEST
 
 // Visibility Styles
 %token DEFAULT HIDDEN PROTECTED
@@ -1229,7 +1229,8 @@ ParamAttr     : ZEROEXT { $$ = ParamAttr::ZExt;      }
               | INREG   { $$ = ParamAttr::InReg;     }
               | SRET    { $$ = ParamAttr::StructRet; }
               | NOALIAS { $$ = ParamAttr::NoAlias;   }
-              | BYVAL   { $$ = ParamAttr::ByVal;   }
+              | BYVAL   { $$ = ParamAttr::ByVal;     }
+              | NEST    { $$ = ParamAttr::Nest;      }
               ;
 
 OptParamAttrs : /* empty */  { $$ = ParamAttr::None; }
index 4131ed9ecf75628ebfbc1a4c7b02fa9c554dcade..078cbf3d7a21e6d6ff56e3b3f3697b57d4bd6029 100644 (file)
@@ -3156,6 +3156,31 @@ SDOperand SelectionDAGLegalize::LegalizeOp(SDOperand Op) {
     }
     break;
   }
+  case ISD::ADJUST_TRAMP: {
+    Tmp1 = LegalizeOp(Node->getOperand(0));
+    switch (TLI.getOperationAction(Node->getOpcode(), Node->getValueType(0))) {
+    default: assert(0 && "This action is not supported yet!");
+    case TargetLowering::Custom:
+      Result = DAG.UpdateNodeOperands(Result, Tmp1);
+      Result = TLI.LowerOperation(Result, DAG);
+      if (Result.Val) break;
+      // FALL THROUGH
+    case TargetLowering::Expand:
+      Result = Tmp1;
+      break;
+    }
+    break;
+  }
+  case ISD::TRAMPOLINE: {
+    SDOperand Ops[6];
+    for (unsigned i = 0; i != 6; ++i)
+      Ops[i] = LegalizeOp(Node->getOperand(i));
+    Result = DAG.UpdateNodeOperands(Result, Ops, 6);
+    // The only option for this node is to custom lower it.
+    Result = TLI.LowerOperation(Result, DAG);
+    assert(Result.Val && "Should always custom lower!");
+    break;
+  }
   }
   
   assert(Result.getValueType() == Op.getValueType() &&
index d4d984b13f5bb8357db15d16b09db70448b820eb..4b7863d896c8c6b95c0838b373011cef73e5490d 100644 (file)
@@ -3513,6 +3513,10 @@ std::string SDNode::getOperationName(const SelectionDAG *G) const {
   case ISD::LOCATION: return "location";
   case ISD::DEBUG_LOC: return "debug_loc";
 
+  // Trampolines
+  case ISD::ADJUST_TRAMP: return "adjust_tramp";
+  case ISD::TRAMPOLINE:   return "trampoline";
+
   case ISD::CONDCODE:
     switch (cast<CondCodeSDNode>(this)->get()) {
     default: assert(0 && "Unknown setcc condition!");
index 05578fe31cdebb91c9249f01bececd0c9742aca8..ce09eb4f4874eee9010ac9706b79dace1077b813 100644 (file)
@@ -2863,6 +2863,28 @@ SelectionDAGLowering::visitIntrinsicCall(CallInst &I, unsigned Intrinsic) {
   case Intrinsic::var_annotation:
     // Discard annotate attributes
     return 0;
+
+  case Intrinsic::adjust_trampoline: {
+    SDOperand Arg = getValue(I.getOperand(1));
+    setValue(&I, DAG.getNode(ISD::ADJUST_TRAMP, TLI.getPointerTy(), Arg));
+    return 0;
+  }
+
+  case Intrinsic::init_trampoline: {
+    const Function *F =
+      cast<Function>(IntrinsicInst::StripPointerCasts(I.getOperand(2)));
+
+    SDOperand Ops[6];
+    Ops[0] = getRoot();
+    Ops[1] = getValue(I.getOperand(1));
+    Ops[2] = getValue(I.getOperand(2));
+    Ops[3] = getValue(I.getOperand(3));
+    Ops[4] = DAG.getSrcValue(I.getOperand(1));
+    Ops[5] = DAG.getSrcValue(F);
+
+    DAG.setRoot(DAG.getNode(ISD::TRAMPOLINE, MVT::Other, Ops, 6));
+    return 0;
+  }
   }
 }
 
@@ -2892,6 +2914,7 @@ void SelectionDAGLowering::LowerCallTo(Instruction &I,
     Entry.isZExt  = Attrs && Attrs->paramHasAttr(attrInd, ParamAttr::ZExt);
     Entry.isInReg = Attrs && Attrs->paramHasAttr(attrInd, ParamAttr::InReg);
     Entry.isSRet  = Attrs && Attrs->paramHasAttr(attrInd, ParamAttr::StructRet);
+    Entry.isNest  = Attrs && Attrs->paramHasAttr(attrInd, ParamAttr::Nest);
     Args.push_back(Entry);
   }
 
@@ -3827,6 +3850,8 @@ TargetLowering::LowerArguments(Function &F, SelectionDAG &DAG) {
       Flags |= ISD::ParamFlags::StructReturn;
     if (Attrs && Attrs->paramHasAttr(j, ParamAttr::ByVal))
       Flags |= ISD::ParamFlags::ByVal;
+    if (Attrs && Attrs->paramHasAttr(j, ParamAttr::Nest))
+      Flags |= ISD::ParamFlags::Nest;
     Flags |= (OriginalAlignment << ISD::ParamFlags::OrigAlignmentOffs);
     
     switch (getTypeAction(VT)) {
@@ -3945,6 +3970,8 @@ TargetLowering::LowerCallTo(SDOperand Chain, const Type *RetTy,
       Flags |= ISD::ParamFlags::InReg;
     if (Args[i].isSRet)
       Flags |= ISD::ParamFlags::StructReturn;
+    if (Args[i].isNest)
+      Flags |= ISD::ParamFlags::Nest;
     Flags |= OriginalAlignment << ISD::ParamFlags::OrigAlignmentOffs;
     
     switch (getTypeAction(VT)) {
index 6f63fbdcb31132b5e0557a37a1b89a22d646cdbb..a274c14eabff7a1f828ac7177ecbf55016207d03 100644 (file)
@@ -190,7 +190,12 @@ ARMTargetLowering::ARMTargetLowering(TargetMachine &TM)
   setOperationAction(ISD::MEMSET          , MVT::Other, Expand);
   setOperationAction(ISD::MEMCPY          , MVT::Other, Custom);
   setOperationAction(ISD::MEMMOVE         , MVT::Other, Expand);
-  
+
+  if (Subtarget->isThumb())
+    setOperationAction(ISD::ADJUST_TRAMP, MVT::i32, Custom);
+  else
+    setOperationAction(ISD::ADJUST_TRAMP, MVT::i32, Expand);
+
   // Use the default implementation.
   setOperationAction(ISD::VASTART           , MVT::Other, Expand);
   setOperationAction(ISD::VAARG             , MVT::Other, Expand);
@@ -1413,6 +1418,14 @@ SDOperand ARMTargetLowering::LowerMEMCPY(SDOperand Op, SelectionDAG &DAG) {
   return Chain;
 }
 
+SDOperand ARMTargetLowering::LowerADJUST_TRAMP(SDOperand Op,
+                                                    SelectionDAG &DAG) {
+  // Thumb trampolines should be entered in thumb mode, so set the bottom bit
+  // of the address.
+  return DAG.getNode(ISD::OR, MVT::i32, Op.getOperand(0),
+                     DAG.getConstant(1, MVT::i32));
+}
+
 SDOperand ARMTargetLowering::LowerOperation(SDOperand Op, SelectionDAG &DAG) {
   switch (Op.getOpcode()) {
   default: assert(0 && "Don't know how to custom lower this!"); abort();
@@ -1444,6 +1457,7 @@ SDOperand ARMTargetLowering::LowerOperation(SDOperand Op, SelectionDAG &DAG) {
   case ISD::FRAMEADDR:     break;
   case ISD::GLOBAL_OFFSET_TABLE: return LowerGLOBAL_OFFSET_TABLE(Op, DAG);
   case ISD::MEMCPY:        return LowerMEMCPY(Op, DAG);
+  case ISD::ADJUST_TRAMP:  return LowerADJUST_TRAMP(Op, DAG);
   }
   return SDOperand();
 }
index 2b66f2332d2bcebf5ff0f9d69a9f07ea090d16ae..318657eb8e2a8c3194ae2d483919e6112afd1113 100644 (file)
@@ -138,6 +138,7 @@ namespace llvm {
     SDOperand LowerFORMAL_ARGUMENTS(SDOperand Op, SelectionDAG &DAG);
     SDOperand LowerBR_JT(SDOperand Op, SelectionDAG &DAG);
     SDOperand LowerMEMCPY(SDOperand Op, SelectionDAG &DAG);
+    SDOperand LowerADJUST_TRAMP(SDOperand Op, SelectionDAG &DAG);
   };
 }
 
index d4777b2c5f431e90f540e744e6ab9f62a0066b0a..adbf322dade42d6a173c3d16f229c122b261ccc5 100644 (file)
@@ -124,6 +124,9 @@ AlphaTargetLowering::AlphaTargetLowering(TargetMachine &TM) : TargetLowering(TM)
   setOperationAction(ISD::ExternalSymbol, MVT::i64, Custom);
   setOperationAction(ISD::GlobalTLSAddress, MVT::i64, Custom);
 
+  setOperationAction(ISD::ADJUST_TRAMP, MVT::i32, Expand);
+  setOperationAction(ISD::ADJUST_TRAMP, MVT::i64, Expand);
+
   setOperationAction(ISD::VASTART, MVT::Other, Custom);
   setOperationAction(ISD::VAEND,   MVT::Other, Expand);
   setOperationAction(ISD::VACOPY,  MVT::Other, Custom);
index 0237a9a47b67c22f2a4559a381c8e617906659ba..b9508a9cb35344f900f428a46de7d332218386b7 100644 (file)
@@ -97,6 +97,8 @@ IA64TargetLowering::IA64TargetLowering(TargetMachine &TM)
       setOperationAction(ISD::ROTR , MVT::i64  , Expand);
       setOperationAction(ISD::BSWAP, MVT::i64  , Expand);  // mux @rev
 
+      setOperationAction(ISD::ADJUST_TRAMP, MVT::i64, Expand);
+
       // VASTART needs to be custom lowered to use the VarArgsFrameIndex
       setOperationAction(ISD::VAARG             , MVT::Other, Custom);
       setOperationAction(ISD::VASTART           , MVT::Other, Custom);
index 790cdaf79f2c60e9165d9e269c991c2591096d30..33283365bfeae449cdde3b4e60c8390e9d666d1b 100644 (file)
@@ -102,6 +102,8 @@ MipsTargetLowering(MipsTargetMachine &TM): TargetLowering(TM)
   setOperationAction(ISD::STACKSAVE, MVT::Other, Expand);
   setOperationAction(ISD::STACKRESTORE, MVT::Other, Expand);
 
+  setOperationAction(ISD::ADJUST_TRAMP, MVT::i32, Expand);
+
   setStackPointerRegisterToSaveRestore(Mips::SP);
   computeRegisterProperties();
 }
index 6c2f3837b23da1fd9eefca49f53e6922b76cfc73..0ed1112fff2a96b310b59a4ad6097bcb3e3f638e 100644 (file)
@@ -169,7 +169,10 @@ PPCTargetLowering::PPCTargetLowering(PPCTargetMachine &TM)
   
   // RET must be custom lowered, to meet ABI requirements
   setOperationAction(ISD::RET               , MVT::Other, Custom);
-  
+
+  setOperationAction(ISD::ADJUST_TRAMP, MVT::i32, Expand);
+  setOperationAction(ISD::ADJUST_TRAMP, MVT::i64, Expand);
+
   // VASTART needs to be custom lowered to use the VarArgsFrameIndex
   setOperationAction(ISD::VASTART           , MVT::Other, Custom);
   
index 8c8b3f8d3ac533c7400be0af4112039f3fcc794e..536abc11cb7c487a30664870191168dc63ba4bfe 100644 (file)
@@ -215,7 +215,9 @@ SparcTargetLowering::SparcTargetLowering(TargetMachine &TM)
 
   // RET must be custom lowered, to meet ABI requirements
   setOperationAction(ISD::RET               , MVT::Other, Custom);
-  
+
+  setOperationAction(ISD::ADJUST_TRAMP, MVT::i32, Expand);
+
   // VASTART needs to be custom lowered to use the VarArgsFrameIndex.
   setOperationAction(ISD::VASTART           , MVT::Other, Custom);
   // VAARG needs to be lowered to not do unaligned accesses for doubles.
index 94193200eaa40866ea4f754ec57e3cf65aa418ac..176a848ec02bc4eddd17f0850b8c041c4c3b89dc 100644 (file)
@@ -45,6 +45,10 @@ class CCIfCC<string CC, CCAction A>
 /// the specified action.
 class CCIfInReg<CCAction A> : CCIf<"ArgFlags & ISD::ParamFlags::InReg", A> {}
 
+/// CCIfNest - If this argument is marked with the 'nest' attribute, apply
+/// the specified action.
+class CCIfNest<CCAction A> : CCIf<"ArgFlags & ISD::ParamFlags::Nest", A> {}
+
 /// CCIfNotVarArg - If the current function is not vararg - apply the action
 class CCIfNotVarArg<CCAction A> : CCIf<"!State.isVarArg()", A> {}
 
index dd781964a9174ad28bb215a4a1132fab8cf9352f..1374d55e7d9c755bd5d8d3bf75a8e787b834f458 100644 (file)
@@ -105,6 +105,8 @@ ParamAttrsList::getParamAttrsText(uint16_t Attrs) {
     Result += "sret ";  
   if (Attrs & ParamAttr::ByVal)
     Result += "byval ";
+  if (Attrs & ParamAttr::Nest)
+    Result += "nest ";
   return Result;
 }
 
index ffca88bfabc307a67c3f4ffc196f4298434698f4..de4050dadae566e861969176f1e147f2d6f5b649 100644 (file)
@@ -361,6 +361,7 @@ void Verifier::visitFunction(Function &F) {
 
   if (const ParamAttrsList *Attrs = FT->getParamAttrs()) {
     unsigned Idx = 1;
+    bool SawNest = false;
 
     Assert1(!Attrs->paramHasAttr(0, ParamAttr::ByVal),
             "Attribute ByVal should not apply to functions!", &F);
@@ -368,6 +369,8 @@ void Verifier::visitFunction(Function &F) {
             "Attribute SRet should not apply to functions!", &F);
     Assert1(!Attrs->paramHasAttr(0, ParamAttr::InReg),
             "Attribute InReg should not apply to functions!", &F);
+    Assert1(!Attrs->paramHasAttr(0, ParamAttr::Nest),
+            "Attribute Nest should not apply to functions!", &F);
 
     for (FunctionType::param_iterator I = FT->param_begin(), 
          E = FT->param_end(); I != E; ++I, ++Idx) {
@@ -391,6 +394,20 @@ void Verifier::visitFunction(Function &F) {
                 "Attribute ByVal should only apply to pointer to structs!", &F);
       }
 
+      if (Attrs->paramHasAttr(Idx, ParamAttr::Nest)) {
+        Assert1(!SawNest, "More than one parameter has attribute Nest!", &F);
+        SawNest = true;
+
+        Assert1(isa<PointerType>(FT->getParamType(Idx-1)),
+                "Attribute Nest should only apply to Pointer type!", &F);
+        Assert1(!Attrs->paramHasAttr(Idx, ParamAttr::ByVal),
+                "Attributes Nest and ByVal are incompatible!", &F);
+        Assert1(!Attrs->paramHasAttr(Idx, ParamAttr::InReg),
+                "Attributes Nest and InReg are incompatible!", &F);
+        Assert1(!Attrs->paramHasAttr(Idx, ParamAttr::StructRet),
+                "Attributes Nest and StructRet are incompatible!", &F);
+      }
+
       Assert1(!Attrs->paramHasAttr(Idx, ParamAttr::NoReturn), 
              "Attribute NoReturn should only be applied to function", &F);
       Assert1(!Attrs->paramHasAttr(Idx, ParamAttr::NoUnwind),