Support for trampolines, except for X86 codegen which is
still under discussion.


git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@40549 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/AsmParser/Lexer.l b/lib/AsmParser/Lexer.l
index 24467cf..6b8bba5 100644
--- a/lib/AsmParser/Lexer.l
+++ b/lib/AsmParser/Lexer.l
@@ -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); }
diff --git a/lib/AsmParser/llvmAsmParser.y b/lib/AsmParser/llvmAsmParser.y
index 0936af3..0cc7a98 100644
--- a/lib/AsmParser/llvmAsmParser.y
+++ b/lib/AsmParser/llvmAsmParser.y
@@ -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; }
diff --git a/lib/CodeGen/SelectionDAG/LegalizeDAG.cpp b/lib/CodeGen/SelectionDAG/LegalizeDAG.cpp
index 4131ed9..078cbf3 100644
--- a/lib/CodeGen/SelectionDAG/LegalizeDAG.cpp
+++ b/lib/CodeGen/SelectionDAG/LegalizeDAG.cpp
@@ -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() &&
diff --git a/lib/CodeGen/SelectionDAG/SelectionDAG.cpp b/lib/CodeGen/SelectionDAG/SelectionDAG.cpp
index d4d984b..4b7863d 100644
--- a/lib/CodeGen/SelectionDAG/SelectionDAG.cpp
+++ b/lib/CodeGen/SelectionDAG/SelectionDAG.cpp
@@ -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!");
diff --git a/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp b/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp
index 05578fe..ce09eb4 100644
--- a/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp
+++ b/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp
@@ -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)) {
diff --git a/lib/Target/ARM/ARMISelLowering.cpp b/lib/Target/ARM/ARMISelLowering.cpp
index 6f63fbd..a274c14 100644
--- a/lib/Target/ARM/ARMISelLowering.cpp
+++ b/lib/Target/ARM/ARMISelLowering.cpp
@@ -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();
 }
diff --git a/lib/Target/ARM/ARMISelLowering.h b/lib/Target/ARM/ARMISelLowering.h
index 2b66f23..318657e 100644
--- a/lib/Target/ARM/ARMISelLowering.h
+++ b/lib/Target/ARM/ARMISelLowering.h
@@ -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);
   };
 }
 
diff --git a/lib/Target/Alpha/AlphaISelLowering.cpp b/lib/Target/Alpha/AlphaISelLowering.cpp
index d4777b2..adbf322 100644
--- a/lib/Target/Alpha/AlphaISelLowering.cpp
+++ b/lib/Target/Alpha/AlphaISelLowering.cpp
@@ -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);
diff --git a/lib/Target/IA64/IA64ISelLowering.cpp b/lib/Target/IA64/IA64ISelLowering.cpp
index 0237a9a..b9508a9 100644
--- a/lib/Target/IA64/IA64ISelLowering.cpp
+++ b/lib/Target/IA64/IA64ISelLowering.cpp
@@ -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);
diff --git a/lib/Target/Mips/MipsISelLowering.cpp b/lib/Target/Mips/MipsISelLowering.cpp
index 790cdaf..3328336 100644
--- a/lib/Target/Mips/MipsISelLowering.cpp
+++ b/lib/Target/Mips/MipsISelLowering.cpp
@@ -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();
 }
diff --git a/lib/Target/PowerPC/PPCISelLowering.cpp b/lib/Target/PowerPC/PPCISelLowering.cpp
index 6c2f383..0ed1112 100644
--- a/lib/Target/PowerPC/PPCISelLowering.cpp
+++ b/lib/Target/PowerPC/PPCISelLowering.cpp
@@ -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);
   
diff --git a/lib/Target/Sparc/SparcISelDAGToDAG.cpp b/lib/Target/Sparc/SparcISelDAGToDAG.cpp
index 8c8b3f8..536abc1 100644
--- a/lib/Target/Sparc/SparcISelDAGToDAG.cpp
+++ b/lib/Target/Sparc/SparcISelDAGToDAG.cpp
@@ -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.
diff --git a/lib/Target/TargetCallingConv.td b/lib/Target/TargetCallingConv.td
index 9419320..176a848 100644
--- a/lib/Target/TargetCallingConv.td
+++ b/lib/Target/TargetCallingConv.td
@@ -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> {}
 
diff --git a/lib/VMCore/Function.cpp b/lib/VMCore/Function.cpp
index dd78196..1374d55 100644
--- a/lib/VMCore/Function.cpp
+++ b/lib/VMCore/Function.cpp
@@ -105,6 +105,8 @@
     Result += "sret ";  
   if (Attrs & ParamAttr::ByVal)
     Result += "byval ";
+  if (Attrs & ParamAttr::Nest)
+    Result += "nest ";
   return Result;
 }
 
diff --git a/lib/VMCore/Verifier.cpp b/lib/VMCore/Verifier.cpp
index ffca88b..de4050d 100644
--- a/lib/VMCore/Verifier.cpp
+++ b/lib/VMCore/Verifier.cpp
@@ -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),