Index: llvm/include/llvm/IR/Module.h =================================================================== --- llvm/include/llvm/IR/Module.h +++ llvm/include/llvm/IR/Module.h @@ -363,6 +363,8 @@ /// In all cases, the returned value is a FunctionCallee wrapper around the /// 'FunctionType *T' passed in, as well as a 'Value*' either of the Function or /// the bitcast to the function. + /// + /// Note: For library calls getOrInsertLibFunc() should be used instead. FunctionCallee getOrInsertFunction(StringRef Name, FunctionType *T, AttributeList AttributeList); Index: llvm/include/llvm/Transforms/Utils/BuildLibCalls.h =================================================================== --- llvm/include/llvm/Transforms/Utils/BuildLibCalls.h +++ llvm/include/llvm/Transforms/Utils/BuildLibCalls.h @@ -22,12 +22,48 @@ class IRBuilderBase; /// Analyze the name and prototype of the given function and set any - /// applicable attributes. + /// applicable attributes. Note that this merely helps optimizations on an + /// already existing function but does not consider mandatory attributes. + /// /// If the library function is unavailable, this doesn't modify it. /// /// Returns true if any attributes were set and false otherwise. - bool inferLibFuncAttributes(Function &F, const TargetLibraryInfo &TLI); - bool inferLibFuncAttributes(Module *M, StringRef Name, const TargetLibraryInfo &TLI); + bool inferNonMandatoryLibFuncAttrs(Module *M, StringRef Name, + const TargetLibraryInfo &TLI); + bool inferNonMandatoryLibFuncAttrs(Function &F, const TargetLibraryInfo &TLI); + + /// Calls getOrInsertFunction() and then makes sure to add mandatory + /// argument attributes. + FunctionCallee getOrInsertLibFunc(Module *M, const TargetLibraryInfo &TLI, + LibFunc TheLibFunc, StringRef Name, + FunctionType *T, AttributeList AttributeList); + FunctionCallee getOrInsertLibFunc(Module *M, const TargetLibraryInfo &TLI, + LibFunc TheLibFunc, StringRef Name, + FunctionType *T); + template + FunctionCallee getOrInsertLibFunc(Module *M, const TargetLibraryInfo &TLI, + LibFunc TheLibFunc, StringRef Name, + AttributeList AttributeList, Type *RetTy, + ArgsTy... Args) { + SmallVector ArgTys{Args...}; + return getOrInsertLibFunc(M, TLI, TheLibFunc, Name, + FunctionType::get(RetTy, ArgTys, false), + AttributeList); + } + /// Same as above, but without the attributes. + template + FunctionCallee getOrInsertLibFunc(Module *M, const TargetLibraryInfo &TLI, + LibFunc TheLibFunc, StringRef Name, Type *RetTy, + ArgsTy... Args) { + return getOrInsertLibFunc(M, TLI, TheLibFunc, Name, AttributeList{}, RetTy, + Args...); + } + // Avoid an incorrect ordering that'd otherwise compile incorrectly. + template + FunctionCallee + getOrInsertLibFunc(Module *M, const TargetLibraryInfo &TLI, + LibFunc TheLibFunc, StringRef Name, AttributeList AttributeList, + FunctionType *Invalid, ArgsTy... Args) = delete; /// Check whether the overloaded floating point function /// corresponding to \a Ty is available. @@ -35,10 +71,10 @@ LibFunc DoubleFn, LibFunc FloatFn, LibFunc LongDoubleFn); /// Get the name of the overloaded floating point function - /// corresponding to \a Ty. - StringRef getFloatFnName(const TargetLibraryInfo *TLI, Type *Ty, - LibFunc DoubleFn, LibFunc FloatFn, - LibFunc LongDoubleFn); + /// corresponding to \a Ty. Return the LibFunc in \a TheLibFunc. + StringRef getFloatFn(const TargetLibraryInfo *TLI, Type *Ty, + LibFunc DoubleFn, LibFunc FloatFn, + LibFunc LongDoubleFn, LibFunc &TheLibFunc); /// Return V if it is an i8*, otherwise cast it to i8*. Value *castToCStr(Value *V, IRBuilderBase &B); @@ -148,7 +184,8 @@ /// function is known to take a single of type matching 'Op' and returns one /// value with the same type. If 'Op' is a long double, 'l' is added as the /// suffix of name, if 'Op' is a float, we add a 'f' suffix. - Value *emitUnaryFloatFnCall(Value *Op, StringRef Name, IRBuilderBase &B, + Value *emitUnaryFloatFnCall(Value *Op, const TargetLibraryInfo *TLI, + StringRef Name, IRBuilderBase &B, const AttributeList &Attrs); /// Emit a call to the unary function DoubleFn, FloatFn or LongDoubleFn, @@ -162,8 +199,10 @@ /// function is known to take type matching 'Op1' and 'Op2' and return one /// value with the same type. If 'Op1/Op2' are long double, 'l' is added as /// the suffix of name, if 'Op1/Op2' are float, we add a 'f' suffix. - Value *emitBinaryFloatFnCall(Value *Op1, Value *Op2, StringRef Name, - IRBuilderBase &B, const AttributeList &Attrs); + Value *emitBinaryFloatFnCall(Value *Op1, Value *Op2, + const TargetLibraryInfo *TLI, + StringRef Name, IRBuilderBase &B, + const AttributeList &Attrs); /// Emit a call to the binary function DoubleFn, FloatFn or LongDoubleFn, /// depending of the type of Op1. Index: llvm/lib/Transforms/IPO/InferFunctionAttrs.cpp =================================================================== --- llvm/lib/Transforms/IPO/InferFunctionAttrs.cpp +++ llvm/lib/Transforms/IPO/InferFunctionAttrs.cpp @@ -29,7 +29,7 @@ // explicitly visited by CGSCC passes in the new pass manager.) if (F.isDeclaration() && !F.hasOptNone()) { if (!F.hasFnAttribute(Attribute::NoBuiltin)) - Changed |= inferLibFuncAttributes(F, GetTLI(F)); + Changed |= inferNonMandatoryLibFuncAttrs(F, GetTLI(F)); Changed |= inferAttributesFromOthers(F); } Index: llvm/lib/Transforms/Scalar/LoopIdiomRecognize.cpp =================================================================== --- llvm/lib/Transforms/Scalar/LoopIdiomRecognize.cpp +++ llvm/lib/Transforms/Scalar/LoopIdiomRecognize.cpp @@ -1188,9 +1188,9 @@ Module *M = TheStore->getModule(); StringRef FuncName = "memset_pattern16"; - FunctionCallee MSP = M->getOrInsertFunction(FuncName, Builder.getVoidTy(), - Int8PtrTy, Int8PtrTy, IntIdxTy); - inferLibFuncAttributes(M, FuncName, *TLI); + FunctionCallee MSP = getOrInsertLibFunc(M, *TLI, LibFunc_memset_pattern16, + FuncName, Builder.getVoidTy(), Int8PtrTy, Int8PtrTy, IntIdxTy); + inferNonMandatoryLibFuncAttrs(M, FuncName, *TLI); // Otherwise we should form a memset_pattern16. PatternValue is known to be // an constant array of 16-bytes. Plop the value into a mergable global. Index: llvm/lib/Transforms/Utils/BuildLibCalls.cpp =================================================================== --- llvm/lib/Transforms/Utils/BuildLibCalls.cpp +++ llvm/lib/Transforms/Utils/BuildLibCalls.cpp @@ -39,7 +39,6 @@ STATISTIC(NumNoUnwind, "Number of functions inferred as nounwind"); STATISTIC(NumNoCapture, "Number of arguments inferred as nocapture"); STATISTIC(NumWriteOnlyArg, "Number of arguments inferred as writeonly"); -STATISTIC(NumExtArg, "Number of arguments inferred as signext/zeroext."); STATISTIC(NumReadOnlyArg, "Number of arguments inferred as readonly"); STATISTIC(NumNoAlias, "Number of function returns inferred as noalias"); STATISTIC(NumNoUndef, "Number of function returns inferred as noundef returns"); @@ -147,16 +146,6 @@ return true; } -static bool setArgExtAttr(Function &F, unsigned ArgNo, - const TargetLibraryInfo &TLI, bool Signed = true) { - Attribute::AttrKind ExtAttr = TLI.getExtAttrForI32Param(Signed); - if (ExtAttr == Attribute::None || F.hasParamAttribute(ArgNo, ExtAttr)) - return false; - F.addParamAttr(ArgNo, ExtAttr); - ++NumExtArg; - return true; -} - static bool setRetNoUndef(Function &F) { if (!F.getReturnType()->isVoidTy() && !F.hasRetAttribute(Attribute::NoUndef)) { @@ -240,15 +229,16 @@ return true; } -bool llvm::inferLibFuncAttributes(Module *M, StringRef Name, - const TargetLibraryInfo &TLI) { +bool llvm::inferNonMandatoryLibFuncAttrs(Module *M, StringRef Name, + const TargetLibraryInfo &TLI) { Function *F = M->getFunction(Name); if (!F) return false; - return inferLibFuncAttributes(*F, TLI); + return inferNonMandatoryLibFuncAttrs(*F, TLI); } -bool llvm::inferLibFuncAttributes(Function &F, const TargetLibraryInfo &TLI) { +bool llvm::inferNonMandatoryLibFuncAttrs(Function &F, + const TargetLibraryInfo &TLI) { LibFunc TheLibFunc; if (!(TLI.getLibFunc(F, TheLibFunc) && TLI.has(TheLibFunc))) return false; @@ -845,7 +835,6 @@ case LibFunc_putchar: case LibFunc_putchar_unlocked: Changed |= setRetAndArgsNoUndef(F); - Changed |= setArgExtAttr(F, 0, TLI); Changed |= setDoesNotThrow(F); return Changed; case LibFunc_popen: @@ -1066,7 +1055,6 @@ case LibFunc_ldexp: case LibFunc_ldexpf: case LibFunc_ldexpl: - Changed |= setArgExtAttr(F, 1, TLI); Changed |= setWillReturn(F); return Changed; case LibFunc_abs: @@ -1203,6 +1191,69 @@ } } +static void setArgExtAttr(Function &F, unsigned ArgNo, + const TargetLibraryInfo &TLI, bool Signed = true) { + Attribute::AttrKind ExtAttr = TLI.getExtAttrForI32Param(Signed); + if (ExtAttr != Attribute::None && !F.hasParamAttribute(ArgNo, ExtAttr)) + F.addParamAttr(ArgNo, ExtAttr); +} + +FunctionCallee llvm::getOrInsertLibFunc(Module *M, const TargetLibraryInfo &TLI, + LibFunc TheLibFunc, StringRef Name, FunctionType *T, + AttributeList AttributeList) { + assert(TLI.has(TheLibFunc) && + "Creating call to non-existing library function."); + FunctionCallee C = M->getOrInsertFunction(Name, T, AttributeList); + + // Make sure any mandatory argument attributes are added. + + // Any outgoing i32 argument should be handled with setArgExtAttr() which + // will add an extension attribute if the target ABI requires it. Adding + // argument extensions is typically done by the front end but when an + // optimizer is building a library call on its own it has to take care of + // this. Each such generated function must be handled here with sign or + // zero extensions as needed. + Function &F = *M->getFunction(Name); + switch (TheLibFunc) { + case LibFunc_fputc: + case LibFunc_putchar: + setArgExtAttr(F, 0, TLI); + break; + case LibFunc_ldexp: + case LibFunc_ldexpf: + case LibFunc_ldexpl: + case LibFunc_memchr: + case LibFunc_strchr: + setArgExtAttr(F, 1, TLI); + break; + case LibFunc_memccpy: + setArgExtAttr(F, 2, TLI); + break; + default: + break; + } + +#ifndef NDEBUG + // Make sure that any narrow integer argument is extended if required by + // the target ABI. + if (TLI.getExtAttrForI32Param() != Attribute::None) + for (unsigned i = 0; i < T->getNumParams(); i++) + if (auto *IntTy = dyn_cast(T->getParamType(i))) + if (IntTy->getBitWidth() <= 32) { + bool SExt = F.hasParamAttribute(i, Attribute::SExt); + bool ZExt = F.hasParamAttribute(i, Attribute::ZExt); + assert(SExt != ZExt && "Parameter should be properly extended."); + } +#endif + + return C; +} + +FunctionCallee llvm::getOrInsertLibFunc(Module *M, const TargetLibraryInfo &TLI, + LibFunc TheLibFunc, StringRef Name, FunctionType *T) { + return getOrInsertLibFunc(M, TLI, TheLibFunc, Name, T, AttributeList()); +} + bool llvm::hasFloatFn(const TargetLibraryInfo *TLI, Type *Ty, LibFunc DoubleFn, LibFunc FloatFn, LibFunc LongDoubleFn) { switch (Ty->getTypeID()) { @@ -1217,9 +1268,9 @@ } } -StringRef llvm::getFloatFnName(const TargetLibraryInfo *TLI, Type *Ty, - LibFunc DoubleFn, LibFunc FloatFn, - LibFunc LongDoubleFn) { +StringRef llvm::getFloatFn(const TargetLibraryInfo *TLI, Type *Ty, + LibFunc DoubleFn, LibFunc FloatFn, + LibFunc LongDoubleFn, LibFunc &TheLibFunc) { assert(hasFloatFn(TLI, Ty, DoubleFn, FloatFn, LongDoubleFn) && "Cannot get name for unavailable function!"); @@ -1227,10 +1278,13 @@ case Type::HalfTyID: llvm_unreachable("No name for HalfTy!"); case Type::FloatTyID: + TheLibFunc = FloatFn; return TLI->getName(FloatFn); case Type::DoubleTyID: + TheLibFunc = DoubleFn; return TLI->getName(DoubleFn); default: + TheLibFunc = LongDoubleFn; return TLI->getName(LongDoubleFn); } } @@ -1253,8 +1307,9 @@ Module *M = B.GetInsertBlock()->getModule(); StringRef FuncName = TLI->getName(TheLibFunc); FunctionType *FuncType = FunctionType::get(ReturnType, ParamTypes, IsVaArgs); - FunctionCallee Callee = M->getOrInsertFunction(FuncName, FuncType); - inferLibFuncAttributes(M, FuncName, *TLI); + FunctionCallee Callee = getOrInsertLibFunc(M, *TLI, TheLibFunc, FuncName, + FuncType); + inferNonMandatoryLibFuncAttrs(M, FuncName, *TLI); CallInst *CI = B.CreateCall(Callee, Operands, FuncName); if (const Function *F = dyn_cast(Callee.getCallee()->stripPointerCasts())) @@ -1331,7 +1386,7 @@ AS = AttributeList::get(M->getContext(), AttributeList::FunctionIndex, Attribute::NoUnwind); LLVMContext &Context = B.GetInsertBlock()->getContext(); - FunctionCallee MemCpy = M->getOrInsertFunction( + FunctionCallee MemCpy = getOrInsertLibFunc(M, *TLI, LibFunc_memcpy_chk, "__memcpy_chk", AttributeList::get(M->getContext(), AS), B.getInt8PtrTy(), B.getInt8PtrTy(), B.getInt8PtrTy(), DL.getIntPtrType(Context), DL.getIntPtrType(Context)); @@ -1466,14 +1521,15 @@ } } -static Value *emitUnaryFloatFnCallHelper(Value *Op, StringRef Name, - IRBuilderBase &B, - const AttributeList &Attrs) { +static Value *emitUnaryFloatFnCallHelper(Value *Op, LibFunc TheLibFunc, + StringRef Name, IRBuilderBase &B, + const AttributeList &Attrs, + const TargetLibraryInfo *TLI) { assert((Name != "") && "Must specify Name to emitUnaryFloatFnCall"); Module *M = B.GetInsertBlock()->getModule(); - FunctionCallee Callee = - M->getOrInsertFunction(Name, Op->getType(), Op->getType()); + FunctionCallee Callee = getOrInsertLibFunc(M, *TLI, TheLibFunc, Name, + Op->getType(), Op->getType()); CallInst *CI = B.CreateCall(Callee, Op, Name); // The incoming attribute set may have come from a speculatable intrinsic, but @@ -1488,12 +1544,16 @@ return CI; } -Value *llvm::emitUnaryFloatFnCall(Value *Op, StringRef Name, IRBuilderBase &B, +Value *llvm::emitUnaryFloatFnCall(Value *Op, const TargetLibraryInfo *TLI, + StringRef Name, IRBuilderBase &B, const AttributeList &Attrs) { SmallString<20> NameBuffer; appendTypeSuffix(Op, Name, NameBuffer); - return emitUnaryFloatFnCallHelper(Op, Name, B, Attrs); + LibFunc TheLibFunc; + TLI->getLibFunc(Name, TheLibFunc); + + return emitUnaryFloatFnCallHelper(Op, TheLibFunc, Name, B, Attrs, TLI); } Value *llvm::emitUnaryFloatFnCall(Value *Op, const TargetLibraryInfo *TLI, @@ -1501,23 +1561,24 @@ LibFunc LongDoubleFn, IRBuilderBase &B, const AttributeList &Attrs) { // Get the name of the function according to TLI. - StringRef Name = getFloatFnName(TLI, Op->getType(), - DoubleFn, FloatFn, LongDoubleFn); + LibFunc TheLibFunc; + StringRef Name = getFloatFn(TLI, Op->getType(), DoubleFn, FloatFn, + LongDoubleFn, TheLibFunc); - return emitUnaryFloatFnCallHelper(Op, Name, B, Attrs); + return emitUnaryFloatFnCallHelper(Op, TheLibFunc, Name, B, Attrs, TLI); } static Value *emitBinaryFloatFnCallHelper(Value *Op1, Value *Op2, + LibFunc TheLibFunc, StringRef Name, IRBuilderBase &B, const AttributeList &Attrs, - const TargetLibraryInfo *TLI = nullptr) { + const TargetLibraryInfo *TLI) { assert((Name != "") && "Must specify Name to emitBinaryFloatFnCall"); Module *M = B.GetInsertBlock()->getModule(); - FunctionCallee Callee = M->getOrInsertFunction(Name, Op1->getType(), - Op1->getType(), Op2->getType()); - if (TLI != nullptr) - inferLibFuncAttributes(M, Name, *TLI); + FunctionCallee Callee = getOrInsertLibFunc(M, *TLI, TheLibFunc, Name, + Op1->getType(), Op1->getType(), Op2->getType()); + inferNonMandatoryLibFuncAttrs(M, Name, *TLI); CallInst *CI = B.CreateCall(Callee, { Op1, Op2 }, Name); // The incoming attribute set may have come from a speculatable intrinsic, but @@ -1532,15 +1593,19 @@ return CI; } -Value *llvm::emitBinaryFloatFnCall(Value *Op1, Value *Op2, StringRef Name, - IRBuilderBase &B, +Value *llvm::emitBinaryFloatFnCall(Value *Op1, Value *Op2, + const TargetLibraryInfo *TLI, + StringRef Name, IRBuilderBase &B, const AttributeList &Attrs) { assert((Name != "") && "Must specify Name to emitBinaryFloatFnCall"); SmallString<20> NameBuffer; appendTypeSuffix(Op1, Name, NameBuffer); - return emitBinaryFloatFnCallHelper(Op1, Op2, Name, B, Attrs); + LibFunc TheLibFunc; + TLI->getLibFunc(Name, TheLibFunc); + + return emitBinaryFloatFnCallHelper(Op1, Op2, TheLibFunc, Name, B, Attrs, TLI); } Value *llvm::emitBinaryFloatFnCall(Value *Op1, Value *Op2, @@ -1549,10 +1614,11 @@ LibFunc LongDoubleFn, IRBuilderBase &B, const AttributeList &Attrs) { // Get the name of the function according to TLI. - StringRef Name = getFloatFnName(TLI, Op1->getType(), - DoubleFn, FloatFn, LongDoubleFn); + LibFunc TheLibFunc; + StringRef Name = getFloatFn(TLI, Op1->getType(), DoubleFn, FloatFn, + LongDoubleFn, TheLibFunc); - return emitBinaryFloatFnCallHelper(Op1, Op2, Name, B, Attrs, TLI); + return emitBinaryFloatFnCallHelper(Op1, Op2, TheLibFunc, Name, B, Attrs, TLI); } Value *llvm::emitPutChar(Value *Char, IRBuilderBase &B, @@ -1562,9 +1628,9 @@ Module *M = B.GetInsertBlock()->getModule(); StringRef PutCharName = TLI->getName(LibFunc_putchar); - FunctionCallee PutChar = - M->getOrInsertFunction(PutCharName, B.getInt32Ty(), B.getInt32Ty()); - inferLibFuncAttributes(M, PutCharName, *TLI); + FunctionCallee PutChar = getOrInsertLibFunc(M, *TLI, LibFunc_putchar, + PutCharName, B.getInt32Ty(), B.getInt32Ty()); + inferNonMandatoryLibFuncAttrs(M, PutCharName, *TLI); CallInst *CI = B.CreateCall(PutChar, B.CreateIntCast(Char, B.getInt32Ty(), @@ -1585,9 +1651,9 @@ Module *M = B.GetInsertBlock()->getModule(); StringRef PutsName = TLI->getName(LibFunc_puts); - FunctionCallee PutS = - M->getOrInsertFunction(PutsName, B.getInt32Ty(), B.getInt8PtrTy()); - inferLibFuncAttributes(M, PutsName, *TLI); + FunctionCallee PutS = getOrInsertLibFunc(M, *TLI, LibFunc_puts, PutsName, + B.getInt32Ty(), B.getInt8PtrTy()); + inferNonMandatoryLibFuncAttrs(M, PutsName, *TLI); CallInst *CI = B.CreateCall(PutS, castToCStr(Str, B), PutsName); if (const Function *F = dyn_cast(PutS.getCallee()->stripPointerCasts())) @@ -1602,10 +1668,10 @@ Module *M = B.GetInsertBlock()->getModule(); StringRef FPutcName = TLI->getName(LibFunc_fputc); - FunctionCallee F = M->getOrInsertFunction(FPutcName, B.getInt32Ty(), - B.getInt32Ty(), File->getType()); + FunctionCallee F = getOrInsertLibFunc(M, *TLI, LibFunc_fputc, FPutcName, + B.getInt32Ty(), B.getInt32Ty(), File->getType()); if (File->getType()->isPointerTy()) - inferLibFuncAttributes(M, FPutcName, *TLI); + inferNonMandatoryLibFuncAttrs(M, FPutcName, *TLI); Char = B.CreateIntCast(Char, B.getInt32Ty(), /*isSigned*/true, "chari"); CallInst *CI = B.CreateCall(F, {Char, File}, FPutcName); @@ -1623,10 +1689,10 @@ Module *M = B.GetInsertBlock()->getModule(); StringRef FPutsName = TLI->getName(LibFunc_fputs); - FunctionCallee F = M->getOrInsertFunction(FPutsName, B.getInt32Ty(), - B.getInt8PtrTy(), File->getType()); + FunctionCallee F = getOrInsertLibFunc(M, *TLI, LibFunc_fputs, FPutsName, + B.getInt32Ty(), B.getInt8PtrTy(), File->getType()); if (File->getType()->isPointerTy()) - inferLibFuncAttributes(M, FPutsName, *TLI); + inferNonMandatoryLibFuncAttrs(M, FPutsName, *TLI); CallInst *CI = B.CreateCall(F, {castToCStr(Str, B), File}, FPutsName); if (const Function *Fn = @@ -1643,12 +1709,12 @@ Module *M = B.GetInsertBlock()->getModule(); LLVMContext &Context = B.GetInsertBlock()->getContext(); StringRef FWriteName = TLI->getName(LibFunc_fwrite); - FunctionCallee F = M->getOrInsertFunction( + FunctionCallee F = getOrInsertLibFunc(M, *TLI, LibFunc_fwrite, FWriteName, DL.getIntPtrType(Context), B.getInt8PtrTy(), DL.getIntPtrType(Context), DL.getIntPtrType(Context), File->getType()); if (File->getType()->isPointerTy()) - inferLibFuncAttributes(M, FWriteName, *TLI); + inferNonMandatoryLibFuncAttrs(M, FWriteName, *TLI); CallInst *CI = B.CreateCall(F, {castToCStr(Ptr, B), Size, ConstantInt::get(DL.getIntPtrType(Context), 1), File}); @@ -1667,9 +1733,9 @@ Module *M = B.GetInsertBlock()->getModule(); StringRef MallocName = TLI->getName(LibFunc_malloc); LLVMContext &Context = B.GetInsertBlock()->getContext(); - FunctionCallee Malloc = M->getOrInsertFunction(MallocName, B.getInt8PtrTy(), - DL.getIntPtrType(Context)); - inferLibFuncAttributes(M, MallocName, *TLI); + FunctionCallee Malloc = getOrInsertLibFunc(M, *TLI, LibFunc_malloc, MallocName, + B.getInt8PtrTy(), DL.getIntPtrType(Context)); + inferNonMandatoryLibFuncAttrs(M, MallocName, *TLI); CallInst *CI = B.CreateCall(Malloc, Num, MallocName); if (const Function *F = @@ -1688,9 +1754,9 @@ StringRef CallocName = TLI.getName(LibFunc_calloc); const DataLayout &DL = M->getDataLayout(); IntegerType *PtrType = DL.getIntPtrType((B.GetInsertBlock()->getContext())); - FunctionCallee Calloc = - M->getOrInsertFunction(CallocName, B.getInt8PtrTy(), PtrType, PtrType); - inferLibFuncAttributes(M, CallocName, TLI); + FunctionCallee Calloc = getOrInsertLibFunc(M, TLI, LibFunc_calloc, CallocName, + B.getInt8PtrTy(), PtrType, PtrType); + inferNonMandatoryLibFuncAttrs(M, CallocName, TLI); CallInst *CI = B.CreateCall(Calloc, {Num, Size}, CallocName); if (const auto *F = Index: llvm/lib/Transforms/Utils/SimplifyLibCalls.cpp =================================================================== --- llvm/lib/Transforms/Utils/SimplifyLibCalls.cpp +++ llvm/lib/Transforms/Utils/SimplifyLibCalls.cpp @@ -1252,7 +1252,8 @@ /// Shrink double -> float functions. static Value *optimizeDoubleFP(CallInst *CI, IRBuilderBase &B, - bool isBinary, bool isPrecise = false) { + bool isBinary, const TargetLibraryInfo *TLI, + bool isPrecise = false) { Function *CalleeFn = CI->getCalledFunction(); if (!CI->getType()->isDoubleTy() || !CalleeFn) return nullptr; @@ -1302,22 +1303,25 @@ R = isBinary ? B.CreateCall(Fn, V) : B.CreateCall(Fn, V[0]); } else { AttributeList CalleeAttrs = CalleeFn->getAttributes(); - R = isBinary ? emitBinaryFloatFnCall(V[0], V[1], CalleeName, B, CalleeAttrs) - : emitUnaryFloatFnCall(V[0], CalleeName, B, CalleeAttrs); + R = isBinary ? emitBinaryFloatFnCall(V[0], V[1], TLI, CalleeName, B, + CalleeAttrs) + : emitUnaryFloatFnCall(V[0], TLI, CalleeName, B, CalleeAttrs); } return B.CreateFPExt(R, B.getDoubleTy()); } /// Shrink double -> float for unary functions. static Value *optimizeUnaryDoubleFP(CallInst *CI, IRBuilderBase &B, + const TargetLibraryInfo *TLI, bool isPrecise = false) { - return optimizeDoubleFP(CI, B, false, isPrecise); + return optimizeDoubleFP(CI, B, false, TLI, isPrecise); } /// Shrink double -> float for binary functions. static Value *optimizeBinaryDoubleFP(CallInst *CI, IRBuilderBase &B, + const TargetLibraryInfo *TLI, bool isPrecise = false) { - return optimizeDoubleFP(CI, B, true, isPrecise); + return optimizeDoubleFP(CI, B, true, TLI, isPrecise); } // cabs(z) -> sqrt((creal(z)*creal(z)) + (cimag(z)*cimag(z))) @@ -1785,7 +1789,7 @@ // unless the result is expected to be double precision. if (UnsafeFPShrink && Name == TLI->getName(LibFunc_pow) && hasFloatVersion(Name)) { - if (Value *Shrunk = optimizeBinaryDoubleFP(Pow, B, true)) + if (Value *Shrunk = optimizeBinaryDoubleFP(Pow, B, TLI, true)) return Shrunk; } @@ -1799,7 +1803,7 @@ Value *Ret = nullptr; if (UnsafeFPShrink && Name == TLI->getName(LibFunc_exp2) && hasFloatVersion(Name)) - Ret = optimizeUnaryDoubleFP(CI, B, true); + Ret = optimizeUnaryDoubleFP(CI, B, TLI, true); Type *Ty = CI->getType(); Value *Op = CI->getArgOperand(0); @@ -1823,7 +1827,7 @@ Function *Callee = CI->getCalledFunction(); StringRef Name = Callee->getName(); if ((Name == "fmin" || Name == "fmax") && hasFloatVersion(Name)) - if (Value *Ret = optimizeBinaryDoubleFP(CI, B)) + if (Value *Ret = optimizeBinaryDoubleFP(CI, B, TLI)) return Ret; // The LLVM intrinsics minnum/maxnum correspond to fmin/fmax. Canonicalize to @@ -1855,7 +1859,7 @@ Value *Ret = nullptr; if (UnsafeFPShrink && hasFloatVersion(LogNm)) - Ret = optimizeUnaryDoubleFP(Log, B, true); + Ret = optimizeUnaryDoubleFP(Log, B, TLI, true); // The earlier call must also be 'fast' in order to do these transforms. CallInst *Arg = dyn_cast(Log->getArgOperand(0)); @@ -1963,7 +1967,7 @@ Log->doesNotAccessMemory() ? B.CreateCall(Intrinsic::getDeclaration(Mod, LogID, Ty), Arg->getOperand(0), "log") - : emitUnaryFloatFnCall(Arg->getOperand(0), LogNm, B, Attrs); + : emitUnaryFloatFnCall(Arg->getOperand(0), TLI, LogNm, B, Attrs); Value *MulY = B.CreateFMul(Arg->getArgOperand(1), LogX, "mul"); // Since pow() may have side effects, e.g. errno, // dead code elimination may not be trusted to remove it. @@ -1986,7 +1990,7 @@ Value *LogE = Log->doesNotAccessMemory() ? B.CreateCall(Intrinsic::getDeclaration(Mod, LogID, Ty), Eul, "log") - : emitUnaryFloatFnCall(Eul, LogNm, B, Attrs); + : emitUnaryFloatFnCall(Eul, TLI, LogNm, B, Attrs); Value *MulY = B.CreateFMul(Arg->getArgOperand(0), LogE, "mul"); // Since exp() may have side effects, e.g. errno, // dead code elimination may not be trusted to remove it. @@ -2005,7 +2009,7 @@ // condition below. if (TLI->has(LibFunc_sqrtf) && (Callee->getName() == "sqrt" || Callee->getIntrinsicID() == Intrinsic::sqrt)) - Ret = optimizeUnaryDoubleFP(CI, B, true); + Ret = optimizeUnaryDoubleFP(CI, B, TLI, true); if (!CI->isFast()) return Ret; @@ -2071,7 +2075,7 @@ Value *Ret = nullptr; StringRef Name = Callee->getName(); if (UnsafeFPShrink && Name == "tan" && hasFloatVersion(Name)) - Ret = optimizeUnaryDoubleFP(CI, B, true); + Ret = optimizeUnaryDoubleFP(CI, B, TLI, true); Value *Op1 = CI->getArgOperand(0); auto *OpC = dyn_cast(Op1); @@ -3008,11 +3012,11 @@ case LibFunc_sinh: case LibFunc_tanh: if (UnsafeFPShrink && hasFloatVersion(CI->getCalledFunction()->getName())) - return optimizeUnaryDoubleFP(CI, Builder, true); + return optimizeUnaryDoubleFP(CI, Builder, TLI, true); return nullptr; case LibFunc_copysign: if (hasFloatVersion(CI->getCalledFunction()->getName())) - return optimizeBinaryDoubleFP(CI, Builder); + return optimizeBinaryDoubleFP(CI, Builder, TLI); return nullptr; case LibFunc_fminf: case LibFunc_fmin: Index: llvm/test/Transforms/InferFunctionAttrs/annotate.ll =================================================================== --- llvm/test/Transforms/InferFunctionAttrs/annotate.ll +++ llvm/test/Transforms/InferFunctionAttrs/annotate.ll @@ -3,7 +3,6 @@ ; RUN: opt < %s -mtriple=x86_64-apple-macosx10.8.0 -inferattrs -S | FileCheck --match-full-lines --check-prefixes=CHECK,CHECK-KNOWN,CHECK-NOLINUX,CHECK-OPEN,CHECK-DARWIN %s ; RUN: opt < %s -mtriple=x86_64-unknown-linux-gnu -inferattrs -S | FileCheck --match-full-lines --check-prefixes=CHECK,CHECK-KNOWN,CHECK-LINUX %s ; RUN: opt < %s -mtriple=nvptx -inferattrs -S | FileCheck --match-full-lines --check-prefixes=CHECK-NOLINUX,CHECK-NVPTX %s -; RUN: opt < %s -mtriple=s390x-linux-gnu -inferattrs -S | FileCheck --check-prefixes=CHECK-SYSTEMZ %s declare i32 @__nvvm_reflect(i8*) ; CHECK-NVPTX: declare noundef i32 @__nvvm_reflect(i8* noundef) [[NOFREE_NOUNWIND_READNONE:#[0-9]+]] @@ -592,11 +591,9 @@ declare i32 @lchown(i8*, i32, i32) ; CHECK: declare double @ldexp(double, i32) [[NOFREE_WILLRETURN:#[0-9]+]] -; CHECK-SYSTEMZ: declare double @ldexp(double, i32 signext) declare double @ldexp(double, i32) ; CHECK: declare float @ldexpf(float, i32) [[NOFREE_WILLRETURN]] -; CHECK-SYSTEMZ: declare float @ldexpf(float, i32 signext) declare float @ldexpf(float, i32) ; CHECK: declare x86_fp80 @ldexpl(x86_fp80, i32) [[NOFREE_WILLRETURN]] @@ -756,12 +753,10 @@ declare i32 @putc(i32, %opaque*) ; CHECK: declare noundef i32 @putchar(i32 noundef) [[NOFREE_NOUNWIND]] -; CHECK-SYSTEMZ: declare noundef i32 @putchar(i32 noundef signext) declare i32 @putchar(i32) ; CHECK-KNOWN: declare noundef i32 @putchar_unlocked(i32 noundef) [[NOFREE_NOUNWIND]] ; CHECK-UNKNOWN: declare i32 @putchar_unlocked(i32){{$}} -; CHECK-SYSTEMZ: declare noundef i32 @putchar_unlocked(i32 noundef signext) declare i32 @putchar_unlocked(i32) ; CHECK: declare noundef i32 @puts(i8* nocapture noundef readonly) [[NOFREE_NOUNWIND]] Index: llvm/test/Transforms/InstCombine/exp2-1.ll =================================================================== --- llvm/test/Transforms/InstCombine/exp2-1.ll +++ llvm/test/Transforms/InstCombine/exp2-1.ll @@ -5,6 +5,7 @@ ; RUN: opt < %s -passes=instcombine -S -mtriple=msp430 | FileCheck %s -check-prefixes=LDEXP16 ; RUN: opt < %s -passes=instcombine -S -mtriple=i386-pc-win32 | FileCheck %s -check-prefixes=NOLDEXPF ; RUN: opt < %s -passes=instcombine -S -mtriple=amdgcn-unknown-unknown | FileCheck %s -check-prefixes=NOLDEXP +; RUN: opt < %s -passes=instcombine -S -mtriple=systemz-unknown | FileCheck %s -check-prefixes=CHECK-SYSTEMZ target datalayout = "e-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:32:64-f32:32:32-f64:32:64-v64:64:64-v128:128:128-a0:0:64-f80:128:128" @@ -273,3 +274,16 @@ %ret = call float @llvm.exp2.f32(float %conv) ret float %ret } + +; Test building a call to ldexpl, to test the i32 arg signext attribute below. +declare fp128 @exp2l(fp128) +define fp128 @test_simplify11(i8 zeroext %x) { + %conv = uitofp i8 %x to fp128 + %ret = call fp128 @exp2l(fp128 %conv) + ret fp128 %ret +} + +; Make sure the i32 arg has the signext attribute. +; CHECK-SYSTEMZ: declare double @ldexp(double, i32 signext) +; CHECK-SYSTEMZ: declare float @ldexpf(float, i32 signext) +; CHECK-SYSTEMZ: declare fp128 @ldexpl(fp128, i32 signext) Index: llvm/test/Transforms/InstCombine/fortify-folding.ll =================================================================== --- llvm/test/Transforms/InstCombine/fortify-folding.ll +++ llvm/test/Transforms/InstCombine/fortify-folding.ll @@ -1,5 +1,6 @@ ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py ; RUN: opt < %s -passes=instcombine -S | FileCheck %s +; RUN: opt < %s -passes=instcombine -S -mtriple=systemz-unknown | FileCheck %s -check-prefixes=CHECK-SYSTEMZ target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128" @@ -363,3 +364,6 @@ declare i64 @__strlcpy_chk(i8*, i8*, i64, i64) declare i32 @__vsnprintf_chk(i8*, i64, i32, i64, i8*, %struct.__va_list_tag*) declare i32 @__vsprintf_chk(i8*, i32, i64, i8*, %struct.__va_list_tag*) + +; Make sure the i32 arg has the signext attribute. +; CHECK-SYSTEMZ: declare i8* @memccpy(i8* noalias writeonly, i8* noalias nocapture readonly, i32 signext, i64) Index: llvm/test/Transforms/InstCombine/fputs-1.ll =================================================================== --- llvm/test/Transforms/InstCombine/fputs-1.ll +++ llvm/test/Transforms/InstCombine/fputs-1.ll @@ -1,8 +1,7 @@ ; Test that the fputs library call simplifier works correctly. ; ; RUN: opt < %s -passes=instcombine -S | FileCheck %s - -target datalayout = "e-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:32:64-f32:32:32-f64:32:64-v64:64:64-v128:128:128-a0:0:64-f80:128:128" +; RUN: opt < %s -passes=instcombine -S -mtriple=systemz-unknown | FileCheck --check-prefixes=CHECK-SYSTEMZ %s %FILE = type { } @@ -37,7 +36,10 @@ ; CHECK-LABEL: @test_simplify3( %str = getelementptr [7 x i8], [7 x i8]* @hello, i32 0, i32 0 call i32 @fputs(i8* %str, %FILE* %fp) -; CHECK-NEXT: call i32 @fwrite(i8* getelementptr inbounds ([7 x i8], [7 x i8]* @hello, i32 0, i32 0), i32 6, i32 1, %FILE* %fp) +; CHECK-NEXT: call i64 @fwrite(i8* getelementptr inbounds ([7 x i8], [7 x i8]* @hello, i64 0, i64 0), i64 6, i64 1, %FILE* %fp) ret void ; CHECK-NEXT: ret void } + +; Make sure the i32 arg has the signext attribute. +; CHECK-SYSTEMZ: declare noundef i32 @fputc(i32 noundef signext, %FILE* nocapture noundef) Index: llvm/test/Transforms/InstCombine/puts-1.ll =================================================================== --- llvm/test/Transforms/InstCombine/puts-1.ll +++ llvm/test/Transforms/InstCombine/puts-1.ll @@ -2,6 +2,7 @@ ; Test that the puts library call simplifier works correctly. ; ; RUN: opt < %s -passes=instcombine -S | FileCheck %s +; RUN: opt < %s -passes=instcombine -S -mtriple=systemz-unknown | FileCheck --check-prefixes=CHECK-SYSTEMZ %s target datalayout = "e-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:32:64-f32:32:32-f64:32:64-v64:64:64-v128:128:128-a0:0:64-f80:128:128" @@ -32,3 +33,6 @@ %ret = call i32 @puts(i8* %str) ret i32 %ret } + +; Make sure the i32 arg has the signext attribute. +; CHECK-SYSTEMZ: declare noundef i32 @putchar(i32 noundef signext) Index: llvm/test/Transforms/InstCombine/strchr-1.ll =================================================================== --- llvm/test/Transforms/InstCombine/strchr-1.ll +++ llvm/test/Transforms/InstCombine/strchr-1.ll @@ -1,8 +1,7 @@ ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py ; Test that the strchr library call simplifier works correctly. ; RUN: opt < %s -passes=instcombine -S | FileCheck %s - -target datalayout = "e-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:32:64-f32:32:32-f64:32:64-v64:64:64-v128:128:128-a0:0:64-f80:128:128-n8:16:32" +; RUN: opt < %s -passes=instcombine -S -mtriple=systemz-unknown | FileCheck %s -check-prefixes=CHECK-SYSTEMZ @hello = constant [14 x i8] c"hello world\5Cn\00" @null = constant [1 x i8] zeroinitializer @@ -13,7 +12,7 @@ define void @test_simplify1() { ; CHECK-LABEL: @test_simplify1( -; CHECK-NEXT: store i8* getelementptr inbounds ([14 x i8], [14 x i8]* @hello, i32 0, i32 6), i8** @chp, align 4 +; CHECK-NEXT: store i8* getelementptr inbounds ([14 x i8], [14 x i8]* @hello, i64 0, i64 6), i8** @chp, align 8 ; CHECK-NEXT: ret void ; @@ -25,7 +24,7 @@ define void @test_simplify2() { ; CHECK-LABEL: @test_simplify2( -; CHECK-NEXT: store i8* null, i8** @chp, align 4 +; CHECK-NEXT: store i8* null, i8** @chp, align 8 ; CHECK-NEXT: ret void ; @@ -37,7 +36,7 @@ define void @test_simplify3() { ; CHECK-LABEL: @test_simplify3( -; CHECK-NEXT: store i8* getelementptr inbounds ([14 x i8], [14 x i8]* @hello, i32 0, i32 13), i8** @chp, align 4 +; CHECK-NEXT: store i8* getelementptr inbounds ([14 x i8], [14 x i8]* @hello, i64 0, i64 13), i8** @chp, align 8 ; CHECK-NEXT: ret void ; @@ -49,8 +48,8 @@ define void @test_simplify4(i32 %chr) { ; CHECK-LABEL: @test_simplify4( -; CHECK-NEXT: [[MEMCHR:%.*]] = call i8* @memchr(i8* noundef nonnull dereferenceable(14) getelementptr inbounds ([14 x i8], [14 x i8]* @hello, i32 0, i32 0), i32 [[CHR:%.*]], i32 14) -; CHECK-NEXT: store i8* [[MEMCHR]], i8** @chp, align 4 +; CHECK-NEXT: [[MEMCHR:%.*]] = call i8* @memchr(i8* noundef nonnull dereferenceable(14) getelementptr inbounds ([14 x i8], [14 x i8]* @hello, i64 0, i64 0), i32 [[CHR:%.*]], i64 14) +; CHECK-NEXT: store i8* [[MEMCHR]], i8** @chp, align 8 ; CHECK-NEXT: ret void ; @@ -62,7 +61,7 @@ define void @test_simplify5() { ; CHECK-LABEL: @test_simplify5( -; CHECK-NEXT: store i8* getelementptr inbounds ([14 x i8], [14 x i8]* @hello, i32 0, i32 13), i8** @chp, align 4 +; CHECK-NEXT: store i8* getelementptr inbounds ([14 x i8], [14 x i8]* @hello, i64 0, i64 13), i8** @chp, align 8 ; CHECK-NEXT: ret void ; @@ -75,9 +74,9 @@ ; Check transformation strchr(p, 0) -> p + strlen(p) define void @test_simplify6(i8* %str) { ; CHECK-LABEL: @test_simplify6( -; CHECK-NEXT: [[STRLEN:%.*]] = call i32 @strlen(i8* noundef nonnull dereferenceable(1) [[STR:%.*]]) -; CHECK-NEXT: [[STRCHR:%.*]] = getelementptr i8, i8* [[STR]], i32 [[STRLEN]] -; CHECK-NEXT: store i8* [[STRCHR]], i8** @chp, align 4 +; CHECK-NEXT: [[STRLEN:%.*]] = call i64 @strlen(i8* noundef nonnull dereferenceable(1) [[STR:%.*]]) +; CHECK-NEXT: [[STRCHR:%.*]] = getelementptr i8, i8* [[STR]], i64 [[STRLEN]] +; CHECK-NEXT: store i8* [[STRCHR]], i8** @chp, align 8 ; CHECK-NEXT: ret void ; @@ -89,14 +88,9 @@ ; Check transformation strchr("\r\n", C) != nullptr -> (C & 9217) != 0 define i1 @test_simplify7(i32 %C) { ; CHECK-LABEL: @test_simplify7( -; CHECK-NEXT: [[TMP1:%.*]] = trunc i32 [[C:%.*]] to i16 -; CHECK-NEXT: [[TMP2:%.*]] = and i16 [[TMP1]], 255 -; CHECK-NEXT: [[MEMCHR_BOUNDS:%.*]] = icmp ult i16 [[TMP2]], 16 -; CHECK-NEXT: [[TMP3:%.*]] = shl i16 1, [[TMP2]] -; CHECK-NEXT: [[TMP4:%.*]] = and i16 [[TMP3]], 9217 -; CHECK-NEXT: [[MEMCHR_BITS:%.*]] = icmp ne i16 [[TMP4]], 0 -; CHECK-NEXT: [[MEMCHR1:%.*]] = select i1 [[MEMCHR_BOUNDS]], i1 [[MEMCHR_BITS]], i1 false -; CHECK-NEXT: ret i1 [[MEMCHR1]] +; CHECK-NEXT: [[MEMCHR:%.*]] = call i8* @memchr(i8* noundef nonnull dereferenceable(3) getelementptr inbounds ([3 x i8], [3 x i8]* @newlines, i64 0, i64 0), i32 [[C:%.*]], i64 3) +; CHECK-NEXT: [[CMP:%.*]] = icmp ne i8* [[MEMCHR]], null +; CHECK-NEXT: ret i1 [[CMP]] ; %dst = call i8* @strchr(i8* getelementptr inbounds ([3 x i8], [3 x i8]* @newlines, i64 0, i64 0), i32 %C) @@ -123,3 +117,7 @@ %ret = call i8* @strchr(i8* %str, i32 %c) ret i8* %ret } + + +; Make sure the i32 arg has the signext attribute. +; CHECK-SYSTEMZ: declare i8* @memchr(i8*, i32 signext, i64) Index: llvm/test/Transforms/InstCombine/strstr-1.ll =================================================================== --- llvm/test/Transforms/InstCombine/strstr-1.ll +++ llvm/test/Transforms/InstCombine/strstr-1.ll @@ -2,6 +2,7 @@ ; Test that the strstr library call simplifier works correctly. ; ; RUN: opt < %s -passes=instcombine -S | FileCheck %s +; RUN: opt < %s -passes=instcombine -S -mtriple=systemz-unknown | FileCheck %s -check-prefixes=CHECK-SYSTEMZ target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64-S128" @@ -88,3 +89,6 @@ %ret = call i8* @strstr(i8* %str1, i8* %str2) ret i8* %ret } + +; Make sure the i32 arg has the signext attribute. +; CHECK-SYSTEMZ: declare i8* @strchr(i8*, i32 signext)