const uint16_t ReturnOnly = NoReturn | NoUnwind | ReadNone | ReadOnly;
/// @brief Parameter attributes that do not apply to vararg call arguments.
-const uint16_t VarArgsIncompatible = Nest | StructRet;
+const uint16_t VarArgsIncompatible = StructRet;
/// @brief Attributes that are mutually incompatible.
const uint16_t MutuallyIncompatible[3] = {
return getParamAttrs(i) & attr;
}
+ /// This returns whether the given attribute is set for at least one
+ /// parameter or for the return value.
+ /// @returns true if the parameter attribute is set somewhere
+ /// @brief Determine if a ParameterAttributes is set somewhere
+ bool hasAttrSomewhere(ParameterAttributes attr) const;
+
/// The set of ParameterAttributes set in Attributes is converted to a
/// string of equivalent mnemonics. This is, presumably, for writing out
/// the mnemonics for the assembly writer.
Value *Callee = CS.getCalledValue();
const PointerType *PTy = cast<PointerType>(Callee->getType());
const FunctionType *FTy = cast<FunctionType>(PTy->getElementType());
+ const ParamAttrsList *Attrs = CS.getParamAttrs();
+
+ // If the call already has the 'nest' attribute somewhere then give up -
+ // otherwise 'nest' would occur twice after splicing in the chain.
+ if (Attrs && Attrs->hasAttrSomewhere(ParamAttr::Nest))
+ return 0;
IntrinsicInst *Tramp =
cast<IntrinsicInst>(cast<BitCastInst>(Callee)->getOperand(0));
std::vector<Value*> NewArgs;
NewArgs.reserve(unsigned(CS.arg_end()-CS.arg_begin())+1);
+ ParamAttrsVector NewAttrs;
+ NewAttrs.reserve(Attrs ? Attrs->size() + 1 : 1);
+
// Insert the nest argument into the call argument list, which may
- // mean appending it.
+ // mean appending it. Likewise for attributes.
+
+ // Add any function result attributes.
+ uint16_t Attr = Attrs ? Attrs->getParamAttrs(0) : 0;
+ if (Attr)
+ NewAttrs.push_back (ParamAttrsWithIndex::get(0, Attr));
+
{
unsigned Idx = 1;
CallSite::arg_iterator I = CS.arg_begin(), E = CS.arg_end();
do {
if (Idx == NestIdx) {
- // Add the chain argument.
+ // Add the chain argument and attributes.
Value *NestVal = Tramp->getOperand(3);
if (NestVal->getType() != NestTy)
NestVal = new BitCastInst(NestVal, NestTy, "nest", Caller);
NewArgs.push_back(NestVal);
+ NewAttrs.push_back(ParamAttrsWithIndex::get(NestIdx, NestAttr));
}
if (I == E)
break;
- // Add the original argument.
+ // Add the original argument and attributes.
NewArgs.push_back(*I);
+ Attr = Attrs ? Attrs->getParamAttrs(Idx) : 0;
+ if (Attr)
+ NewAttrs.push_back
+ (ParamAttrsWithIndex::get(Idx + (Idx >= NestIdx), Attr));
++Idx, ++I;
} while (1);
// The trampoline may have been bitcast to a bogus type (FTy).
// Handle this by synthesizing a new function type, equal to FTy
- // with the chain parameter inserted. Likewise for attributes.
+ // with the chain parameter inserted.
- const ParamAttrsList *Attrs = CS.getParamAttrs();
std::vector<const Type*> NewTypes;
- ParamAttrsVector NewAttrs;
NewTypes.reserve(FTy->getNumParams()+1);
- // Add any function result attributes.
- uint16_t Attr = Attrs ? Attrs->getParamAttrs(0) : 0;
- if (Attr)
- NewAttrs.push_back (ParamAttrsWithIndex::get(0, Attr));
-
// Insert the chain's type into the list of parameter types, which may
- // mean appending it. Likewise for the chain's attributes.
+ // mean appending it.
{
unsigned Idx = 1;
FunctionType::param_iterator I = FTy->param_begin(),
E = FTy->param_end();
do {
- if (Idx == NestIdx) {
- // Add the chain's type and attributes.
+ if (Idx == NestIdx)
+ // Add the chain's type.
NewTypes.push_back(NestTy);
- NewAttrs.push_back(ParamAttrsWithIndex::get(NestIdx, NestAttr));
- }
if (I == E)
break;
- // Add the original type and attributes.
+ // Add the original type.
NewTypes.push_back(*I);
- Attr = Attrs ? Attrs->getParamAttrs(Idx) : 0;
- if (Attr)
- NewAttrs.push_back
- (ParamAttrsWithIndex::get(Idx + (Idx >= NestIdx), Attr));
++Idx, ++I;
} while (1);
return ParamAttr::None;
}
+bool ParamAttrsList::hasAttrSomewhere(ParameterAttributes attr) const {
+ for (unsigned i = 0, e = attrs.size(); i < e; ++i)
+ if (attrs[i].attrs & attr)
+ return true;
+ return false;
+}
+
std::string
ParamAttrsList::getParamAttrsText(uint16_t Attrs) {
std::string Result;
--- /dev/null
+; RUN: llvm-as < %s | opt -instcombine -disable-output
+
+ %struct.FRAME.nest = type { i32, i32 (i32*)* }
+ %struct.__builtin_trampoline = type { [10 x i8] }
+
+declare i8* @llvm.init.trampoline(i8*, i8*, i8*) nounwind
+
+declare i32 @f(%struct.FRAME.nest* nest , i32*)
+
+define i32 @nest(i32 %n) {
+entry:
+ %FRAME.0 = alloca %struct.FRAME.nest, align 8 ; <%struct.FRAME.nest*> [#uses=3]
+ %TRAMP.216 = alloca [10 x i8], align 16 ; <[10 x i8]*> [#uses=1]
+ %TRAMP.216.sub = getelementptr [10 x i8]* %TRAMP.216, i32 0, i32 0 ; <i8*> [#uses=1]
+ %tmp3 = getelementptr %struct.FRAME.nest* %FRAME.0, i32 0, i32 0 ; <i32*> [#uses=1]
+ store i32 %n, i32* %tmp3, align 8
+ %FRAME.06 = bitcast %struct.FRAME.nest* %FRAME.0 to i8* ; <i8*> [#uses=1]
+ %tramp = call i8* @llvm.init.trampoline( i8* %TRAMP.216.sub, i8* bitcast (i32 (%struct.FRAME.nest*, i32*)* @f to i8*), i8* %FRAME.06 ) ; <i8*> [#uses=1]
+ %tmp7 = getelementptr %struct.FRAME.nest* %FRAME.0, i32 0, i32 1 ; <i32 (i32*)**> [#uses=1]
+ %tmp89 = bitcast i8* %tramp to i32 (i32*)* ; <i32 (i32*)*> [#uses=2]
+ store i32 (i32*)* %tmp89, i32 (i32*)** %tmp7, align 8
+ %tmp2.i = call i32 %tmp89( i32* nest null ) ; <i32> [#uses=1]
+ ret i32 %tmp2.i
+}
--- /dev/null
+; RUN: llvm-as < %s | opt -instcombine | llvm-dis | grep zeroext
+
+ %struct.FRAME.nest = type { i32, i32 (...)* }
+ %struct.__builtin_trampoline = type { [10 x i8] }
+
+declare i8* @llvm.init.trampoline(i8*, i8*, i8*) nounwind
+
+declare i32 @f(%struct.FRAME.nest* nest , ...)
+
+define i32 @nest(i32 %n) {
+entry:
+ %FRAME.0 = alloca %struct.FRAME.nest, align 8 ; <%struct.FRAME.nest*> [#uses=3]
+ %TRAMP.216 = alloca [10 x i8], align 16 ; <[10 x i8]*> [#uses=1]
+ %TRAMP.216.sub = getelementptr [10 x i8]* %TRAMP.216, i32 0, i32 0 ; <i8*> [#uses=1]
+ %tmp3 = getelementptr %struct.FRAME.nest* %FRAME.0, i32 0, i32 0 ; <i32*> [#uses=1]
+ store i32 %n, i32* %tmp3, align 8
+ %FRAME.06 = bitcast %struct.FRAME.nest* %FRAME.0 to i8* ; <i8*> [#uses=1]
+ %tramp = call i8* @llvm.init.trampoline( i8* %TRAMP.216.sub, i8* bitcast (i32 (%struct.FRAME.nest*, ...)* @f to i8*), i8* %FRAME.06 ) ; <i8*> [#uses=1]
+ %tmp7 = getelementptr %struct.FRAME.nest* %FRAME.0, i32 0, i32 1 ; <i32 (...)**> [#uses=1]
+ %tmp89 = bitcast i8* %tramp to i32 (...)* ; <i32 (...)*> [#uses=2]
+ store i32 (...)* %tmp89, i32 (...)** %tmp7, align 8
+ %tmp2.i = call i32 (...)* %tmp89( i32 zeroext 0 ) ; <i32> [#uses=1]
+ ret i32 %tmp2.i
+}