Index: llvm/include/llvm/IR/Intrinsics.h =================================================================== --- llvm/include/llvm/IR/Intrinsics.h +++ llvm/include/llvm/IR/Intrinsics.h @@ -53,11 +53,21 @@ StringRef getName(ID id); /// Return the LLVM name for an intrinsic, such as "llvm.ppc.altivec.lvx". - /// Note, this version of getName supports overloads, but is less efficient - /// than the StringRef version of this function. If no overloads are - /// requried, it is safe to use this version, but better to use the StringRef - /// version. - std::string getName(ID id, ArrayRef Tys); + /// Note, this version of getName supports overloads, but no anonymous + /// structs. It is less efficient than the StringRef version of this function. + /// If no overloads are requiered, it is safe to use this version, but better + /// to use the StringRef version. + std::string getName(ID id, ArrayRef Tys); + + /// Return the LLVM name for an intrinsic, such as "llvm.ppc.altivec.lvx". + /// Note, this version of getName supports overloads and anonymous structs, + /// but is less efficient than the StringRef version of this function. If no + /// overloads are requierd, it is safe to use this version, but better to use + /// the StringRef version. The function type can be provided as a speedup. + /// It is used (or computed) if one of the types is based on an anonymous + /// struct. + std::string getName(ID id, ArrayRef Tys, Module *M, + llvm::FunctionType *FT); /// Return the function type for an intrinsic. FunctionType *getType(LLVMContext &Context, ID id, Index: llvm/include/llvm/IR/Module.h =================================================================== --- llvm/include/llvm/IR/Module.h +++ llvm/include/llvm/IR/Module.h @@ -197,6 +197,12 @@ ///< Format: (arch)(sub)-(vendor)-(sys0-(abi) NamedMDSymTabType NamedMDSymTab; ///< NamedMDNode names. DataLayout DL; ///< DataLayout associated with the module + DenseMap + CurrentIntrinsicIds; ///< Keep track of the current unique id + ///< count for the specified intrinsic + DenseMap, unsigned> + UniquedIntrinsicNames; ///< Keep track of uniqued names of intrinsics + ///< based on anonymous structs friend class Constant; @@ -335,6 +341,11 @@ std::vector getIdentifiedStructTypes() const; + /// Return a unique name for an intrinsic whose mangling is based on an + /// anonymous struct. The Proto represents the function prototype. + std::string getUniqueIntrinsicName(StringRef BaseName, Intrinsic::ID id, + const FunctionType *Proto); + /// @} /// @name Function Accessors /// @{ Index: llvm/lib/IR/Function.cpp =================================================================== --- llvm/lib/IR/Function.cpp +++ llvm/lib/IR/Function.cpp @@ -710,30 +710,35 @@ /// which can't be confused with it's prefix. This ensures we don't have /// collisions between two unrelated function types. Otherwise, you might /// parse ffXX as f(fXX) or f(fX)X. (X is a placeholder for any other type.) -/// -static std::string getMangledTypeStr(Type* Ty) { +/// The HasAnonymousStruct boolean is set if an anonymous struct was +/// encountered, indicating that extra care must be taken to ensure a unique +/// name. +static std::string getMangledTypeStr(Type *Ty, bool &HasAnonymousStruct) { std::string Result; if (PointerType* PTyp = dyn_cast(Ty)) { Result += "p" + utostr(PTyp->getAddressSpace()) + - getMangledTypeStr(PTyp->getElementType()); + getMangledTypeStr(PTyp->getElementType(), HasAnonymousStruct); } else if (ArrayType* ATyp = dyn_cast(Ty)) { Result += "a" + utostr(ATyp->getNumElements()) + - getMangledTypeStr(ATyp->getElementType()); + getMangledTypeStr(ATyp->getElementType(), HasAnonymousStruct); } else if (StructType *STyp = dyn_cast(Ty)) { if (!STyp->isLiteral()) { Result += "s_"; - Result += STyp->getName(); + if (STyp->hasName()) + Result += STyp->getName(); + else + HasAnonymousStruct = true; } else { Result += "sl_"; for (auto Elem : STyp->elements()) - Result += getMangledTypeStr(Elem); + Result += getMangledTypeStr(Elem, HasAnonymousStruct); } // Ensure nested structs are distinguishable. Result += "s"; } else if (FunctionType *FT = dyn_cast(Ty)) { - Result += "f_" + getMangledTypeStr(FT->getReturnType()); + Result += "f_" + getMangledTypeStr(FT->getReturnType(), HasAnonymousStruct); for (size_t i = 0; i < FT->getNumParams(); i++) - Result += getMangledTypeStr(FT->getParamType(i)); + Result += getMangledTypeStr(FT->getParamType(i), HasAnonymousStruct); if (FT->isVarArg()) Result += "vararg"; // Ensure nested function types are distinguishable. @@ -743,7 +748,7 @@ if (EC.isScalable()) Result += "nx"; Result += "v" + utostr(EC.getKnownMinValue()) + - getMangledTypeStr(VTy->getElementType()); + getMangledTypeStr(VTy->getElementType(), HasAnonymousStruct); } else if (Ty) { switch (Ty->getTypeID()) { default: llvm_unreachable("Unhandled type"); @@ -772,15 +777,29 @@ return IntrinsicNameTable[id]; } -std::string Intrinsic::getName(ID id, ArrayRef Tys) { +std::string Intrinsic::getName(ID id, ArrayRef Tys, Module *M, + FunctionType *FT) { assert(id < num_intrinsics && "Invalid intrinsic ID!"); + bool HasAnonymousStruct = false; std::string Result(IntrinsicNameTable[id]); for (Type *Ty : Tys) { - Result += "." + getMangledTypeStr(Ty); + Result += "." + getMangledTypeStr(Ty, HasAnonymousStruct); + } + if (M && HasAnonymousStruct) { + if (FT == nullptr) + FT = getType(M->getContext(), id, Tys); + else + assert((FT == getType(M->getContext(), id, Tys)) && + "Provided FunctionType must match arguments"); + return M->getUniqueIntrinsicName(Result, id, FT); } return Result; } +std::string Intrinsic::getName(ID id, ArrayRef Tys) { + return getName(id, Tys, nullptr, nullptr); +} + /// IIT_Info - These are enumerators that describe the entries returned by the /// getIntrinsicInfoTableEntries function. /// @@ -1235,10 +1254,9 @@ Function *Intrinsic::getDeclaration(Module *M, ID id, ArrayRef Tys) { // There can never be multiple globals with the same name of different types, // because intrinsics must be a specific type. + auto *FT = getType(M->getContext(), id, Tys); return cast( - M->getOrInsertFunction(getName(id, Tys), - getType(M->getContext(), id, Tys)) - .getCallee()); + M->getOrInsertFunction(getName(id, Tys, M, FT), FT).getCallee()); } // This defines the "Intrinsic::getIntrinsicForGCCBuiltin()" method. @@ -1548,7 +1566,9 @@ Intrinsic::ID ID = F->getIntrinsicID(); StringRef Name = F->getName(); - if (Name == Intrinsic::getName(ID, ArgTys)) + if (Name == Intrinsic::getName( + ID, ArgTys, F->getParent(), + nullptr)) //@ FIXME: can be made faster for anonymous structs return None; auto NewDecl = Intrinsic::getDeclaration(F->getParent(), ID, ArgTys); Index: llvm/lib/IR/Module.cpp =================================================================== --- llvm/lib/IR/Module.cpp +++ llvm/lib/IR/Module.cpp @@ -473,6 +473,50 @@ return Ret; } +std::string Module::getUniqueIntrinsicName(StringRef BaseName, Intrinsic::ID id, + const FunctionType *Proto) { + { + // fast path - the prototype is already known + auto UinItInserted = UniquedIntrinsicNames.insert({{id, Proto}, 0}); + if (!UinItInserted.second) + return (Twine(BaseName) + "." + Twine(UinItInserted.first->second)).str(); + } + + // Not known yet. A new entry was created with index 0. Check if there already + // exists a matching declaration, or select a new entry. + + // Start looking for names with the current known maximum count (or 0). + auto NiidItInserted = CurrentIntrinsicIds.insert({id, 0}); + unsigned Count = NiidItInserted.first->second; + + // This might be slow if a whole population of intrinsics already existed, but + // we cache the values for later usage. + while (true) { + GlobalValue *F = + getNamedValue((Twine(BaseName) + "." + Twine(Count)).str()); + if (F == nullptr) { + // Reserve this entry for the new proto + UniquedIntrinsicNames[{id, Proto}] = Count; + break; + } + + FunctionType *FT = dyn_cast(F->getType()->getElementType()); + auto UinItInserted = UniquedIntrinsicNames.insert({{id, FT}, Count}); + if (!UinItInserted.second) { + assert(UinItInserted.first->first == std::make_pair(id, Proto) && + "only the new {id, proto} can already be in cache"); + UinItInserted.first->second = Count; + break; + } + + ++Count; + } + + NiidItInserted.first->second = Count + 1; + + return (Twine(BaseName) + "." + Twine(Count)).str(); +} + // dropAllReferences() - This function causes all the subelements to "let go" // of all references that they are maintaining. This allows one to 'delete' a // whole module at a time, even though there may be circular references... first Index: llvm/lib/IR/Verifier.cpp =================================================================== --- llvm/lib/IR/Verifier.cpp +++ llvm/lib/IR/Verifier.cpp @@ -4517,7 +4517,8 @@ // know they are legal for the intrinsic!) get the intrinsic name through the // usual means. This allows us to verify the mangling of argument types into // the name. - const std::string ExpectedName = Intrinsic::getName(ID, ArgTys); + const std::string ExpectedName = + Intrinsic::getName(ID, ArgTys, IF->getParent(), IFTy); Assert(ExpectedName == IF->getName(), "Intrinsic name not mangled correctly for type arguments! " "Should be: " +