diff options
author | Duncan Sands <baldrick@free.fr> | 2007-11-28 17:07:01 +0000 |
---|---|---|
committer | Duncan Sands <baldrick@free.fr> | 2007-11-28 17:07:01 +0000 |
commit | afa3b6da11bc05281bcf09e45de9e037e0ee5011 (patch) | |
tree | bad8f7480a6ea8ab2cbce2ad3427e8173247f68e | |
parent | 1e7b1bbd9c939ce1581862a6e0f8961279ea5992 (diff) | |
download | external_llvm-afa3b6da11bc05281bcf09e45de9e037e0ee5011.zip external_llvm-afa3b6da11bc05281bcf09e45de9e037e0ee5011.tar.gz external_llvm-afa3b6da11bc05281bcf09e45de9e037e0ee5011.tar.bz2 |
Add some convenience methods for querying attributes, and
use them.
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@44403 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r-- | include/llvm/Function.h | 10 | ||||
-rw-r--r-- | include/llvm/Instructions.h | 17 | ||||
-rw-r--r-- | include/llvm/Support/CallSite.h | 4 | ||||
-rw-r--r-- | lib/Analysis/BasicAliasAnalysis.cpp | 5 | ||||
-rw-r--r-- | lib/AsmParser/llvmAsmParser.cpp.cvs | 6 | ||||
-rw-r--r-- | lib/AsmParser/llvmAsmParser.y.cvs | 6 | ||||
-rw-r--r-- | lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp | 23 | ||||
-rw-r--r-- | lib/ExecutionEngine/Interpreter/Execution.cpp | 21 | ||||
-rw-r--r-- | lib/Target/MSIL/MSILWriter.cpp | 5 | ||||
-rw-r--r-- | lib/Transforms/Scalar/SimplifyCFG.cpp | 33 | ||||
-rw-r--r-- | lib/VMCore/Function.cpp | 7 | ||||
-rw-r--r-- | lib/VMCore/Instructions.cpp | 26 | ||||
-rw-r--r-- | test/Transforms/SimplifyCFG/2007-11-22-InvokeNoUnwind.ll | 2 | ||||
-rw-r--r-- | tools/llvm-upgrade/UpgradeParser.cpp.cvs | 2 | ||||
-rw-r--r-- | tools/llvm-upgrade/UpgradeParser.y.cvs | 2 |
15 files changed, 81 insertions, 88 deletions
diff --git a/include/llvm/Function.h b/include/llvm/Function.h index 897e53b..627b47f 100644 --- a/include/llvm/Function.h +++ b/include/llvm/Function.h @@ -21,6 +21,7 @@ #include "llvm/GlobalValue.h" #include "llvm/BasicBlock.h" #include "llvm/Argument.h" +#include "llvm/ParameterAttributes.h" #include "llvm/Support/Annotation.h" namespace llvm { @@ -152,8 +153,15 @@ public: /// @brief Set the parameter attributes. void setParamAttrs(const ParamAttrsList *attrs); + /// @brief Determine whether the function has the given attribute. + bool paramHasAttr(uint16_t i, ParameterAttributes attr) const { + return ParamAttrs && ParamAttrs->paramHasAttr(i, attr); + } + /// @brief Determine if the function returns a structure. - bool isStructReturn() const; + bool isStructReturn() const { + return paramHasAttr(1, ParamAttr::StructRet); + } /// deleteBody - This method deletes the body of the function, and converts /// the linkage to external. diff --git a/include/llvm/Instructions.h b/include/llvm/Instructions.h index 96ca43d..34b22c7 100644 --- a/include/llvm/Instructions.h +++ b/include/llvm/Instructions.h @@ -20,6 +20,7 @@ #include "llvm/InstrTypes.h" #include "llvm/DerivedTypes.h" +#include "llvm/ParameterAttributes.h" namespace llvm { @@ -923,8 +924,14 @@ public: /// @brief Set the parameter attributes. void setParamAttrs(const ParamAttrsList *attrs); + /// @brief Determine whether the call or the callee has the given attribute. + bool paramHasAttr(uint16_t i, ParameterAttributes attr) const; + /// @brief Determine if the call returns a structure. - bool isStructReturn() const; + bool isStructReturn() const { + // Be friendly and also check the callee. + return paramHasAttr(1, ParamAttr::StructRet); + } /// getCalledFunction - Return the function being called by this instruction /// if it is a direct call. If it is a call through a function pointer, @@ -1701,8 +1708,14 @@ public: /// @brief Set the parameter attributes. void setParamAttrs(const ParamAttrsList *attrs); + /// @brief Determine whether the call or the callee has the given attribute. + bool paramHasAttr(uint16_t i, ParameterAttributes attr) const; + /// @brief Determine if the call returns a structure. - bool isStructReturn() const; + bool isStructReturn() const { + // Be friendly and also check the callee. + return paramHasAttr(1, ParamAttr::StructRet); + } /// getCalledFunction - Return the function called, or null if this is an /// indirect function invocation. diff --git a/include/llvm/Support/CallSite.h b/include/llvm/Support/CallSite.h index d03d209..b613dff 100644 --- a/include/llvm/Support/CallSite.h +++ b/include/llvm/Support/CallSite.h @@ -22,6 +22,7 @@ #include "llvm/Instruction.h" #include "llvm/BasicBlock.h" +#include "llvm/ParameterAttributes.h" namespace llvm { @@ -63,6 +64,9 @@ public: const ParamAttrsList *getParamAttrs() const; void setParamAttrs(const ParamAttrsList *PAL); + /// paramHasAttr - whether the call or the callee has the given attribute. + bool paramHasAttr(uint16_t i, ParameterAttributes attr) const; + /// getType - Return the type of the instruction that generated this call site /// const Type *getType() const { return I->getType(); } diff --git a/lib/Analysis/BasicAliasAnalysis.cpp b/lib/Analysis/BasicAliasAnalysis.cpp index 82dee54..575e921 100644 --- a/lib/Analysis/BasicAliasAnalysis.cpp +++ b/lib/Analysis/BasicAliasAnalysis.cpp @@ -839,10 +839,9 @@ BasicAliasAnalysis::getModRefBehavior(Function *F, CallSite CS, return UnknownModRefBehavior; } - const ParamAttrsList *Attrs = F->getParamAttrs(); - if (Attrs && Attrs->paramHasAttr(0, ParamAttr::ReadNone)) + if (F->paramHasAttr(0, ParamAttr::ReadNone)) return DoesNotAccessMemory; - if (Attrs && Attrs->paramHasAttr(0, ParamAttr::ReadOnly)) + if (F->paramHasAttr(0, ParamAttr::ReadOnly)) return OnlyReadsMemory; return UnknownModRefBehavior; diff --git a/lib/AsmParser/llvmAsmParser.cpp.cvs b/lib/AsmParser/llvmAsmParser.cpp.cvs index 5907eec..c5b414c 100644 --- a/lib/AsmParser/llvmAsmParser.cpp.cvs +++ b/lib/AsmParser/llvmAsmParser.cpp.cvs @@ -5161,7 +5161,7 @@ yyreduce: bool isVarArg = ParamTypeList.size() && ParamTypeList.back() == Type::VoidTy; if (isVarArg) ParamTypeList.pop_back(); - ParamAttrsList *PAL = 0; + const ParamAttrsList *PAL = 0; if (!Attrs.empty()) PAL = ParamAttrsList::get(Attrs); @@ -5664,7 +5664,7 @@ yyreduce: GEN_ERROR("Invalid number of parameters detected"); } - ParamAttrsList *PAL = 0; + const ParamAttrsList *PAL = 0; if (!Attrs.empty()) PAL = ParamAttrsList::get(Attrs); @@ -6094,7 +6094,7 @@ yyreduce: } // Finish off the ParamAttrs and check them - ParamAttrsList *PAL = 0; + const ParamAttrsList *PAL = 0; if (!Attrs.empty()) PAL = ParamAttrsList::get(Attrs); diff --git a/lib/AsmParser/llvmAsmParser.y.cvs b/lib/AsmParser/llvmAsmParser.y.cvs index 683b95b..31fd619 100644 --- a/lib/AsmParser/llvmAsmParser.y.cvs +++ b/lib/AsmParser/llvmAsmParser.y.cvs @@ -2243,7 +2243,7 @@ FunctionHeaderH : OptCallingConv ResultTypes GlobalName '(' ArgList ')' bool isVarArg = ParamTypeList.size() && ParamTypeList.back() == Type::VoidTy; if (isVarArg) ParamTypeList.pop_back(); - ParamAttrsList *PAL = 0; + const ParamAttrsList *PAL = 0; if (!Attrs.empty()) PAL = ParamAttrsList::get(Attrs); @@ -2645,7 +2645,7 @@ BBTerminatorInst : RET ResolvedVal { // Return with a result... GEN_ERROR("Invalid number of parameters detected"); } - ParamAttrsList *PAL = 0; + const ParamAttrsList *PAL = 0; if (!Attrs.empty()) PAL = ParamAttrsList::get(Attrs); @@ -2977,7 +2977,7 @@ InstVal : ArithmeticOps Types ValueRef ',' ValueRef { } // Finish off the ParamAttrs and check them - ParamAttrsList *PAL = 0; + const ParamAttrsList *PAL = 0; if (!Attrs.empty()) PAL = ParamAttrsList::get(Attrs); diff --git a/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp b/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp index 3ba886f..a350ea9 100644 --- a/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp +++ b/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp @@ -934,11 +934,11 @@ void SelectionDAGLowering::visitRet(ReturnInst &I) { TmpVT = TLI.getTypeToTransformTo(MVT::i32); else TmpVT = MVT::i32; - const ParamAttrsList *PAL = I.getParent()->getParent()->getParamAttrs(); + const Function *F = I.getParent()->getParent(); ISD::NodeType ExtendKind = ISD::ANY_EXTEND; - if (PAL && PAL->paramHasAttr(0, ParamAttr::SExt)) + if (F->paramHasAttr(0, ParamAttr::SExt)) ExtendKind = ISD::SIGN_EXTEND; - if (PAL && PAL->paramHasAttr(0, ParamAttr::ZExt)) + if (F->paramHasAttr(0, ParamAttr::ZExt)) ExtendKind = ISD::ZERO_EXTEND; RetOp = DAG.getNode(ExtendKind, TmpVT, RetOp); NewValues.push_back(RetOp); @@ -3892,7 +3892,6 @@ void SelectionDAGLowering::visitVACopy(CallInst &I) { /// integrated into SDISel. std::vector<SDOperand> TargetLowering::LowerArguments(Function &F, SelectionDAG &DAG) { - const ParamAttrsList *Attrs = F.getParamAttrs(); // Add CC# and isVararg as operands to the FORMAL_ARGUMENTS node. std::vector<SDOperand> Ops; Ops.push_back(DAG.getRoot()); @@ -3911,15 +3910,15 @@ TargetLowering::LowerArguments(Function &F, SelectionDAG &DAG) { // FIXME: Distinguish between a formal with no [sz]ext attribute from one // that is zero extended! - if (Attrs && Attrs->paramHasAttr(j, ParamAttr::ZExt)) + if (F.paramHasAttr(j, ParamAttr::ZExt)) Flags &= ~(ISD::ParamFlags::SExt); - if (Attrs && Attrs->paramHasAttr(j, ParamAttr::SExt)) + if (F.paramHasAttr(j, ParamAttr::SExt)) Flags |= ISD::ParamFlags::SExt; - if (Attrs && Attrs->paramHasAttr(j, ParamAttr::InReg)) + if (F.paramHasAttr(j, ParamAttr::InReg)) Flags |= ISD::ParamFlags::InReg; - if (Attrs && Attrs->paramHasAttr(j, ParamAttr::StructRet)) + if (F.paramHasAttr(j, ParamAttr::StructRet)) Flags |= ISD::ParamFlags::StructReturn; - if (Attrs && Attrs->paramHasAttr(j, ParamAttr::ByVal)) { + if (F.paramHasAttr(j, ParamAttr::ByVal)) { Flags |= ISD::ParamFlags::ByVal; const PointerType *Ty = cast<PointerType>(I->getType()); const StructType *STy = cast<StructType>(Ty->getElementType()); @@ -3929,7 +3928,7 @@ TargetLowering::LowerArguments(Function &F, SelectionDAG &DAG) { Flags |= (StructAlign << ISD::ParamFlags::ByValAlignOffs); Flags |= (StructSize << ISD::ParamFlags::ByValSizeOffs); } - if (Attrs && Attrs->paramHasAttr(j, ParamAttr::Nest)) + if (F.paramHasAttr(j, ParamAttr::Nest)) Flags |= ISD::ParamFlags::Nest; Flags |= (OriginalAlignment << ISD::ParamFlags::OrigAlignmentOffs); @@ -3986,10 +3985,10 @@ TargetLowering::LowerArguments(Function &F, SelectionDAG &DAG) { case Promote: { SDOperand Op(Result, i++); if (MVT::isInteger(VT)) { - if (Attrs && Attrs->paramHasAttr(Idx, ParamAttr::SExt)) + if (F.paramHasAttr(Idx, ParamAttr::SExt)) Op = DAG.getNode(ISD::AssertSext, Op.getValueType(), Op, DAG.getValueType(VT)); - else if (Attrs && Attrs->paramHasAttr(Idx, ParamAttr::ZExt)) + else if (F.paramHasAttr(Idx, ParamAttr::ZExt)) Op = DAG.getNode(ISD::AssertZext, Op.getValueType(), Op, DAG.getValueType(VT)); Op = DAG.getNode(ISD::TRUNCATE, VT, Op); diff --git a/lib/ExecutionEngine/Interpreter/Execution.cpp b/lib/ExecutionEngine/Interpreter/Execution.cpp index 6ab1231..687814b 100644 --- a/lib/ExecutionEngine/Interpreter/Execution.cpp +++ b/lib/ExecutionEngine/Interpreter/Execution.cpp @@ -896,18 +896,15 @@ void Interpreter::visitCallSite(CallSite CS) { e = SF.Caller.arg_end(); i != e; ++i, ++pNum) { Value *V = *i; ArgVals.push_back(getOperandValue(V, SF)); - if (F) { - // Promote all integral types whose size is < sizeof(i32) into i32. - // We do this by zero or sign extending the value as appropriate - // according to the parameter attributes - const Type *Ty = V->getType(); - if (Ty->isInteger() && (ArgVals.back().IntVal.getBitWidth() < 32)) - if (const ParamAttrsList *PA = F->getParamAttrs()) - if (PA->paramHasAttr(pNum, ParamAttr::ZExt)) - ArgVals.back().IntVal = ArgVals.back().IntVal.zext(32); - else if (PA->paramHasAttr(pNum, ParamAttr::SExt)) - ArgVals.back().IntVal = ArgVals.back().IntVal.sext(32); - } + // Promote all integral types whose size is < sizeof(i32) into i32. + // We do this by zero or sign extending the value as appropriate + // according to the parameter attributes + const Type *Ty = V->getType(); + if (Ty->isInteger() && (ArgVals.back().IntVal.getBitWidth() < 32)) + if (CS.paramHasAttr(pNum, ParamAttr::ZExt)) + ArgVals.back().IntVal = ArgVals.back().IntVal.zext(32); + else if (CS.paramHasAttr(pNum, ParamAttr::SExt)) + ArgVals.back().IntVal = ArgVals.back().IntVal.sext(32); } // To handle indirect calls, we must get the pointer value from the argument diff --git a/lib/Target/MSIL/MSILWriter.cpp b/lib/Target/MSIL/MSILWriter.cpp index 2fe4f3b..dafdbe7 100644 --- a/lib/Target/MSIL/MSILWriter.cpp +++ b/lib/Target/MSIL/MSILWriter.cpp @@ -1387,8 +1387,7 @@ void MSILWriter::printStaticInitializerList() { void MSILWriter::printFunction(const Function& F) { - const ParamAttrsList *Attrs = F.getParamAttrs(); - bool isSigned = Attrs && Attrs->paramHasAttr(0, ParamAttr::SExt); + bool isSigned = F.paramHasAttr(0, ParamAttr::SExt); Out << "\n.method static "; Out << (F.hasInternalLinkage() ? "private " : "public "); if (F.isVarArg()) Out << "vararg "; @@ -1399,7 +1398,7 @@ void MSILWriter::printFunction(const Function& F) { unsigned ArgIdx = 1; for (Function::const_arg_iterator I = F.arg_begin(), E = F.arg_end(); I!=E; ++I, ++ArgIdx) { - isSigned = Attrs && Attrs->paramHasAttr(ArgIdx, ParamAttr::SExt); + isSigned = F.paramHasAttr(ArgIdx, ParamAttr::SExt); if (I!=F.arg_begin()) Out << ", "; Out << getTypeName(I->getType(),isSigned) << getValueName(I); } diff --git a/lib/Transforms/Scalar/SimplifyCFG.cpp b/lib/Transforms/Scalar/SimplifyCFG.cpp index 22d81c8..ed51746 100644 --- a/lib/Transforms/Scalar/SimplifyCFG.cpp +++ b/lib/Transforms/Scalar/SimplifyCFG.cpp @@ -90,35 +90,6 @@ static void ChangeToCall(InvokeInst *II) { BB->getInstList().erase(II); } -/// IsNoReturn - Return true if the specified call is to a no-return function. -static bool IsNoReturn(const CallInst *CI) { - if (const ParamAttrsList *Attrs = CI->getParamAttrs()) - if (Attrs->paramHasAttr(0, ParamAttr::NoReturn)) - return true; - - if (const Function *Callee = CI->getCalledFunction()) - if (const ParamAttrsList *Attrs = Callee->getParamAttrs()) - if (Attrs->paramHasAttr(0, ParamAttr::NoReturn)) - return true; - - return false; -} - -/// IsNoUnwind - Return true if the specified invoke is to a no-unwind function. -static bool IsNoUnwind(const InvokeInst *II) { - if (const ParamAttrsList *Attrs = II->getParamAttrs()) - if (Attrs->paramHasAttr(0, ParamAttr::NoUnwind)) - return true; - - if (const Function *Callee = II->getCalledFunction()) - if (const ParamAttrsList *Attrs = Callee->getParamAttrs()) - if (Attrs->paramHasAttr(0, ParamAttr::NoUnwind)) - return true; - - return false; -} - - static bool MarkAliveBlocks(BasicBlock *BB, SmallPtrSet<BasicBlock*, 128> &Reachable) { @@ -137,7 +108,7 @@ static bool MarkAliveBlocks(BasicBlock *BB, // canonicalizes unreachable insts into stores to null or undef. for (BasicBlock::iterator BBI = BB->begin(), E = BB->end(); BBI != E;++BBI){ if (CallInst *CI = dyn_cast<CallInst>(BBI)) { - if (IsNoReturn(CI)) { + if (CI->paramHasAttr(0, ParamAttr::NoReturn)) { // If we found a call to a no-return function, insert an unreachable // instruction after it. Make sure there isn't *already* one there // though. @@ -161,7 +132,7 @@ static bool MarkAliveBlocks(BasicBlock *BB, // Turn invokes that call 'nounwind' functions into ordinary calls. if (InvokeInst *II = dyn_cast<InvokeInst>(BB->getTerminator())) - if (IsNoUnwind(II)) { + if (II->paramHasAttr(0, ParamAttr::NoUnwind)) { ChangeToCall(II); Changed = true; } diff --git a/lib/VMCore/Function.cpp b/lib/VMCore/Function.cpp index 023cb55..92853e3 100644 --- a/lib/VMCore/Function.cpp +++ b/lib/VMCore/Function.cpp @@ -13,7 +13,6 @@ #include "llvm/Module.h" #include "llvm/DerivedTypes.h" -#include "llvm/ParameterAttributes.h" #include "llvm/IntrinsicInst.h" #include "llvm/CodeGen/ValueTypes.h" #include "llvm/Support/LeakDetector.h" @@ -287,12 +286,6 @@ void Function::setParamAttrs(const ParamAttrsList *attrs) { ParamAttrs = attrs; } -bool Function::isStructReturn() const { - if (ParamAttrs) - return ParamAttrs->paramHasAttr(1, ParamAttr::StructRet); - return false; -} - const FunctionType *Function::getFunctionType() const { return cast<FunctionType>(getType()->getElementType()); } diff --git a/lib/VMCore/Instructions.cpp b/lib/VMCore/Instructions.cpp index 7226f66..8e48491 100644 --- a/lib/VMCore/Instructions.cpp +++ b/lib/VMCore/Instructions.cpp @@ -47,6 +47,12 @@ void CallSite::setParamAttrs(const ParamAttrsList *PAL) { else cast<InvokeInst>(I)->setParamAttrs(PAL); } +bool CallSite::paramHasAttr(uint16_t i, ParameterAttributes attr) const { + if (CallInst *CI = dyn_cast<CallInst>(I)) + return CI->paramHasAttr(i, attr); + else + return cast<InvokeInst>(I)->paramHasAttr(i, attr); +} @@ -376,12 +382,14 @@ void CallInst::setParamAttrs(const ParamAttrsList *newAttrs) { ParamAttrs = newAttrs; } -bool CallInst::isStructReturn() const { - if (ParamAttrs) - return ParamAttrs->paramHasAttr(1, ParamAttr::StructRet); - return false; +bool CallInst::paramHasAttr(uint16_t i, ParameterAttributes attr) const { + if (ParamAttrs && ParamAttrs->paramHasAttr(i, attr)) + return true; + const Function *F = getCalledFunction(); + return F && F->getParamAttrs() && F->getParamAttrs()->paramHasAttr(i, attr); } + //===----------------------------------------------------------------------===// // InvokeInst Implementation //===----------------------------------------------------------------------===// @@ -451,12 +459,14 @@ void InvokeInst::setParamAttrs(const ParamAttrsList *newAttrs) { ParamAttrs = newAttrs; } -bool InvokeInst::isStructReturn() const { - if (ParamAttrs) - return ParamAttrs->paramHasAttr(1, ParamAttr::StructRet); - return false; +bool InvokeInst::paramHasAttr(uint16_t i, ParameterAttributes attr) const { + if (ParamAttrs && ParamAttrs->paramHasAttr(i, attr)) + return true; + const Function *F = getCalledFunction(); + return F && F->getParamAttrs() && F->getParamAttrs()->paramHasAttr(i, attr); } + //===----------------------------------------------------------------------===// // ReturnInst Implementation //===----------------------------------------------------------------------===// diff --git a/test/Transforms/SimplifyCFG/2007-11-22-InvokeNoUnwind.ll b/test/Transforms/SimplifyCFG/2007-11-22-InvokeNoUnwind.ll index 8e8ef43..449047b 100644 --- a/test/Transforms/SimplifyCFG/2007-11-22-InvokeNoUnwind.ll +++ b/test/Transforms/SimplifyCFG/2007-11-22-InvokeNoUnwind.ll @@ -3,7 +3,7 @@ declare i32 @func(i8*) nounwind define i32 @test() { - invoke i32 @func( i8* null ) nounwind + invoke i32 @func( i8* null ) to label %Cont unwind label %Other ; <i32>:1 [#uses=0] Cont: ; preds = %0 diff --git a/tools/llvm-upgrade/UpgradeParser.cpp.cvs b/tools/llvm-upgrade/UpgradeParser.cpp.cvs index 8f8327e..dce1836 100644 --- a/tools/llvm-upgrade/UpgradeParser.cpp.cvs +++ b/tools/llvm-upgrade/UpgradeParser.cpp.cvs @@ -4510,7 +4510,7 @@ yyreduce: bool isVarArg = Params.size() && Params.back() == Type::VoidTy; if (isVarArg) Params.pop_back(); - ParamAttrsList *PAL = 0; + const ParamAttrsList *PAL = 0; if (lastCallingConv == OldCallingConv::CSRet) { ParamAttrsVector Attrs; ParamAttrsWithIndex PAWI; diff --git a/tools/llvm-upgrade/UpgradeParser.y.cvs b/tools/llvm-upgrade/UpgradeParser.y.cvs index b9a26cb..7a6e3ef 100644 --- a/tools/llvm-upgrade/UpgradeParser.y.cvs +++ b/tools/llvm-upgrade/UpgradeParser.y.cvs @@ -2055,7 +2055,7 @@ UpRTypes bool isVarArg = Params.size() && Params.back() == Type::VoidTy; if (isVarArg) Params.pop_back(); - ParamAttrsList *PAL = 0; + const ParamAttrsList *PAL = 0; if (lastCallingConv == OldCallingConv::CSRet) { ParamAttrsVector Attrs; ParamAttrsWithIndex PAWI; |