Hi Evan,

> Some nit picks.
> 
> 1. Please don't use "Chain" for stand for function static chain. It  
> confuses backend guys like me. :-) "Chain" stands for control flow  
> dependency in the backend.

I've replaced Chain with Nest everywhere, eg the attribute is now 'nest'.

> 2. Purely a stylistic thing:
> 
> +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 {
> 
> If you move the check is64Bit() to the beginning of function, there  
> is no need to nest the part that actually do the work in the "else"  
> clause.

I'd prefer to leave it as it is: this is where the code for 64 bit
support will go, once added.  And since right now codegen will abort
on trampoline lowering on x86-64, I don't think it matters if a few
cycles are wasted before the abort :)  By the way, I think aborting
is the right thing to do: if someone is creating a trampoline, most
likely they are going to use it, i.e. jump to the code it contains.
If we lower trampoline initialization to nothing on architectures that
don't yet support it, then the code will appear to compile fine but will
die very horribly at runtime, by jumping to a bunch of random bytes...

> 3. In X86TargetLowering::LowerTRAMPOLINE():
> +    case CallingConv::X86_StdCall: {
> +      Move = 0xb9; // Pass chain in ECX
> 
> I assume this is the ModR/M byte?

Well, it's MOV32ri.

> Can you refactor ModRMByte() from X86CodeEmitter.cpp (probably also 
> getX86RegNum)
> and use that to calculate this instead?

For the reasons explained in the next paragraph, I've taken a minimal approach.
(1) I've introduced X86CodeEmitter.h, which contains native X86 Register numbers
factored out of X86CodeEmitter.cpp.
(2) In LowerTRAMPOLINE, names like N86::ECX are used to name the register used.
(3) Rather than using 0xb8 and 0xE9, I've introduced symbolic names MOV32ri
and JMP.  I could also get these by doing something like this:
 const X86InstrInfo *TII = 
((X86TargetMachine&)getTargetMachine()).getInstrInfo();
 unsigned char MOV32ri = TII->getBaseOpcodeFor(&TII->get(X86::MOV32ri));
But it didn't seem worth it (is there a way to extract the machine opcode
statically?).

> Also, isn't the static chain register described in X86CallingConv.td?

It is, but it's hard to use here.  The problem is that when lowering the
init.trampoline intrinsic you only have a pointer to the target function.
From this pointer you would like to find out which register a certain
parameter will be passed in for that function.  Not so easy!  It's like
having a call instruction without having the arguments.  In order to
exploit X86CallingConv.td, you have to use all the lowering machinery,
which isn't adapted to this case.  For example, you could try to synthesize
a fake call.  Or you could pretend to be lowering the target function.  I
tried it, and it can be done with a lot of horrible hacking.  But it's not
worth it.  It's much simpler to simply grab the calling convention and use
that, which unfortunately means keeping LowerTRAMPOLINE and
X86CallingConv.td in sync.  Personally I can live with that, especially since
I've seen the alternative and it still wakes me up screaming at night :)
But maybe you can see a reasonable way of doing it?

Since I need to map the calling convention to a native X86 register number,
I chose to bypass X86::ECX etc and directly use N86::ECX.  This would be
different if the register number was being extracted from lowering +
CCInfo.

> Magic number is confusing. :-)

Hopefully it's more readable now.  The amount of code factorization is
minimal which is a pity but seems the best choice.

> Looks great otherwise. Thanks!

Thanks for reviewing!

Duncan.
Index: llvm.master/docs/LangRef.html
===================================================================
--- llvm.master.orig/docs/LangRef.html	2007-07-27 10:07:33.000000000 +0200
+++ llvm.master/docs/LangRef.html	2007-07-27 10:16:35.000000000 +0200
@@ -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>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>
 </div>
 
Index: llvm.master/include/llvm/CodeGen/SelectionDAGNodes.h
===================================================================
--- llvm.master.orig/include/llvm/CodeGen/SelectionDAGNodes.h	2007-07-27 10:07:33.000000000 +0200
+++ llvm.master/include/llvm/CodeGen/SelectionDAGNodes.h	2007-07-27 10:20:11.000000000 +0200
@@ -66,6 +66,8 @@
     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 @@
     // 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: llvm.master/include/llvm/Intrinsics.td
===================================================================
--- llvm.master.orig/include/llvm/Intrinsics.td	2007-07-27 10:07:33.000000000 +0200
+++ llvm.master/include/llvm/Intrinsics.td	2007-07-27 10:09:24.000000000 +0200
@@ -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: llvm.master/include/llvm/ParameterAttributes.h
===================================================================
--- llvm.master.orig/include/llvm/ParameterAttributes.h	2007-07-27 10:07:33.000000000 +0200
+++ llvm.master/include/llvm/ParameterAttributes.h	2007-07-27 10:09:24.000000000 +0200
@@ -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
+  Nest       = 1 << 8  ///< Nested function static chain
 };
 
 }
Index: llvm.master/include/llvm/Target/TargetLowering.h
===================================================================
--- llvm.master.orig/include/llvm/Target/TargetLowering.h	2007-07-27 10:07:33.000000000 +0200
+++ llvm.master/include/llvm/Target/TargetLowering.h	2007-07-27 10:09:24.000000000 +0200
@@ -812,8 +812,10 @@
     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: llvm.master/lib/AsmParser/Lexer.l
===================================================================
--- llvm.master.orig/lib/AsmParser/Lexer.l	2007-07-27 10:07:33.000000000 +0200
+++ llvm.master/lib/AsmParser/Lexer.l	2007-07-27 10:09:24.000000000 +0200
@@ -233,6 +233,7 @@
 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: llvm.master/lib/AsmParser/llvmAsmParser.y
===================================================================
--- llvm.master.orig/lib/AsmParser/llvmAsmParser.y	2007-07-27 10:07:33.000000000 +0200
+++ llvm.master/lib/AsmParser/llvmAsmParser.y	2007-07-27 10:09:24.000000000 +0200
@@ -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 NEST
 
 // 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;     }
+              | NEST    { $$ = ParamAttr::Nest;      }
               ;
 
 OptParamAttrs : /* empty */  { $$ = ParamAttr::None; }
Index: llvm.master/lib/CodeGen/SelectionDAG/LegalizeDAG.cpp
===================================================================
--- llvm.master.orig/lib/CodeGen/SelectionDAG/LegalizeDAG.cpp	2007-07-27 10:07:33.000000000 +0200
+++ llvm.master/lib/CodeGen/SelectionDAG/LegalizeDAG.cpp	2007-07-27 10:09:24.000000000 +0200
@@ -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: llvm.master/lib/CodeGen/SelectionDAG/SelectionDAG.cpp
===================================================================
--- llvm.master.orig/lib/CodeGen/SelectionDAG/SelectionDAG.cpp	2007-07-27 10:07:33.000000000 +0200
+++ llvm.master/lib/CodeGen/SelectionDAG/SelectionDAG.cpp	2007-07-27 10:09:24.000000000 +0200
@@ -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: llvm.master/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp
===================================================================
--- llvm.master.orig/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp	2007-07-27 10:07:33.000000000 +0200
+++ llvm.master/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp	2007-07-27 10:09:24.000000000 +0200
@@ -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.isNest  = Attrs && Attrs->paramHasAttr(attrInd, ParamAttr::Nest);
     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::Nest))
+      Flags |= ISD::ParamFlags::Nest;
     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].isNest)
+      Flags |= ISD::ParamFlags::Nest;
     Flags |= OriginalAlignment << ISD::ParamFlags::OrigAlignmentOffs;
     
     switch (getTypeAction(VT)) {
Index: llvm.master/lib/Target/ARM/ARMISelLowering.cpp
===================================================================
--- llvm.master.orig/lib/Target/ARM/ARMISelLowering.cpp	2007-07-27 10:07:33.000000000 +0200
+++ llvm.master/lib/Target/ARM/ARMISelLowering.cpp	2007-07-27 10:09:24.000000000 +0200
@@ -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: llvm.master/lib/Target/ARM/ARMISelLowering.h
===================================================================
--- llvm.master.orig/lib/Target/ARM/ARMISelLowering.h	2007-07-27 10:07:33.000000000 +0200
+++ llvm.master/lib/Target/ARM/ARMISelLowering.h	2007-07-27 10:09:24.000000000 +0200
@@ -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: llvm.master/lib/Target/Alpha/AlphaISelLowering.cpp
===================================================================
--- llvm.master.orig/lib/Target/Alpha/AlphaISelLowering.cpp	2007-07-27 10:07:33.000000000 +0200
+++ llvm.master/lib/Target/Alpha/AlphaISelLowering.cpp	2007-07-27 10:09:24.000000000 +0200
@@ -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: llvm.master/lib/Target/IA64/IA64ISelLowering.cpp
===================================================================
--- llvm.master.orig/lib/Target/IA64/IA64ISelLowering.cpp	2007-07-27 10:07:33.000000000 +0200
+++ llvm.master/lib/Target/IA64/IA64ISelLowering.cpp	2007-07-27 10:09:24.000000000 +0200
@@ -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: llvm.master/lib/Target/Mips/MipsISelLowering.cpp
===================================================================
--- llvm.master.orig/lib/Target/Mips/MipsISelLowering.cpp	2007-07-27 10:07:33.000000000 +0200
+++ llvm.master/lib/Target/Mips/MipsISelLowering.cpp	2007-07-27 10:09:24.000000000 +0200
@@ -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: llvm.master/lib/Target/PowerPC/PPCISelLowering.cpp
===================================================================
--- llvm.master.orig/lib/Target/PowerPC/PPCISelLowering.cpp	2007-07-27 10:07:33.000000000 +0200
+++ llvm.master/lib/Target/PowerPC/PPCISelLowering.cpp	2007-07-27 10:09:24.000000000 +0200
@@ -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: llvm.master/lib/Target/Sparc/SparcISelDAGToDAG.cpp
===================================================================
--- llvm.master.orig/lib/Target/Sparc/SparcISelDAGToDAG.cpp	2007-07-27 10:07:33.000000000 +0200
+++ llvm.master/lib/Target/Sparc/SparcISelDAGToDAG.cpp	2007-07-27 10:09:24.000000000 +0200
@@ -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: llvm.master/lib/Target/TargetCallingConv.td
===================================================================
--- llvm.master.orig/lib/Target/TargetCallingConv.td	2007-07-27 10:07:33.000000000 +0200
+++ llvm.master/lib/Target/TargetCallingConv.td	2007-07-27 10:09:24.000000000 +0200
@@ -45,6 +45,10 @@
 /// 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: llvm.master/lib/Target/X86/X86CallingConv.td
===================================================================
--- llvm.master.orig/lib/Target/X86/X86CallingConv.td	2007-07-27 10:07:33.000000000 +0200
+++ llvm.master/lib/Target/X86/X86CallingConv.td	2007-07-27 10:09:24.000000000 +0200
@@ -108,6 +108,9 @@
   CCIfType<[v8i8, v4i16, v2i32, v1i64],
               CCAssignToReg<[RDI, RSI, RDX, RCX, R8 , R9 ]>>,
 
+  // The 'nest' parameter, if any, is passed in R10.
+  CCIfNest<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 'nest' parameter, if any, is passed in ECX.
+  CCIfNest<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 'nest' parameter, if any, is passed in EAX.
+  CCIfNest<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: llvm.master/lib/Target/X86/X86ISelLowering.cpp
===================================================================
--- llvm.master.orig/lib/Target/X86/X86ISelLowering.cpp	2007-07-27 10:07:33.000000000 +0200
+++ llvm.master/lib/Target/X86/X86ISelLowering.cpp	2007-07-27 12:20:11.000000000 +0200
@@ -13,6 +13,7 @@
 //===----------------------------------------------------------------------===//
 
 #include "X86.h"
+#include "X86CodeEmitter.h"
 #include "X86InstrBuilder.h"
 #include "X86ISelLowering.h"
 #include "X86MachineFunctionInfo.h"
@@ -34,6 +35,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 +246,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);
@@ -4282,6 +4288,89 @@
                      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 Nest = Op.getOperand(3); // 'nest' parameter value
+
+  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 char NestReg;
+
+    switch (CC) {
+    default:
+      assert(0 && "Unsupported calling convention");
+    case CallingConv::C:
+    case CallingConv::Fast:
+    case CallingConv::X86_StdCall: {
+      // Pass 'nest' parameter in ECX.
+      // Must be kept in sync with X86CallingConv.td
+      NestReg = N86::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 += (getTargetData()->getTypeSizeInBits(*I) + 31) / 32;
+
+        if (InRegCount > 2) {
+          cerr << "Nest register in use - reduce number of inreg parameters!\n";
+          abort();
+        }
+      }
+      break;
+    }
+    case CallingConv::X86_FastCall:
+      // Pass 'nest' parameter in EAX.
+      // Must be kept in sync with X86CallingConv.td
+      NestReg = N86::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);
+
+    const unsigned char MOV32ri = 0xB8;
+    const unsigned char JMP     = 0xE9;
+
+    OutChains[0] = DAG.getStore(Root, DAG.getConstant(MOV32ri|NestReg, 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, Nest, 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(JMP, 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) {
@@ -4323,6 +4412,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: llvm.master/lib/Target/X86/X86ISelLowering.h
===================================================================
--- llvm.master.orig/lib/Target/X86/X86ISelLowering.h	2007-07-27 10:07:33.000000000 +0200
+++ llvm.master/lib/Target/X86/X86ISelLowering.h	2007-07-27 10:09:24.000000000 +0200
@@ -431,6 +431,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: llvm.master/lib/VMCore/Function.cpp
===================================================================
--- llvm.master.orig/lib/VMCore/Function.cpp	2007-07-27 10:07:33.000000000 +0200
+++ llvm.master/lib/VMCore/Function.cpp	2007-07-27 10:09:24.000000000 +0200
@@ -105,6 +105,8 @@
     Result += "sret ";  
   if (Attrs & ParamAttr::ByVal)
     Result += "byval ";
+  if (Attrs & ParamAttr::Nest)
+    Result += "nest ";
   return Result;
 }
 
Index: llvm.master/lib/VMCore/Verifier.cpp
===================================================================
--- llvm.master.orig/lib/VMCore/Verifier.cpp	2007-07-27 10:07:33.000000000 +0200
+++ llvm.master/lib/VMCore/Verifier.cpp	2007-07-27 10:09:25.000000000 +0200
@@ -361,6 +361,7 @@
 
   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 @@
             "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 @@
                 "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),
Index: llvm.master/lib/Target/X86/X86CodeEmitter.h
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ llvm.master/lib/Target/X86/X86CodeEmitter.h	2007-07-27 11:29:38.000000000 +0200
@@ -0,0 +1,25 @@
+//===-- X86CodeEmitter.h - X86 DAG Lowering Interface -----------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file was developed by Duncan Sands and is distributed under
+// the University of Illinois Open Source License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines utilities for X86 code emission.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef X86CODEEMITTER_H
+#define X86CODEEMITTER_H
+
+/// N86 namespace - Native X86 Register numbers... used by X86 backend.
+///
+namespace N86 {
+  enum {
+    EAX = 0, ECX = 1, EDX = 2, EBX = 3, ESP = 4, EBP = 5, ESI = 6, EDI = 7
+  };
+}
+
+#endif    // X86CODEEMITTER_H
Index: llvm.master/lib/Target/X86/X86CodeEmitter.cpp
===================================================================
--- llvm.master.orig/lib/Target/X86/X86CodeEmitter.cpp	2007-07-27 11:28:30.000000000 +0200
+++ llvm.master/lib/Target/X86/X86CodeEmitter.cpp	2007-07-27 11:29:57.000000000 +0200
@@ -13,6 +13,7 @@
 //===----------------------------------------------------------------------===//
 
 #define DEBUG_TYPE "x86-emitter"
+#include "X86CodeEmitter.h"
 #include "X86InstrInfo.h"
 #include "X86Subtarget.h"
 #include "X86TargetMachine.h"
@@ -192,14 +193,6 @@
   MCE.emitWordLE(0); // The relocated value will be added to the displacement
 }
 
-/// N86 namespace - Native X86 Register numbers... used by X86 backend.
-///
-namespace N86 {
-  enum {
-    EAX = 0, ECX = 1, EDX = 2, EBX = 3, ESP = 4, EBP = 5, ESI = 6, EDI = 7
-  };
-}
-
 // getX86RegNum - This function maps LLVM register identifiers to their X86
 // specific numbering, which is used in various places encoding instructions.
 //
Index: gcc.llvm/gcc/llvm-convert.cpp
===================================================================
--- gcc.llvm.orig/gcc/llvm-convert.cpp	2007-07-26 21:26:13.000000000 +0200
+++ gcc.llvm/gcc/llvm-convert.cpp	2007-07-27 12:32:12.000000000 +0200
@@ -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/gcc/llvm-internal.h
===================================================================
--- gcc.llvm.orig/gcc/llvm-internal.h	2007-07-26 21:26:13.000000000 +0200
+++ gcc.llvm/gcc/llvm-internal.h	2007-07-27 12:32:12.000000000 +0200
@@ -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/gcc/llvm-types.cpp
===================================================================
--- gcc.llvm.orig/gcc/llvm-types.cpp	2007-07-26 21:26:13.000000000 +0200
+++ gcc.llvm/gcc/llvm-types.cpp	2007-07-27 12:32:50.000000000 +0200
@@ -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::Nest));
+  }
 
   // If the target has regparam parameters, allow it to inspect the function
   // type.
Index: gcc.llvm/gcc/tree-nested.c
===================================================================
--- gcc.llvm.orig/gcc/tree-nested.c	2007-07-26 21:26:13.000000000 +0200
+++ gcc.llvm/gcc/tree-nested.c	2007-07-27 12:32:12.000000000 +0200
@@ -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