aboutsummaryrefslogtreecommitdiff
path: root/llvm/lib/IR/Function.cpp
diff options
context:
space:
mode:
authorSander de Smalen <sander.desmalen@arm.com>2019-06-13 08:19:33 +0000
committerSander de Smalen <sander.desmalen@arm.com>2019-06-13 08:19:33 +0000
commit7957fc6547e1b8af8e6586e2c25446b724eabb75 (patch)
treedec114bbf1ff2c4f035809383388b433c773a48e /llvm/lib/IR/Function.cpp
parent02eac87ba3e60ae5f576a38cbe00e435a4d5a4a6 (diff)
downloadllvm-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.cpp119
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;
}