Index: llvm/include/llvm/Analysis/TargetTransformInfo.h =================================================================== --- llvm/include/llvm/Analysis/TargetTransformInfo.h +++ llvm/include/llvm/Analysis/TargetTransformInfo.h @@ -1510,6 +1510,14 @@ bool areTypesABICompatible(const Function *Caller, const Function *Callee, const ArrayRef &Types) const; + /// \returns True if \p ParamTy at a call base can be passed to \p ArgTy at a + /// callee. + bool willResultInPoisonOnCallEdge(Type *ParamTy, Type *ArgTy) const; + + /// \returns True if \p CB may legally call \p Callee via an indirect call. + bool isValidCallBaseForCallee(const CallBase *CB, + const Function *Callee) const; + /// The type of load/store indexing. enum MemIndexedMode { MIM_Unindexed, ///< No indexing. @@ -1998,6 +2006,9 @@ virtual bool areTypesABICompatible(const Function *Caller, const Function *Callee, const ArrayRef &Types) const = 0; + virtual bool willResultInPoisonOnCallEdge(Type *ParamTy, Type *ArgTy) const = 0; + virtual bool isValidCallBaseForCallee(const CallBase *CB, + const Function *Callee) const = 0; virtual bool isIndexedLoadLegal(MemIndexedMode Mode, Type *Ty) const = 0; virtual bool isIndexedStoreLegal(MemIndexedMode Mode, Type *Ty) const = 0; virtual unsigned getLoadStoreVecRegBitWidth(unsigned AddrSpace) const = 0; @@ -2654,6 +2665,13 @@ const ArrayRef &Types) const override { return Impl.areTypesABICompatible(Caller, Callee, Types); } + bool willResultInPoisonOnCallEdge(Type *ParamTy, Type *ArgTy) const override { + return Impl.willResultInPoisonOnCallEdge(ParamTy, ArgTy); + } + bool isValidCallBaseForCallee(const CallBase *CB, + const Function *Callee) const override { + return Impl.isValidCallBaseForCallee(CB, Callee); + } bool isIndexedLoadLegal(MemIndexedMode Mode, Type *Ty) const override { return Impl.isIndexedLoadLegal(Mode, Ty, getDataLayout()); } Index: llvm/include/llvm/Analysis/TargetTransformInfoImpl.h =================================================================== --- llvm/include/llvm/Analysis/TargetTransformInfoImpl.h +++ llvm/include/llvm/Analysis/TargetTransformInfoImpl.h @@ -15,8 +15,10 @@ #define LLVM_ANALYSIS_TARGETTRANSFORMINFOIMPL_H #include "llvm/Analysis/ScalarEvolutionExpressions.h" +#include "llvm/Analysis/TargetLibraryInfo.h" #include "llvm/Analysis/TargetTransformInfo.h" #include "llvm/Analysis/VectorUtils.h" +#include "llvm/IR/Attributes.h" #include "llvm/IR/DataLayout.h" #include "llvm/IR/GetElementPtrTypeIterator.h" #include "llvm/IR/IntrinsicInst.h" @@ -806,6 +808,99 @@ Callee->getFnAttribute("target-features")); } + bool willResultInPoisonOnCallEdge(Type *ParamTy, Type *ArgTy) const { + if (ParamTy == ArgTy) + return false; + + // TODO: Is scalable vs non-scalable OK? + // TODO: Is sized vs non-sized OK? + // TODO: For sized and non-scalable, we could check the sizes. + + // Floating point vs non-floating point, not OK. + if (ParamTy->isFloatingPointTy() != ArgTy->isFloatingPointTy()) + return true; + + // Non-vector: ptr/int vs non-ptr/int, not OK. + if (!ArgTy->isVectorTy() && !ParamTy->isVectorTy()) + if (ArgTy->isIntOrPtrTy() != ParamTy->isIntOrPtrTy()) + return true; + + if (ArgTy->isPointerTy() && ParamTy->isPointerTy()) { + // Implicit non-trivial AS cast, not OK. + if (!isNoopAddrSpaceCast(ParamTy->getPointerAddressSpace(), + ArgTy->getPointerAddressSpace())) + return true; + } + + // Give up. + return false; + } + + bool isValidCallBaseForCallee(const CallBase *CB, + const Function *Callee) const { + // Given a call and callee definition, if their calling conventions don't + // match, and neither one of the calling conventions is compatible with C + // calling convention this call must be unreachable, as the call is + // undefined. Declarations are excluded because a prototype may + // not actually end up matching the implementation's calling conv for a + // variety of reasons (e.g. it may be written in assembly). + // Note: Copied from InstCombineCalls, apparently TLI can be used there but + // not TTI (due to policy). + if (!Callee->isDeclaration() && + (Callee->getCallingConv() != CB->getCallingConv() && + !(Callee->getCallingConv() == llvm::CallingConv::C && + TargetLibraryInfoImpl::isCallingConvCCompatible( + const_cast(CB))) && + !(CB->getCallingConv() == llvm::CallingConv::C && + TargetLibraryInfoImpl::isCallingConvCCompatible( + const_cast(Callee))))) + return false; + + // TODO: Check the additional musttail rules here. + + Type *FnRetTy = Callee->getReturnType(); + Type *CBRetTy = CB->getType(); + if (!CBRetTy->isVoidTy() && CB->hasRetAttr(Attribute::NoUndef)) { + // Void function would "return poison", which would be UB. + if (FnRetTy->isVoidTy()) + return false; + // Non-void function that would "return poison", which would be UB. + if (!FnRetTy->isVoidTy() && + willResultInPoisonOnCallEdge(CBRetTy, FnRetTy)) + return false; + } + + // TODO: Depending on the target, call sites might not be allowed void if + // the callee is not returning void. + + unsigned FnNumArgs = Callee->arg_size(); + unsigned CBNumArgs = CB->arg_size(); + + // Check arguments that are poison due to the lack of call site + // parameters. + for (unsigned ArgNo = CBNumArgs; ArgNo < FnNumArgs; ++ArgNo) + if (Callee->getArg(ArgNo)->hasAttribute(Attribute::NoUndef)) + return false; + + // TODO: Depending on the source and maybe target we could disallow too + // many arugments. For now, we allow it. + + // Check if we will violate noundef for arguments. + for (unsigned ArgNo = 0; ArgNo < std::min(CBNumArgs, FnNumArgs); ++ArgNo) + if (Callee->hasParamAttribute(ArgNo, Attribute::NoUndef) && + willResultInPoisonOnCallEdge(CB->getArgOperand(ArgNo)->getType(), + Callee->getArg(ArgNo)->getType())) + return false; + + // TODO: Check FnNumArgs till CBNumArgs for OK variadic argument + // types/attributes. + + // TODO: Check attributes. + + // Seems valid enough. + return true; + } + bool isIndexedLoadLegal(TTI::MemIndexedMode Mode, Type *Ty, const DataLayout &DL) const { return false; Index: llvm/include/llvm/IR/Attributes.h =================================================================== --- llvm/include/llvm/IR/Attributes.h +++ llvm/include/llvm/IR/Attributes.h @@ -1224,7 +1224,6 @@ /// attributes for inlining purposes. bool areInlineCompatible(const Function &Caller, const Function &Callee); - /// Checks if there are any incompatible function attributes between /// \p A and \p B. /// Index: llvm/lib/Analysis/TargetTransformInfo.cpp =================================================================== --- llvm/lib/Analysis/TargetTransformInfo.cpp +++ llvm/lib/Analysis/TargetTransformInfo.cpp @@ -1128,6 +1128,16 @@ return TTIImpl->areTypesABICompatible(Caller, Callee, Types); } +bool TargetTransformInfo::willResultInPoisonOnCallEdge(Type *ParamTy, + Type *ArgTy) const { + return TTIImpl->willResultInPoisonOnCallEdge(ParamTy, ArgTy); +} + +bool TargetTransformInfo::isValidCallBaseForCallee( + const CallBase *CB, const Function *Callee) const { + return TTIImpl->isValidCallBaseForCallee(CB, Callee); +} + bool TargetTransformInfo::isIndexedLoadLegal(MemIndexedMode Mode, Type *Ty) const { return TTIImpl->isIndexedLoadLegal(Mode, Ty);