These patches add support for taking pointers to nested
functions (a gcc extension).  This is done by building
and executing a small code stub on the stack, known as
a trampoline.  The LLVM part adds two new intrinsics,
llvm.init.trampoline and llvm.adjust.trampoline.  The
adjust intrinsic is implemented for all architectures
that are supported in gcc, while the init intrinsic is
only implemented for X86.  Furthermore, trampolines can
interact badly with stack protection mechanisms which
don't much like execution of code on the stack.  GCC
does various tricks to tell the OS that the trampoline
is kosher.  I didn't implement any of those tricks yet,
because it works without them on my machine :)

Enjoy!

Duncan.
Index: include/llvm/Target/TargetLowering.h
===================================================================
--- include/llvm/Target/TargetLowering.h	(revision 40522)
+++ include/llvm/Target/TargetLowering.h	(working copy)
@@ -812,8 +812,10 @@
     bool isZExt;
     bool isInReg;
     bool isSRet;
+    bool isChain;
 
-    ArgListEntry():isSExt(false), isZExt(false), isInReg(false), isSRet(false) { };
+    ArgListEntry() : isSExt(false), isZExt(false), isInReg(false),
+      isSRet(false), isChain(false) { };
   };
   typedef std::vector<ArgListEntry> ArgListTy;
   virtual std::pair<SDOperand, SDOperand>
Index: include/llvm/ParameterAttributes.h
===================================================================
--- include/llvm/ParameterAttributes.h	(revision 40522)
+++ include/llvm/ParameterAttributes.h	(working copy)
@@ -30,14 +30,15 @@
 /// @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
+  Chain      = 1 << 8  ///< Nested function static chain
 };
 
 }
Index: include/llvm/Intrinsics.td
===================================================================
--- include/llvm/Intrinsics.td	(revision 40522)
+++ include/llvm/Intrinsics.td	(working copy)
@@ -247,6 +247,14 @@
                                     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: include/llvm/CodeGen/SelectionDAGNodes.h
===================================================================
--- include/llvm/CodeGen/SelectionDAGNodes.h	(revision 40522)
+++ include/llvm/CodeGen/SelectionDAGNodes.h	(working copy)
@@ -66,6 +66,8 @@
     StructReturnOffs  = 3,
     ByVal             = 1<<4,  ///< Struct passed by value
     ByValOffs         = 4,
+    Chain             = 1<<5,  ///< Parameter is nested function static chain
+    ChainOffs         = 5,
     OrigAlignment     = 0x1F<<27,
     OrigAlignmentOffs = 27
   };
@@ -528,7 +530,19 @@
     // 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 static chain pointer, 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: docs/LangRef.html
===================================================================
--- docs/LangRef.html	(revision 40522)
+++ docs/LangRef.html	(working copy)
@@ -200,6 +200,12 @@
           <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">
@@ -5123,6 +5129,105 @@
 
 <!-- ======================================================================= -->
 <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>chain</tt> attribute, from a function.  The result is a callable
+  function pointer lacking the chain 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 chain 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* chain  %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* chain , i32, i32)* @f to i8*), i8* %cval )
+  %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* %cval, 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;cval&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>chain</tt> attribute removed.  At most
+  one such <tt>chain</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>cval</tt> used for the missing
+  <tt>chain</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>
 </div>
 
Index: lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp
===================================================================
--- lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp	(revision 40522)
+++ lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp	(working copy)
@@ -2863,6 +2863,28 @@
   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 @@
     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.isChain = Attrs && Attrs->paramHasAttr(attrInd, ParamAttr::Chain);
     Args.push_back(Entry);
   }
 
@@ -3827,6 +3850,8 @@
       Flags |= ISD::ParamFlags::StructReturn;
     if (Attrs && Attrs->paramHasAttr(j, ParamAttr::ByVal))
       Flags |= ISD::ParamFlags::ByVal;
+    if (Attrs && Attrs->paramHasAttr(j, ParamAttr::Chain))
+      Flags |= ISD::ParamFlags::Chain;
     Flags |= (OriginalAlignment << ISD::ParamFlags::OrigAlignmentOffs);
     
     switch (getTypeAction(VT)) {
@@ -3945,6 +3970,8 @@
       Flags |= ISD::ParamFlags::InReg;
     if (Args[i].isSRet)
       Flags |= ISD::ParamFlags::StructReturn;
+    if (Args[i].isChain)
+      Flags |= ISD::ParamFlags::Chain;
     Flags |= OriginalAlignment << ISD::ParamFlags::OrigAlignmentOffs;
     
     switch (getTypeAction(VT)) {
Index: lib/CodeGen/SelectionDAG/SelectionDAG.cpp
===================================================================
--- lib/CodeGen/SelectionDAG/SelectionDAG.cpp	(revision 40522)
+++ lib/CodeGen/SelectionDAG/SelectionDAG.cpp	(working copy)
@@ -3513,6 +3513,10 @@
   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: lib/CodeGen/SelectionDAG/LegalizeDAG.cpp
===================================================================
--- lib/CodeGen/SelectionDAG/LegalizeDAG.cpp	(revision 40522)
+++ lib/CodeGen/SelectionDAG/LegalizeDAG.cpp	(working copy)
@@ -3156,6 +3156,31 @@
     }
     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: lib/Target/PowerPC/PPCISelLowering.cpp
===================================================================
--- lib/Target/PowerPC/PPCISelLowering.cpp	(revision 40522)
+++ lib/Target/PowerPC/PPCISelLowering.cpp	(working copy)
@@ -169,7 +169,10 @@
   
   // 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: lib/Target/ARM/ARMISelLowering.h
===================================================================
--- lib/Target/ARM/ARMISelLowering.h	(revision 40522)
+++ lib/Target/ARM/ARMISelLowering.h	(working copy)
@@ -138,6 +138,7 @@
     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: lib/Target/ARM/ARMISelLowering.cpp
===================================================================
--- lib/Target/ARM/ARMISelLowering.cpp	(revision 40522)
+++ lib/Target/ARM/ARMISelLowering.cpp	(working copy)
@@ -190,7 +190,12 @@
   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 @@
   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 @@
   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: lib/Target/Alpha/AlphaISelLowering.cpp
===================================================================
--- lib/Target/Alpha/AlphaISelLowering.cpp	(revision 40522)
+++ lib/Target/Alpha/AlphaISelLowering.cpp	(working copy)
@@ -124,6 +124,9 @@
   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: lib/Target/X86/X86ISelLowering.cpp
===================================================================
--- lib/Target/X86/X86ISelLowering.cpp	(revision 40522)
+++ lib/Target/X86/X86ISelLowering.cpp	(working copy)
@@ -34,6 +34,7 @@
 #include "llvm/Support/MathExtras.h"
 #include "llvm/Target/TargetOptions.h"
 #include "llvm/ADT/StringExtras.h"
+#include "llvm/ParameterAttributes.h"
 using namespace llvm;
 
 X86TargetLowering::X86TargetLowering(TargetMachine &TM)
@@ -244,6 +245,10 @@
     setExceptionSelectorRegister(X86::EDX);
   }
   
+  setOperationAction(ISD::ADJUST_TRAMP, MVT::i32,   Expand);
+  setOperationAction(ISD::ADJUST_TRAMP, MVT::i64,   Expand);
+  setOperationAction(ISD::TRAMPOLINE,   MVT::Other, Custom);
+
   // VASTART needs to be custom lowered to use the VarArgsFrameIndex
   setOperationAction(ISD::VASTART           , MVT::Other, Custom);
   setOperationAction(ISD::VAARG             , MVT::Other, Expand);
@@ -4265,6 +4270,82 @@
                      Chain, DAG.getRegister(X86::ECX, getPointerTy()));
 }
 
+SDOperand X86TargetLowering::LowerTRAMPOLINE(SDOperand Op,
+                                             SelectionDAG &DAG) {
+  SDOperand Root = Op.getOperand(0);
+  SDOperand Trmp = Op.getOperand(1); // trampoline
+  SDOperand FPtr = Op.getOperand(2); // nested function
+  SDOperand SChn = Op.getOperand(3); // static chain
+
+  SrcValueSDNode *TrmpSV = cast<SrcValueSDNode>(Op.getOperand(4));
+
+  if (Subtarget->is64Bit()) {
+    return SDOperand(); // not yet supported
+  } else {
+    Function *Func = (Function *)
+      cast<Function>(cast<SrcValueSDNode>(Op.getOperand(5))->getValue());
+    unsigned CC = Func->getCallingConv();
+    unsigned Move;
+
+    switch (CC) {
+    default:
+      assert(0 && "Unsupported calling convention");
+    case CallingConv::C:
+    case CallingConv::Fast:
+    case CallingConv::X86_StdCall: {
+      Move = 0xb9; // Pass chain in ECX
+
+      // Check that ECX wasn't needed by an 'inreg' parameter.
+      const FunctionType *FTy = Func->getFunctionType();
+      const ParamAttrsList *Attrs = FTy->getParamAttrs();
+
+      if (Attrs && !Func->isVarArg()) {
+        unsigned InRegCount = 0;
+        unsigned Idx = 1;
+
+        for (FunctionType::param_iterator I = FTy->param_begin(),
+             E = FTy->param_end(); I != E; ++I, ++Idx)
+          if (Attrs->paramHasAttr(Idx, ParamAttr::InReg))
+            // FIXME: should only count parameters that are lowered to integers.
+            InRegCount++;
+
+        if (InRegCount > 2) {
+          cerr << "Chain register in use - reduce number of inreg parameters!\n";
+          abort();
+        }
+      }
+      break;
+    }
+    case CallingConv::X86_FastCall:
+      Move = 0xb8; // Pass chain in EAX
+      break;
+    }
+
+    SDOperand OutChains[4];
+    SDOperand Addr, Disp;
+
+    Addr = DAG.getNode(ISD::ADD, MVT::i32, Trmp, DAG.getConstant(10, MVT::i32));
+    Disp = DAG.getNode(ISD::SUB, MVT::i32, FPtr, Addr);
+
+    OutChains[0] = DAG.getStore(Root, DAG.getConstant(Move, MVT::i8), Trmp,
+                                TrmpSV->getValue(), TrmpSV->getOffset());
+
+    Addr = DAG.getNode(ISD::ADD, MVT::i32, Trmp, DAG.getConstant(1, MVT::i32));
+    OutChains[1] = DAG.getStore(Root, SChn, Addr, TrmpSV->getValue(),
+                                TrmpSV->getOffset() + 1, false, 1);
+
+    Addr = DAG.getNode(ISD::ADD, MVT::i32, Trmp, DAG.getConstant(5, MVT::i32));
+    OutChains[2] = DAG.getStore(Root, DAG.getConstant(0xe9, MVT::i8), Addr,
+                                TrmpSV->getValue() + 5, TrmpSV->getOffset());
+
+    Addr = DAG.getNode(ISD::ADD, MVT::i32, Trmp, DAG.getConstant(6, MVT::i32));
+    OutChains[3] = DAG.getStore(Root, Disp, Addr, TrmpSV->getValue(),
+                                TrmpSV->getOffset() + 6, false, 1);
+
+    return DAG.getNode(ISD::TokenFactor, MVT::Other, OutChains, 4);
+  }
+}
+
 /// LowerOperation - Provide custom lowering hooks for some operations.
 ///
 SDOperand X86TargetLowering::LowerOperation(SDOperand Op, SelectionDAG &DAG) {
@@ -4306,6 +4387,7 @@
                                 return LowerFRAME_TO_ARGS_OFFSET(Op, DAG);
   case ISD::DYNAMIC_STACKALLOC: return LowerDYNAMIC_STACKALLOC(Op, DAG);
   case ISD::EH_RETURN:          return LowerEH_RETURN(Op, DAG);
+  case ISD::TRAMPOLINE:         return LowerTRAMPOLINE(Op, DAG);
   }
   return SDOperand();
 }
Index: lib/Target/X86/X86CallingConv.td
===================================================================
--- lib/Target/X86/X86CallingConv.td	(revision 40522)
+++ lib/Target/X86/X86CallingConv.td	(working copy)
@@ -108,6 +108,9 @@
   CCIfType<[v8i8, v4i16, v2i32, v1i64],
               CCAssignToReg<[RDI, RSI, RDX, RCX, R8 , R9 ]>>,
 
+  // The static chain parameter, if any, is passed in R10.
+  CCIfChain<CCAssignToReg<[R10]>>,
+
   // Integer/FP values get stored in stack slots that are 8 bytes in size and
   // 8-byte aligned if there are no more registers to hold them.
   CCIfType<[i32, i64, f32, f64], CCAssignToStack<8, 8>>,
@@ -150,11 +153,14 @@
 def CC_X86_32_C : CallingConv<[
   // Promote i8/i16 arguments to i32.
   CCIfType<[i8, i16], CCPromoteToType<i32>>,
-  
+
+  // The static chain parameter, if any, is passed in ECX.
+  CCIfChain<CCAssignToReg<[ECX]>>,
+
   // The first 3 integer arguments, if marked 'inreg' and if the call is not
   // a vararg call, are passed in integer registers.
   CCIfNotVarArg<CCIfInReg<CCIfType<[i32], CCAssignToReg<[EAX, EDX, ECX]>>>>,
-  
+
   // Otherwise, same as everything else.
   CCDelegateTo<CC_X86_32_Common>
 ]>;
@@ -163,10 +169,13 @@
 def CC_X86_32_FastCall : CallingConv<[
   // Promote i8/i16 arguments to i32.
   CCIfType<[i8, i16], CCPromoteToType<i32>>,
-  
+
+  // The static chain parameter, if any, is passed in EAX.
+  CCIfChain<CCAssignToReg<[EAX]>>,
+
   // The first 2 integer arguments are passed in ECX/EDX
   CCIfType<[i32], CCAssignToReg<[ECX, EDX]>>,
-  
+
   // Otherwise, same as everything else.
   CCDelegateTo<CC_X86_32_Common>
 ]>;
Index: lib/Target/X86/X86ISelLowering.h
===================================================================
--- lib/Target/X86/X86ISelLowering.h	(revision 40522)
+++ lib/Target/X86/X86ISelLowering.h	(working copy)
@@ -423,6 +423,7 @@
     SDOperand LowerFRAMEADDR(SDOperand Op, SelectionDAG &DAG);
     SDOperand LowerFRAME_TO_ARGS_OFFSET(SDOperand Op, SelectionDAG &DAG);
     SDOperand LowerEH_RETURN(SDOperand Op, SelectionDAG &DAG);
+    SDOperand LowerTRAMPOLINE(SDOperand Op, SelectionDAG &DAG);
   };
 }
 
Index: lib/Target/IA64/IA64ISelLowering.cpp
===================================================================
--- lib/Target/IA64/IA64ISelLowering.cpp	(revision 40522)
+++ lib/Target/IA64/IA64ISelLowering.cpp	(working copy)
@@ -97,6 +97,8 @@
       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: lib/Target/Mips/MipsISelLowering.cpp
===================================================================
--- lib/Target/Mips/MipsISelLowering.cpp	(revision 40522)
+++ lib/Target/Mips/MipsISelLowering.cpp	(working copy)
@@ -102,6 +102,8 @@
   setOperationAction(ISD::STACKSAVE, MVT::Other, Expand);
   setOperationAction(ISD::STACKRESTORE, MVT::Other, Expand);
 
+  setOperationAction(ISD::ADJUST_TRAMP, MVT::i32, Expand);
+
   setStackPointerRegisterToSaveRestore(Mips::SP);
   computeRegisterProperties();
 }
Index: lib/Target/Sparc/SparcISelDAGToDAG.cpp
===================================================================
--- lib/Target/Sparc/SparcISelDAGToDAG.cpp	(revision 40522)
+++ lib/Target/Sparc/SparcISelDAGToDAG.cpp	(working copy)
@@ -215,7 +215,9 @@
 
   // 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: lib/Target/TargetCallingConv.td
===================================================================
--- lib/Target/TargetCallingConv.td	(revision 40522)
+++ lib/Target/TargetCallingConv.td	(working copy)
@@ -45,6 +45,10 @@
 /// the specified action.
 class CCIfInReg<CCAction A> : CCIf<"ArgFlags & ISD::ParamFlags::InReg", A> {}
 
+/// CCIfChain - If this argument is marked with the 'chain' attribute, apply
+/// the specified action.
+class CCIfChain<CCAction A> : CCIf<"ArgFlags & ISD::ParamFlags::Chain", A> {}
+
 /// CCIfNotVarArg - If the current function is not vararg - apply the action
 class CCIfNotVarArg<CCAction A> : CCIf<"!State.isVarArg()", A> {}
 
Index: lib/VMCore/Verifier.cpp
===================================================================
--- lib/VMCore/Verifier.cpp	(revision 40522)
+++ lib/VMCore/Verifier.cpp	(working copy)
@@ -361,6 +361,7 @@
 
   if (const ParamAttrsList *Attrs = FT->getParamAttrs()) {
     unsigned Idx = 1;
+    bool SawChain = false;
 
     Assert1(!Attrs->paramHasAttr(0, ParamAttr::ByVal),
             "Attribute ByVal should not apply to functions!", &F);
@@ -368,6 +369,8 @@
             "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::Chain),
+            "Attribute Chain 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 @@
                 "Attribute ByVal should only apply to pointer to structs!", &F);
       }
 
+      if (Attrs->paramHasAttr(Idx, ParamAttr::Chain)) {
+        Assert1(!SawChain, "More than one parameter has attribute Chain!", &F);
+        SawChain = true;
+
+        Assert1(isa<PointerType>(FT->getParamType(Idx-1)),
+                "Attribute Chain should only apply to Pointer type!", &F);
+        Assert1(!Attrs->paramHasAttr(Idx, ParamAttr::ByVal),
+                "Attributes Chain and ByVal are incompatible!", &F);
+        Assert1(!Attrs->paramHasAttr(Idx, ParamAttr::InReg),
+                "Attributes Chain and InReg are incompatible!", &F);
+        Assert1(!Attrs->paramHasAttr(Idx, ParamAttr::StructRet),
+                "Attributes Chain 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),
Index: lib/VMCore/Function.cpp
===================================================================
--- lib/VMCore/Function.cpp	(revision 40522)
+++ lib/VMCore/Function.cpp	(working copy)
@@ -105,6 +105,8 @@
     Result += "sret ";  
   if (Attrs & ParamAttr::ByVal)
     Result += "byval ";
+  if (Attrs & ParamAttr::Chain)
+    Result += "chain ";
   return Result;
 }
 
Index: lib/AsmParser/llvmAsmParser.y
===================================================================
--- lib/AsmParser/llvmAsmParser.y	(revision 40522)
+++ lib/AsmParser/llvmAsmParser.y	(working copy)
@@ -1101,7 +1101,7 @@
 %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 CHAIN
 
 // Visibility Styles
 %token DEFAULT HIDDEN PROTECTED
@@ -1229,7 +1229,8 @@
               | INREG   { $$ = ParamAttr::InReg;     }
               | SRET    { $$ = ParamAttr::StructRet; }
               | NOALIAS { $$ = ParamAttr::NoAlias;   }
-              | BYVAL   { $$ = ParamAttr::ByVal;   }
+              | BYVAL   { $$ = ParamAttr::ByVal;     }
+              | CHAIN   { $$ = ParamAttr::Chain;     }
               ;
 
 OptParamAttrs : /* empty */  { $$ = ParamAttr::None; }
Index: lib/AsmParser/Lexer.l
===================================================================
--- lib/AsmParser/Lexer.l	(revision 40522)
+++ lib/AsmParser/Lexer.l	(working copy)
@@ -233,6 +233,7 @@
 noreturn        { return NORETURN; }
 noalias         { return NOALIAS; }
 byval           { return BYVAL; }
+chain           { return CHAIN; }
 
 void            { RET_TY(Type::VoidTy,  VOID);  }
 float           { RET_TY(Type::FloatTy, FLOAT); }
Index: gcc/llvm-convert.cpp
===================================================================
--- gcc/llvm-convert.cpp	(revision 40523)
+++ gcc/llvm-convert.cpp	(working copy)
@@ -4211,6 +4211,10 @@
    return EmitBuiltinExtractReturnAddr(exp, Result);
   case BUILT_IN_FROB_RETURN_ADDR:
    return EmitBuiltinFrobReturnAddr(exp, Result);
+  case BUILT_IN_INIT_TRAMPOLINE:
+    return EmitBuiltinInitTrampoline(exp);
+  case BUILT_IN_ADJUST_TRAMPOLINE:
+    return EmitBuiltinAdjustTrampoline(exp, Result);
 
   // Builtins used by the exception handling runtime.
   case BUILT_IN_DWARF_CFA:
@@ -4857,6 +4861,45 @@
   return true;
 }
 
+bool TreeToLLVM::EmitBuiltinInitTrampoline(tree exp) {
+  tree arglist = TREE_OPERAND(exp, 1);
+  if (!validate_arglist (arglist, POINTER_TYPE, POINTER_TYPE, POINTER_TYPE,
+                         VOID_TYPE))
+    return false;
+
+  static const Type *VPTy = PointerType::get(Type::Int8Ty);
+
+  Value *Tramp = Emit(TREE_VALUE(arglist), 0);
+  Tramp = CastToType(Instruction::BitCast, Tramp, VPTy);
+
+  Value *Func = Emit(TREE_VALUE(TREE_CHAIN(arglist)), 0);
+  Func = CastToType(Instruction::BitCast, Func, VPTy);
+
+  Value *Chain = Emit(TREE_VALUE(TREE_CHAIN(TREE_CHAIN(arglist))), 0);
+  Chain = CastToType(Instruction::BitCast, Chain, VPTy);
+
+  Value *Ops[3] = { Tramp, Func, Chain };
+
+  Function *Intr = Intrinsic::getDeclaration(TheModule,
+                                             Intrinsic::init_trampoline);
+  Builder.CreateCall(Intr, Ops, 3);
+  return true;
+}
+
+bool TreeToLLVM::EmitBuiltinAdjustTrampoline(tree exp, Value *&Result) {
+  tree arglist = TREE_OPERAND(exp, 1);
+  if (!validate_arglist(arglist, POINTER_TYPE, VOID_TYPE))
+    return false;
+
+  Value *Tramp = Emit(TREE_VALUE(arglist), 0);
+  Tramp = CastToType(Instruction::BitCast, Tramp,
+                     PointerType::get(Type::Int8Ty));
+
+  Function *Intr = Intrinsic::getDeclaration(TheModule,
+                                             Intrinsic::adjust_trampoline);
+  Result = Builder.CreateCall(Intr, Tramp, "adj");
+  return true;
+}
 
 //===----------------------------------------------------------------------===//
 //                      ... Complex Math Expressions ...
Index: gcc/llvm-internal.h
===================================================================
--- gcc/llvm-internal.h	(revision 40523)
+++ gcc/llvm-internal.h	(working copy)
@@ -580,6 +580,8 @@
   bool EmitBuiltinEHReturn(tree_node *exp, Value *&Result);
   bool EmitBuiltinInitDwarfRegSizes(tree_node *exp, Value *&Result);
   bool EmitBuiltinUnwindInit(tree_node *exp, Value *&Result);
+  bool EmitBuiltinInitTrampoline(tree_node *exp);
+  bool EmitBuiltinAdjustTrampoline(tree_node *exp, Value *&Result);
 
   // Complex Math Expressions.
   void EmitLoadFromComplex(Value *&Real, Value *&Imag, Value *SrcComplex,
Index: gcc/llvm-types.cpp
===================================================================
--- gcc/llvm-types.cpp	(revision 40523)
+++ gcc/llvm-types.cpp	(working copy)
@@ -962,9 +962,13 @@
     Attrs.push_back(ParamAttrsWithIndex::get(ArgTypes.size(),
                                              ParamAttr::StructRet));
     
-  if (static_chain)
+  if (static_chain) {
     // Pass the static chain as the first parameter.
     ABIConverter.HandleArgument(TREE_TYPE(static_chain));
+    // Mark it as the chain argument.
+    Attrs.push_back(ParamAttrsWithIndex::get(ArgTypes.size(),
+                                             ParamAttr::Chain));
+  }
 
   // If the target has regparam parameters, allow it to inspect the function
   // type.
Index: gcc/tree-nested.c
===================================================================
--- gcc/tree-nested.c	(revision 40523)
+++ gcc/tree-nested.c	(working copy)
@@ -409,6 +409,8 @@
   align = TRAMPOLINE_ALIGNMENT;
   size = TRAMPOLINE_SIZE;
 
+/* APPLE LOCAL LLVM */
+#ifndef ENABLE_LLVM /* Rely on LLVM supporting large alignments. */
   /* If we won't be able to guarantee alignment simply via TYPE_ALIGN,
      then allocate extra space so that we can do dynamic alignment.  */
   /* APPLE LOCAL STACK_BOUNDARY must be a signed expression on Darwin/x86 */
@@ -417,6 +419,8 @@
       size += ((align/BITS_PER_UNIT) - 1) & -(STACK_BOUNDARY/BITS_PER_UNIT);
       align = STACK_BOUNDARY;
     }
+/* APPLE LOCAL LLVM */
+#endif
 
   t = build_index_type (build_int_cst (NULL_TREE, size - 1));
   t = build_array_type (char_type_node, t);
_______________________________________________
llvm-commits mailing list
llvm-commits@cs.uiuc.edu
http://lists.cs.uiuc.edu/mailman/listinfo/llvm-commits

Reply via email to