From 36397f50343639ce9a25996f2d790c656791ab92 Mon Sep 17 00:00:00 2001 From: Duncan Sands Date: Fri, 27 Jul 2007 12:58:54 +0000 Subject: [PATCH] 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 --- docs/LangRef.html | 105 ++++++++++++++++++ include/llvm/CodeGen/SelectionDAGNodes.h | 16 ++- include/llvm/Intrinsics.td | 8 ++ include/llvm/ParameterAttributes.h | 15 +-- include/llvm/Target/TargetLowering.h | 4 +- lib/AsmParser/Lexer.l | 1 + lib/AsmParser/llvmAsmParser.y | 5 +- lib/CodeGen/SelectionDAG/LegalizeDAG.cpp | 25 +++++ lib/CodeGen/SelectionDAG/SelectionDAG.cpp | 4 + lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp | 27 +++++ lib/Target/ARM/ARMISelLowering.cpp | 16 ++- lib/Target/ARM/ARMISelLowering.h | 1 + lib/Target/Alpha/AlphaISelLowering.cpp | 3 + lib/Target/IA64/IA64ISelLowering.cpp | 2 + lib/Target/Mips/MipsISelLowering.cpp | 2 + lib/Target/PowerPC/PPCISelLowering.cpp | 5 +- lib/Target/Sparc/SparcISelDAGToDAG.cpp | 4 +- lib/Target/TargetCallingConv.td | 4 + lib/VMCore/Function.cpp | 2 + lib/VMCore/Verifier.cpp | 17 +++ 20 files changed, 252 insertions(+), 14 deletions(-) diff --git a/docs/LangRef.html b/docs/LangRef.html index 6ebbb293077..2cf74c2824f 100644 --- a/docs/LangRef.html +++ b/docs/LangRef.html @@ -200,6 +200,12 @@
  • 'llvm.memory.barrier' Intrinsic
  • +
  • Trampoline Intrinsics +
      +
    1. 'llvm.init.trampoline' Intrinsic
    2. +
    3. 'llvm.adjust.trampoline' Intrinsic
    4. +
    +
  • General intrinsics
    1. @@ -5121,6 +5127,105 @@ declare void @llvm.memory.barrier( i1 <ll>, i1 <ls>, i1 <sl>, + + + +
      +

      + These intrinsics make it possible to excise one parameter, marked with + the nest 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. +

      +

      + For example, if the function is + i32 f(i8* nest %c, i32 %x, i32 %y) then the resulting function + pointer has signature i32 (i32, i32)*. It can be created as follows: +

      +  %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)*
      +
      + The call %val = call i32 %fp( i32 %x, i32 %y ) is then equivalent to + %val = call i32 %f( i8* %nval, i32 %x, i32 %y ). +

      +

      + Trampolines are currently only supported on the X86 architecture. +

      +
      + + + +
      +
      Syntax:
      +
      +declare void @llvm.init.trampoline(i8* <tramp>, i8* <func>, i8* <nval>)
      +
      +
      Overview:
      +

      + This initializes the memory pointed to by tramp as a trampoline. +

      +
      Arguments:
      +

      + The llvm.init.trampoline intrinsic takes three arguments, all + pointers. The tramp 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 func argument must hold a + function bitcast to an i8*. +

      +
      Semantics:
      +

      + The block of memory pointed to by tramp is filled with target + dependent code, turning it into a function. + The new function's signature is the same as that of func with + any arguments marked with the nest attribute removed. At most + one such nest argument is allowed, and it must be of pointer + type. Calling the new function is equivalent to calling func + with the same argument list, but with nval used for the missing + nest argument. +

      +
      + + + +
      +
      Syntax:
      +
      +declare i8* @llvm.adjust.trampoline(i8* <tramp>)
      +
      +
      Overview:
      +

      + This intrinsic returns a function pointer suitable for executing + the trampoline code pointed to by tramp. +

      +
      Arguments:
      +

      + The llvm.adjust.trampoline takes one argument, a pointer to a + trampoline initialized by the + 'llvm.init.trampoline' intrinsic. +

      +
      Semantics:
      +

      + A function pointer that can be used to execute the trampoline code in + tramp is returned. The returned value should be bitcast to an + appropriate function pointer type + before being called. +

      +
      +
      General Intrinsics diff --git a/include/llvm/CodeGen/SelectionDAGNodes.h b/include/llvm/CodeGen/SelectionDAGNodes.h index a74c04836f9..ce7dda40280 100644 --- a/include/llvm/CodeGen/SelectionDAGNodes.h +++ b/include/llvm/CodeGen/SelectionDAGNodes.h @@ -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 }; diff --git a/include/llvm/Intrinsics.td b/include/llvm/Intrinsics.td index e5bb2f62134..205eac509a9 100644 --- a/include/llvm/Intrinsics.td +++ b/include/llvm/Intrinsics.td @@ -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 //===----------------------------------------------------------------------===// diff --git a/include/llvm/ParameterAttributes.h b/include/llvm/ParameterAttributes.h index b1cb966e0af..e2890f5a711 100644 --- a/include/llvm/ParameterAttributes.h +++ b/include/llvm/ParameterAttributes.h @@ -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 }; } diff --git a/include/llvm/Target/TargetLowering.h b/include/llvm/Target/TargetLowering.h index a95a03bca0d..a1aa50c9c79 100644 --- a/include/llvm/Target/TargetLowering.h +++ b/include/llvm/Target/TargetLowering.h @@ -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 ArgListTy; virtual std::pair diff --git a/lib/AsmParser/Lexer.l b/lib/AsmParser/Lexer.l index 24467cf606d..6b8bba5d68d 100644 --- a/lib/AsmParser/Lexer.l +++ b/lib/AsmParser/Lexer.l @@ -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); } diff --git a/lib/AsmParser/llvmAsmParser.y b/lib/AsmParser/llvmAsmParser.y index 0936af3a4d0..0cc7a9831a2 100644 --- a/lib/AsmParser/llvmAsmParser.y +++ b/lib/AsmParser/llvmAsmParser.y @@ -1101,7 +1101,7 @@ Module *llvm::RunVMAsmParser(const char * AsmString, Module * M) { %token 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; } diff --git a/lib/CodeGen/SelectionDAG/LegalizeDAG.cpp b/lib/CodeGen/SelectionDAG/LegalizeDAG.cpp index 4131ed9ecf7..078cbf3d7a2 100644 --- a/lib/CodeGen/SelectionDAG/LegalizeDAG.cpp +++ b/lib/CodeGen/SelectionDAG/LegalizeDAG.cpp @@ -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() && diff --git a/lib/CodeGen/SelectionDAG/SelectionDAG.cpp b/lib/CodeGen/SelectionDAG/SelectionDAG.cpp index d4d984b13f5..4b7863d896c 100644 --- a/lib/CodeGen/SelectionDAG/SelectionDAG.cpp +++ b/lib/CodeGen/SelectionDAG/SelectionDAG.cpp @@ -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(this)->get()) { default: assert(0 && "Unknown setcc condition!"); diff --git a/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp b/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp index 05578fe31cd..ce09eb4f487 100644 --- a/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp +++ b/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp @@ -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(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)) { diff --git a/lib/Target/ARM/ARMISelLowering.cpp b/lib/Target/ARM/ARMISelLowering.cpp index 6f63fbdcb31..a274c14eabf 100644 --- a/lib/Target/ARM/ARMISelLowering.cpp +++ b/lib/Target/ARM/ARMISelLowering.cpp @@ -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(); } diff --git a/lib/Target/ARM/ARMISelLowering.h b/lib/Target/ARM/ARMISelLowering.h index 2b66f2332d2..318657eb8e2 100644 --- a/lib/Target/ARM/ARMISelLowering.h +++ b/lib/Target/ARM/ARMISelLowering.h @@ -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); }; } diff --git a/lib/Target/Alpha/AlphaISelLowering.cpp b/lib/Target/Alpha/AlphaISelLowering.cpp index d4777b2c5f4..adbf322dade 100644 --- a/lib/Target/Alpha/AlphaISelLowering.cpp +++ b/lib/Target/Alpha/AlphaISelLowering.cpp @@ -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); diff --git a/lib/Target/IA64/IA64ISelLowering.cpp b/lib/Target/IA64/IA64ISelLowering.cpp index 0237a9a47b6..b9508a9cb35 100644 --- a/lib/Target/IA64/IA64ISelLowering.cpp +++ b/lib/Target/IA64/IA64ISelLowering.cpp @@ -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); diff --git a/lib/Target/Mips/MipsISelLowering.cpp b/lib/Target/Mips/MipsISelLowering.cpp index 790cdaf79f2..33283365bfe 100644 --- a/lib/Target/Mips/MipsISelLowering.cpp +++ b/lib/Target/Mips/MipsISelLowering.cpp @@ -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(); } diff --git a/lib/Target/PowerPC/PPCISelLowering.cpp b/lib/Target/PowerPC/PPCISelLowering.cpp index 6c2f3837b23..0ed1112fff2 100644 --- a/lib/Target/PowerPC/PPCISelLowering.cpp +++ b/lib/Target/PowerPC/PPCISelLowering.cpp @@ -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); diff --git a/lib/Target/Sparc/SparcISelDAGToDAG.cpp b/lib/Target/Sparc/SparcISelDAGToDAG.cpp index 8c8b3f8d3ac..536abc11cb7 100644 --- a/lib/Target/Sparc/SparcISelDAGToDAG.cpp +++ b/lib/Target/Sparc/SparcISelDAGToDAG.cpp @@ -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. diff --git a/lib/Target/TargetCallingConv.td b/lib/Target/TargetCallingConv.td index 94193200eaa..176a848ec02 100644 --- a/lib/Target/TargetCallingConv.td +++ b/lib/Target/TargetCallingConv.td @@ -45,6 +45,10 @@ class CCIfCC /// the specified action. class CCIfInReg : CCIf<"ArgFlags & ISD::ParamFlags::InReg", A> {} +/// CCIfNest - If this argument is marked with the 'nest' attribute, apply +/// the specified action. +class CCIfNest : CCIf<"ArgFlags & ISD::ParamFlags::Nest", A> {} + /// CCIfNotVarArg - If the current function is not vararg - apply the action class CCIfNotVarArg : CCIf<"!State.isVarArg()", A> {} diff --git a/lib/VMCore/Function.cpp b/lib/VMCore/Function.cpp index dd781964a91..1374d55e7d9 100644 --- a/lib/VMCore/Function.cpp +++ b/lib/VMCore/Function.cpp @@ -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; } diff --git a/lib/VMCore/Verifier.cpp b/lib/VMCore/Verifier.cpp index ffca88bfabc..de4050dadae 100644 --- a/lib/VMCore/Verifier.cpp +++ b/lib/VMCore/Verifier.cpp @@ -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(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), -- 2.34.1