diff options
author | Sander de Smalen <sander.desmalen@arm.com> | 2019-06-13 08:19:33 +0000 |
---|---|---|
committer | Sander de Smalen <sander.desmalen@arm.com> | 2019-06-13 08:19:33 +0000 |
commit | 7957fc6547e1b8af8e6586e2c25446b724eabb75 (patch) | |
tree | dec114bbf1ff2c4f035809383388b433c773a48e /llvm/lib/IR/Function.cpp | |
parent | 02eac87ba3e60ae5f576a38cbe00e435a4d5a4a6 (diff) | |
download | llvm-7957fc6547e1b8af8e6586e2c25446b724eabb75.zip llvm-7957fc6547e1b8af8e6586e2c25446b724eabb75.tar.gz llvm-7957fc6547e1b8af8e6586e2c25446b724eabb75.tar.bz2 |
[IntrinsicEmitter] Extend argument overloading with forward references.
Extend the mechanism to overload intrinsic arguments by using either
backward or forward references to the overloadable arguments.
In for example:
def int_something : Intrinsic<[LLVMPointerToElt<0>],
[llvm_anyvector_ty], []>;
LLVMPointerToElt<0> is a forward reference to the overloadable operand
of type 'llvm_anyvector_ty' and would allow intrinsics such as:
declare i32* @llvm.something.v4i32(<4 x i32>);
declare i64* @llvm.something.v2i64(<2 x i64>);
where the result pointer type is deduced from the element type of the
first argument.
If the returned pointer is not a pointer to the element type, LLVM will
give an error:
Intrinsic has incorrect return type!
i64* (<4 x i32>)* @llvm.something.v4i32
Reviewers: RKSimon, arsenm, rnk, greened
Reviewed By: arsenm
Differential Revision: https://reviews.llvm.org/D62995
llvm-svn: 363233
Diffstat (limited to 'llvm/lib/IR/Function.cpp')
-rw-r--r-- | llvm/lib/IR/Function.cpp | 119 |
1 files changed, 85 insertions, 34 deletions
diff --git a/llvm/lib/IR/Function.cpp b/llvm/lib/IR/Function.cpp index c88fd1a..affd85e 100644 --- a/llvm/lib/IR/Function.cpp +++ b/llvm/lib/IR/Function.cpp @@ -1047,12 +1047,26 @@ Function *Intrinsic::getDeclaration(Module *M, ID id, ArrayRef<Type*> Tys) { #include "llvm/IR/IntrinsicImpl.inc" #undef GET_LLVM_INTRINSIC_FOR_MS_BUILTIN -bool Intrinsic::matchIntrinsicType(Type *Ty, ArrayRef<Intrinsic::IITDescriptor> &Infos, - SmallVectorImpl<Type*> &ArgTys) { +using DeferredIntrinsicMatchPair = + std::pair<Type *, ArrayRef<Intrinsic::IITDescriptor>>; + +static bool matchIntrinsicType( + Type *Ty, ArrayRef<Intrinsic::IITDescriptor> &Infos, + SmallVectorImpl<Type *> &ArgTys, + SmallVectorImpl<DeferredIntrinsicMatchPair> &DeferredChecks, + bool IsDeferredCheck) { using namespace Intrinsic; // If we ran out of descriptors, there are too many arguments. if (Infos.empty()) return true; + + // Do this before slicing off the 'front' part + auto InfosRef = Infos; + auto DeferCheck = [&DeferredChecks, &InfosRef](Type *T) { + DeferredChecks.emplace_back(T, InfosRef); + return false; + }; + IITDescriptor D = Infos.front(); Infos = Infos.slice(1); @@ -1070,12 +1084,14 @@ bool Intrinsic::matchIntrinsicType(Type *Ty, ArrayRef<Intrinsic::IITDescriptor> case IITDescriptor::Vector: { VectorType *VT = dyn_cast<VectorType>(Ty); return !VT || VT->getNumElements() != D.Vector_Width || - matchIntrinsicType(VT->getElementType(), Infos, ArgTys); + matchIntrinsicType(VT->getElementType(), Infos, ArgTys, + DeferredChecks, IsDeferredCheck); } case IITDescriptor::Pointer: { PointerType *PT = dyn_cast<PointerType>(Ty); return !PT || PT->getAddressSpace() != D.Pointer_AddressSpace || - matchIntrinsicType(PT->getElementType(), Infos, ArgTys); + matchIntrinsicType(PT->getElementType(), Infos, ArgTys, + DeferredChecks, IsDeferredCheck); } case IITDescriptor::Struct: { @@ -1084,20 +1100,24 @@ bool Intrinsic::matchIntrinsicType(Type *Ty, ArrayRef<Intrinsic::IITDescriptor> return true; for (unsigned i = 0, e = D.Struct_NumElements; i != e; ++i) - if (matchIntrinsicType(ST->getElementType(i), Infos, ArgTys)) + if (matchIntrinsicType(ST->getElementType(i), Infos, ArgTys, + DeferredChecks, IsDeferredCheck)) return true; return false; } case IITDescriptor::Argument: - // Two cases here - If this is the second occurrence of an argument, verify - // that the later instance matches the previous instance. + // If this is the second occurrence of an argument, + // verify that the later instance matches the previous instance. if (D.getArgumentNumber() < ArgTys.size()) return Ty != ArgTys[D.getArgumentNumber()]; - // Otherwise, if this is the first instance of an argument, record it and - // verify the "Any" kind. - assert(D.getArgumentNumber() == ArgTys.size() && "Table consistency error"); + if (D.getArgumentNumber() > ArgTys.size() || + D.getArgumentKind() == IITDescriptor::AK_MatchType) + return IsDeferredCheck || DeferCheck(Ty); + + assert(D.getArgumentNumber() == ArgTys.size() && !IsDeferredCheck && + "Table consistency error"); ArgTys.push_back(Ty); switch (D.getArgumentKind()) { @@ -1106,13 +1126,14 @@ bool Intrinsic::matchIntrinsicType(Type *Ty, ArrayRef<Intrinsic::IITDescriptor> case IITDescriptor::AK_AnyFloat: return !Ty->isFPOrFPVectorTy(); case IITDescriptor::AK_AnyVector: return !isa<VectorType>(Ty); case IITDescriptor::AK_AnyPointer: return !isa<PointerType>(Ty); + default: break; } llvm_unreachable("all argument kinds not covered"); case IITDescriptor::ExtendArgument: { - // This may only be used when referring to a previous vector argument. + // If this is a forward reference, defer the check for later. if (D.getArgumentNumber() >= ArgTys.size()) - return true; + return IsDeferredCheck || DeferCheck(Ty); Type *NewTy = ArgTys[D.getArgumentNumber()]; if (VectorType *VTy = dyn_cast<VectorType>(NewTy)) @@ -1125,9 +1146,9 @@ bool Intrinsic::matchIntrinsicType(Type *Ty, ArrayRef<Intrinsic::IITDescriptor> return Ty != NewTy; } case IITDescriptor::TruncArgument: { - // This may only be used when referring to a previous vector argument. + // If this is a forward reference, defer the check for later. if (D.getArgumentNumber() >= ArgTys.size()) - return true; + return IsDeferredCheck || DeferCheck(Ty); Type *NewTy = ArgTys[D.getArgumentNumber()]; if (VectorType *VTy = dyn_cast<VectorType>(NewTy)) @@ -1140,14 +1161,17 @@ bool Intrinsic::matchIntrinsicType(Type *Ty, ArrayRef<Intrinsic::IITDescriptor> return Ty != NewTy; } case IITDescriptor::HalfVecArgument: - // This may only be used when referring to a previous vector argument. + // If this is a forward reference, defer the check for later. return D.getArgumentNumber() >= ArgTys.size() || !isa<VectorType>(ArgTys[D.getArgumentNumber()]) || VectorType::getHalfElementsVectorType( cast<VectorType>(ArgTys[D.getArgumentNumber()])) != Ty; case IITDescriptor::SameVecWidthArgument: { - if (D.getArgumentNumber() >= ArgTys.size()) - return true; + if (D.getArgumentNumber() >= ArgTys.size()) { + // Defer check and subsequent check for the vector element type. + Infos = Infos.slice(1); + return IsDeferredCheck || DeferCheck(Ty); + } auto *ReferenceType = dyn_cast<VectorType>(ArgTys[D.getArgumentNumber()]); auto *ThisArgType = dyn_cast<VectorType>(Ty); // Both must be vectors of the same number of elements or neither. @@ -1160,18 +1184,19 @@ bool Intrinsic::matchIntrinsicType(Type *Ty, ArrayRef<Intrinsic::IITDescriptor> return true; EltTy = ThisArgType->getVectorElementType(); } - return matchIntrinsicType(EltTy, Infos, ArgTys); + return matchIntrinsicType(EltTy, Infos, ArgTys, DeferredChecks, + IsDeferredCheck); } case IITDescriptor::PtrToArgument: { if (D.getArgumentNumber() >= ArgTys.size()) - return true; + return IsDeferredCheck || DeferCheck(Ty); Type * ReferenceType = ArgTys[D.getArgumentNumber()]; PointerType *ThisArgType = dyn_cast<PointerType>(Ty); return (!ThisArgType || ThisArgType->getElementType() != ReferenceType); } case IITDescriptor::PtrToElt: { if (D.getArgumentNumber() >= ArgTys.size()) - return true; + return IsDeferredCheck || DeferCheck(Ty); VectorType * ReferenceType = dyn_cast<VectorType> (ArgTys[D.getArgumentNumber()]); PointerType *ThisArgType = dyn_cast<PointerType>(Ty); @@ -1181,15 +1206,20 @@ bool Intrinsic::matchIntrinsicType(Type *Ty, ArrayRef<Intrinsic::IITDescriptor> } case IITDescriptor::VecOfAnyPtrsToElt: { unsigned RefArgNumber = D.getRefArgNumber(); + if (RefArgNumber >= ArgTys.size()) { + if (IsDeferredCheck) + return true; + // If forward referencing, already add the pointer-vector type and + // defer the checks for later. + ArgTys.push_back(Ty); + return DeferCheck(Ty); + } - // This may only be used when referring to a previous argument. - if (RefArgNumber >= ArgTys.size()) - return true; - - // Record the overloaded type - assert(D.getOverloadArgNumber() == ArgTys.size() && - "Table consistency error"); - ArgTys.push_back(Ty); + if (!IsDeferredCheck){ + assert(D.getOverloadArgNumber() == ArgTys.size() && + "Table consistency error"); + ArgTys.push_back(Ty); + } // Verify the overloaded type "matches" the Ref type. // i.e. Ty is a vector with the same width as Ref. @@ -1211,6 +1241,32 @@ bool Intrinsic::matchIntrinsicType(Type *Ty, ArrayRef<Intrinsic::IITDescriptor> llvm_unreachable("unhandled"); } +Intrinsic::MatchIntrinsicTypesResult +Intrinsic::matchIntrinsicSignature(FunctionType *FTy, + ArrayRef<Intrinsic::IITDescriptor> &Infos, + SmallVectorImpl<Type *> &ArgTys) { + SmallVector<DeferredIntrinsicMatchPair, 2> DeferredChecks; + if (matchIntrinsicType(FTy->getReturnType(), Infos, ArgTys, DeferredChecks, + false)) + return MatchIntrinsicTypes_NoMatchRet; + + unsigned NumDeferredReturnChecks = DeferredChecks.size(); + + for (auto Ty : FTy->params()) + if (matchIntrinsicType(Ty, Infos, ArgTys, DeferredChecks, false)) + return MatchIntrinsicTypes_NoMatchArg; + + for (unsigned I = 0, E = DeferredChecks.size(); I != E; ++I) { + DeferredIntrinsicMatchPair &Check = DeferredChecks[I]; + if (matchIntrinsicType(Check.first, Check.second, ArgTys, DeferredChecks, + true)) + return I < NumDeferredReturnChecks ? MatchIntrinsicTypes_NoMatchRet + : MatchIntrinsicTypes_NoMatchArg; + } + + return MatchIntrinsicTypes_Match; +} + bool Intrinsic::matchIntrinsicVarArg(bool isVarArg, ArrayRef<Intrinsic::IITDescriptor> &Infos) { @@ -1244,13 +1300,8 @@ Optional<Function*> Intrinsic::remangleIntrinsicFunction(Function *F) { getIntrinsicInfoTableEntries(ID, Table); ArrayRef<Intrinsic::IITDescriptor> TableRef = Table; - // If we encounter any problems matching the signature with the descriptor - // just give up remangling. It's up to verifier to report the discrepancy. - if (Intrinsic::matchIntrinsicType(FTy->getReturnType(), TableRef, ArgTys)) + if (Intrinsic::matchIntrinsicSignature(FTy, TableRef, ArgTys)) return None; - for (auto Ty : FTy->params()) - if (Intrinsic::matchIntrinsicType(Ty, TableRef, ArgTys)) - return None; if (Intrinsic::matchIntrinsicVarArg(FTy->isVarArg(), TableRef)) return None; } |